PostHog loads after the page is idle through a same-origin /ingest proxy and follows the signed-in Convex user. Plausible uses the per-site script through a /pa proxy. Sentry keeps errors and traces only. Pages load only the @spoon/ui modules they import, and client code reads public env from publicEnv.ts so zod stays out of the browser. Both analytics integrations stay off until their env is set in Infisical prod.
- Box init + chownInBox exec explicitly as root: under podman keep-id the
container's default user is the mapped uid, which cannot useradd/chown.
- Init renames an existing uid-1000 passwd entry (podman keep-id injects one
named after the HOST user) instead of adding a duplicate that would win the
getpwuid lookup and make whoami report the wrong name.
- Terminal connections tag their shell with a per-connection marker and reap
the process group on WebSocket close: closing the attach socket never
killed the exec'd shell, so every disconnect leaked an attached tmux client
(session stuck at the smallest zombie's size; enough dead clients starve
tmux rendering for live ones).
- Job image: nvm 0.39.5 at /usr/local/nvm (user-writable) with
/etc/profile.d/nvm.sh, matching what user dotfiles expect; docs for the box
user + ownership model.
Add @anthropic-ai/[email protected] to the job image global npm install,
extend the smoke script with claude --version plus a documented per-runtime
turn block, and reconcile OpenCode/Claude adapter flags against the real CLIs
(all assumed flags confirmed). Document the anthropic_oauth_json credential
snapshot pattern in the README.
- Base fedora:41; reinstall toolchain (node 22, gcc/c++, neovim, tmux, git, etc.)
- Add QoL CLI from the user's Panama setup, all in default Fedora repos: zoxide,
eza, bat, fzf, fd, gh, gum, ripgrep, bash-completion; oh-my-posh via installer;
pnpm/yarn/bun via npm; keep [email protected].0 + [email protected].9 pinned
- Ship neutral system-wide defaults that work even with an empty/mounted HOME:
/etc/profile.d/spoon.sh (zoxide/eza/fzf/oh-my-posh init + aliases),
/etc/tmux.conf (login-shell panes), /etc/spoon/omp.json (default prompt theme)
- .dockerignore: re-include docker/agent-job-rootfs into the build context
- Verified: codex runs a real turn on Fedora (exit 0); all tools present
- agent-job image: add neovim, tmux, less, unzip, wget, locales for the
interactive shell (tmux powers cross-reconnect session persistence)
- Wire NEXT_PUBLIC_SPOON_AGENT_WORKER_WS_URL as a build arg (Dockerfile +
compose.yml) since NEXT_PUBLIC vars are inlined at build time
- docs/agent-terminal.md: architecture, env, nginx WS exposure, dev testing,
security; note the build-time var in docs/compose.prod.yml
Root cause of the prod empty-response: the spoon-agent-worker image shipped
without a docker CLI binary, so it could never launch the codex job container.
On Debian trixie (the bun base) 'docker.io' + --no-install-recommends installs
the daemon package but omits the client (split into 'docker-cli'), leaving no
'docker' on PATH. execa('docker', ...) hit ENOENT, and with reject:false that
resolves with exitCode undefined -> coerced to 0 -> looked like a successful
empty run -> 'Codex completed without producing an assistant response'.
- agent-worker.Dockerfile: drop docker.io, install the official static docker
CLI client pinned to 29.5.3 (matches the host daemon) to /usr/local/bin/docker
- runtime/docker.ts: normalizeRunResult() so a spawn failure (exitCode null) is
always a non-zero exit carrying the real reason, never a silent empty success
- tests: cover the spawn-failure and normal-result paths
- Pin [email protected].0 + [email protected].9 in the job image (was @latest,
causing dev/prod drift)
- Worker now s the job image once per process so prod stops
running a stale Codex
- Surface Codex error/turn.failed events instead of swallowing them, so the
real failure reason is reported rather than 'no assistant response'
- Harden the Codex JSON parser to also handle the legacy msg-wrapped shape
- Fix the docker-in-docker workdir: bind-mount identical host:container path
and set SPOON_AGENT_HOST_WORKDIR (named volume can't be mounted by sibling
job containers)
- Add docs/compose.prod.yml as a documented reference deployment