# AGENTS.md ## Architecture - `apps/next`: Next.js 16 frontend. - `apps/agent-worker`: optional server-side coding-agent worker. It polls Convex for queued jobs and may control Docker/Podman to run ephemeral job containers. It also exposes a server-only HTTP API, defaulting to port 3921, that Next route handlers proxy to for active workspace files, diffs, messages, commands, and draft PR actions. - `apps/expo`: Expo scaffold; only work here when explicitly requested. - `packages/backend/convex`: self-hosted Convex functions, schema, and auth. - `packages/ui`: shared shadcn-based UI components. - `tools`: shared ESLint, Prettier, Tailwind, TypeScript, and Vitest config. - Local development uses host-run apps, local Convex on ports 3210/3211, local Postgres on port 5432 for Convex storage, and the Convex dashboard on port 6791. Agent jobs are opt-in; build `docker/agent-job.Dockerfile` as `spoon-agent-job:latest` before running Docker-backed jobs. - Gitea CI builds and pushes `spoon-next`, `spoon-agent-worker`, and `spoon-agent-job` images to `git.gbrown.org/gib`. In production, `SPOON_AGENT_JOB_IMAGE` should point to `git.gbrown.org/gib/spoon-agent-job:latest`, and the worker service requires access to the host Docker socket. API-key provider jobs run through OpenCode; Codex ChatGPT login profiles run through the Codex CLI with an injected `CODEX_HOME/.codex/auth.json` inside the isolated job workspace. The job image must keep Node, npm, Bun, pnpm, yarn, git, ripgrep, jq, Python, OpenCode, and Codex available. ## Protected and generated files - Never edit `packages/backend/convex/_generated/**` or `packages/backend/convex/http.ts`. - Do not rename `apps/next/next.config.js` or `apps/next/src/proxy.ts`. - Preserve `typescript.ignoreBuildErrors` in Next config. - Do not modify Sentry config or `tools/tailwind/theme.css` unless requested. - Generated `.cache`, `.turbo`, `.local`, and environment files are ignored. - `scripts/convex-codegen` generates Convex API files for checks and image builds when deployment env is available; do not hand-edit generated output. ## Environment rules - Local `dev` and `staging` come only from Infisical via `scripts/with-env`; it never falls back to `.env*`. - Run `infisical login` and `infisical init` before local development. - `scripts/export-env` enforces `.local/infisical.env` when multiple local Infisical accounts are logged in. Put `INFISICAL_EMAIL=you@example.com` there for this project and do not commit it. - Machine-generated values belong in `.local/.generated.env`; never put the generated Convex admin key in shared Infisical. - `scripts/sync-convex-env ` copies Authentik, GitHub App, UseSend, `SITE_URL`, `SPOON_WORKER_TOKEN`, encryption, and Convex Auth signing variables from Infisical into the selected Convex deployment. Backend dev/setup scripts run it before `convex dev`. - Agent workspace proxy env uses `SPOON_AGENT_WORKER_URL`, `SPOON_AGENT_WORKER_HTTP_PORT`, and `SPOON_AGENT_WORKER_INTERNAL_TOKEN`. Keep these server-only; the browser must never receive worker tokens. - Host-run worker dev uses `scripts/dev-agent-worker` after Infisical env loading. It prefers Podman, sets `SPOON_AGENT_CONTAINER_ACCESS=host_port`, and expects `spoon-agent-job:latest` to exist locally. - `bun smoke:agent-container` checks that the local job image has Node, npm, Bun, pnpm, yarn, git, ripgrep, jq, Python, OpenCode, and Codex available. - Old terminal workspaces can be deleted from `Settings -> Worker`; orphaned containers/workdirs are cleaned through the worker HTTP API, not from the browser directly. - CI uses Gitea-injected secrets or `CI_ENV_FILE` and must not call Infisical. - Gitea image builds force `SPOON_AGENT_CONTAINER_RUNTIME=docker`; keep local Podman auto-detection out of CI image tagging/pushing. - CI must provide Convex deployment env for codegen, either `CONVEX_SELF_HOSTED_URL` plus `CONVEX_SELF_HOSTED_ADMIN_KEY`, or `CONVEX_DEPLOYMENT`. - App code imports validated variables from `@/env`, never `process.env`. - Add cache-relevant variables to `turbo.json` `globalEnv`. ## Code and dependency rules - Use `const` arrow functions instead of function declarations. - Add `.js` extensions to Convex generated-file imports. - Put custom frontend routes directly in `apps/next/src/app` or normal route groups such as `apps/next/src/app/(auth)`. - Extend the Convex `users` table for application user data; do not add a profile table by default. Authenticate protected functions. - Manage shared versions in root catalogs. Never run `bun update` in a package. - Run root `bun install` and verify with `bun lint:ws`. - Update this guide when architecture or workflows change. ## Local stack ```sh bun db:up # start Postgres, Convex, and dashboard bun dev:next # host Next + deploy/watch local Convex functions bun dev:agent # run the optional coding-agent worker on the host bun dev:next:worker # run Next, backend, and agent worker together bun sync:convex # sync Infisical values into Convex bun db:down # stop and preserve local data bun db:down:wipe # remove local data volumes and generated admin key ``` Local URLs: app `http://localhost:3000`, Convex `http://localhost:3210`, dashboard `http://localhost:6791`, Postgres `localhost:5432`. Use `INFISICAL_ENV=staging bun dev:next` for staging services. Normal `db:up` never connects to staging. ## Validation Use `bun typecheck`, never a production build for routine validation. The full gate is `SKIP_E2E=1 bun run ci:check`; it runs Convex codegen before checking. Local-stack smoke e2e is `bun test:e2e`. Pre-commit runs lint-staged serially and pre-push runs the bounded full gate.