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.
129 lines
7.0 KiB
Markdown
129 lines
7.0 KiB
Markdown
# 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.
|
|
- Threads are the canonical user-facing workspace route. Normal navigation
|
|
should open `/threads/[threadId]`; legacy job URLs under
|
|
`/spoons/[spoonId]/agent/[jobId]` are compatibility routes for jobs that do
|
|
not have a thread yet.
|
|
- 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 `[email protected]` there
|
|
for this project and do not commit it.
|
|
- Machine-generated values belong in `.local/<env>.generated.env`; never put
|
|
the generated Convex admin key in shared Infisical.
|
|
- `scripts/sync-convex-env <dev|staging>` 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.
|
|
- Containerized production workers that control the host Docker socket must set
|
|
`SPOON_AGENT_HOST_WORKDIR` to the host-side path backing
|
|
`SPOON_AGENT_WORKDIR`. Docker bind mount source paths are resolved on the host,
|
|
not inside the worker container.
|
|
- `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 reads Infisical `prod` through `scripts/ci-export-env.mjs`, logged in as the
|
|
read-only `spoon-ci` machine identity (Gitea secrets `INFISICAL_CLIENT_ID` and
|
|
`INFISICAL_CLIENT_SECRET`), and hands the result to the scripts as
|
|
`CI_ENV_FILE`. `scripts/export-env` refuses to run in CI.
|
|
- Plausible (`NEXT_PUBLIC_PLAUSIBLE_SRC`, the per-site script) loads through a
|
|
same-origin `/pa` proxy and PostHog (`NEXT_PUBLIC_POSTHOG_KEY`/`_HOST`) through
|
|
`/ingest`, after the page is idle. Both stay off when unset. Session replay comes
|
|
from PostHog; Sentry carries errors and traces only. Client code reads public env
|
|
from `@/publicEnv`, and `packages/ui/src/index.tsx` holds re-exports only so
|
|
`optimizePackageImports` can load just the modules a page imports.
|
|
- A push to `main` builds the images, syncs the Convex env, deploys Convex, pushes
|
|
the images, and asks the VPS to redeploy `podman-spoon.service`
|
|
(`ssh [email protected] spoon`). A push to `main` is a production deploy.
|
|
- 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.
|