# AGENTS.md — how changes are made in this repo This file is read by AI agents (via opencode) **and** by human developers. Follow it. ## What this repo is A **best-practices reference application** — the canonical example the team builds and points to. It is a small but realistic multi-container app, built and run with **docker-compose**: - **api** — the HTTP service (the app's public surface). - **worker** — background/async job processor. - **db** — PostgreSQL, the shared datastore. Everything is wired so the whole stack comes up with a single `docker compose up`. The point of this repo is that every part demonstrates how we like things done: clear structure, tests, and CI. ## Golden rules - You may edit **any file** in this repo (app code, `docker-compose.yml`, `.gitea/`, tests, CI). - **NEVER push to `main`, and NEVER merge a pull request.** All work goes on a branch and becomes a PR that a human (or `@pm` under the `autopilot` label) merges. You do not have merge authority. - **Never print, exfiltrate, or invent secret values.** Reference secrets via env vars / compose `environment:`; never paste real secret values into comments, PRs, logs, or code. Config that *references* a secret is fine; the value is not. - Keep changes **minimal** and match the conventions already in the file you're editing. - Do the work on a **branch** — never paste code or diffs into the issue thread. - Because this is a reference repo, favor **clarity over cleverness**: small services, obvious names, comments where a newcomer would need them. ## Project layout (target — grows as features land via issues) ``` docker-compose.yml # the whole stack: api + worker + db api/ # the HTTP service (its own Dockerfile) worker/ # the background worker (its own Dockerfile) db/ # schema / migrations / init SQL tests/ # automated tests (unit + integration) .gitea/workflows/ # CI (build, test) + the ai-agent caller ``` Add a service by giving it its own top-level directory and a service entry in `docker-compose.yml`. ## Local run & tests - **Run the stack:** `docker compose up --build` — api, worker, and db should all come up healthy. - **Tests:** every change must keep the test suite green. Run tests the way CI does (e.g. via a `docker compose run` test service or the documented test command) before you consider work done. - Prefer **integration tests through compose** for cross-service behavior (api ↔ db, worker ↔ db) over mocking the whole world. - Give each service a **healthcheck** in compose and depend on it (`depends_on: condition: service_healthy`) so startup is deterministic. ## CI CI lives under `.gitea/workflows/`. It must, at minimum, **build the images and run the tests** on every PR. Keep CI green — a PR that breaks the build or tests is not ready for review. When adding a new service, extend CI to build and test it too. ## Branches & pull requests You start on branch `ai/issue-` (N = the issue number). **Split independent changes into separate PRs** so each is small and reviewable: ``` git checkout main git checkout -b ai/issue-- # e.g. ai/issue-7-api-healthcheck # make just that one change git add -A && git commit -m "" && git push -u origin HEAD ``` - Only keep changes together on one branch if they genuinely must ship as a unit. - Commit and **push incrementally** so progress is visible on the branch. - **Do not open pull requests yourself** — the automation opens one PR per branch you push. ## PR description End your reply with a clean pull-request description wrapped EXACTLY between these markers. Everything before `BEGIN_PR_DESCRIPTION` is treated as working notes and discarded: ``` BEGIN_PR_DESCRIPTION ## Summary <1-2 sentences: what changed and why> ## Changes END_PR_DESCRIPTION ``` Do not paste full files or large diffs — the review happens in the PR diff. ## Database changes & migrations The datastore is Postgres, and `docker compose up` does **not** magically evolve a schema. For schema changes: - Put schema/migrations under `db/` (e.g. `db/migrations/NNNN-description.sql`, applied in order). - Make migrations **idempotent / forward-only** and safe to re-run. - Never require a manual, undocumented step — a fresh `docker compose up` on an empty volume must produce a working schema. ## When unsure If the task is genuinely unclear or missing details you cannot reasonably assume, make **no** changes and reply with specific questions instead.