// macOS process list — the laptop subset of ecosystem.config.cjs. // // Only what a Mac install can actually run and what the laptop workflow needs: the file browser, the // terminal, and Claude/opencode chat. Everything else on the Linux host is either tied to Xorg, tied to // a container the laptop does not run, or holds material that has no business on a laptop. // // KEEP THIS IN STEP WITH ecosystem.config.cjs. It was written on 2026-07-28 and was broken by two // architecture changes within days, which is the failure mode to watch for: // - `officer-claude` was split into `officer-anthropic-proxy` (holds the credential) and // `officer-agent` (spawns `claude`). This file ran only the first under the old name, so chat had a // credential holder and nothing driving it. // - the pty sidecar moved to src/servers/sidecar/pty/index.mjs. This file still pointed at // src/servers/api/terminal/pty-sidecar.mjs, which no longer exists, so the terminal never started. // // Deliberately omitted, and why — so the next person can tell "not applicable" from "forgotten": // officer-vnc mirrors an Xorg display with x11vnc; macOS has no Xorg to mirror. // officer-email needs the mbsync/IMAP stack that setup_mac.sh does not install. // officer-music the ffprobe indexer works, but a full ~/Music index is an expensive thing to // start by default and it is not part of the laptop workflow. // officer-vault a reverse proxy to a self-hosted Vaultwarden container. // officer-slskd supervises the slskd daemon. // officer-headscale fronts a headscale server. // officer-transmission fronts a transmission daemon. // officer-invoiceshelf fronts an InvoiceShelf container. // officer-memos needs an owner-configured Memos instance URL and token. // officer-photos needs an owner-configured Immich instance URL and API key. // officer-caldav supervises Radicale, which setup_mac.sh does not install. // officer-notify the outbound notifier; its producers are the queue and the email/agent // sidecars, so on a laptop there is nothing to notify about. // officer-wallet holds seed and node credentials. Not on a laptop. // // Start with: pm2 startOrRestart ecosystem.mac.config.cjs // The Linux host keeps using ecosystem.config.cjs; neither file references the other. // // `cwd` is pinned on every app because Bun auto-loads .env from the working directory (and the pty // sidecar does `import 'dotenv/config'`). Without it, starting pm2 from anywhere other than the repo // root silently falls back to PORT=5000 with no POSTGRES_URL. const cwd = __dirname; module.exports = { apps: [ { name: 'officer', script: 'bun', args: 'start', cwd, watch: false, }, // Holds the proxy secret and forwards to api.anthropic.com. Does NOT run agents — the old // `officer-claude` name covered both jobs and is exactly how this file ended up with half of chat. { name: 'officer-anthropic-proxy', script: 'bun', args: 'run src/servers/sidecar/claude/index.ts', cwd, watch: false, }, // The process that actually spawns `claude`. Resolves the owner from the database and the proxy // secret from disk, so it needs no startup ordering against the proxy above: if the secret is not // written yet it warns and re-reads before the next spawn. { name: 'officer-agent', script: 'bun', args: 'run src/servers/sidecar/claude/user-instance.ts', cwd, watch: false, }, { name: 'officer-opencode', script: 'bun', args: 'run src/servers/sidecar/opencode/index.ts', cwd, watch: false, }, // node, not bun — same as the Linux host. The pty sidecar is a .mjs that binds node-pty's native // addon, which is built against node's ABI. { name: 'officer-pty', script: 'node', args: 'src/servers/sidecar/pty/index.mjs', cwd, watch: false, }, ], };