Repository-wide rules. apps/* and some packages/* have their own AGENTS.md with the rules for that area.
bun installbun run dev: hub + portal (needs.env, see.env.exampleand docs/DEV.md)bun run check: typecheck everything and bundle the hubbun run test: all tests (hub tests need Postgres)bun run lint: oxlinte2e/: live checks against real services, run by hand, never in CI (e2e/README.md)sh tooling/vendor-diff-check.sh: vendor drift gate
- Interchange is stock. Code lives in
apps/*andpackages/*only. vendor/interchangechanges only with maintainer approval, each listed invendor/interchange/VENDORED.mdandtooling/vendor-diff-allowlist.txt.
- Stock first. Before writing logic, look for an Interchange route or primitive that already does it (see the reference below). Re-implementing one is a defect; where stock lacks a path, raise it upstream instead of building a copy.
- The policy drives everything. A repository's rules and actions live in its policy file,
.corbits-triage.ymlon its default branch, and nowhere else; under the workspace'spolicyautomation that file also decides what Triage does on its own. Nothing repository-specific is written into workflow code. - Workflows are deterministic. Agents exist only where inference happens (packages/triage-workflows/AGENTS.md).
- Effects are idempotent under their effect id, host writes included.
- One writer per pull request. The manager is the only workflow that writes to a pull request, and it lives until its final post or until its head waits only on CI (docs/ARCHITECTURE.md, How a pull request flows).
- Three isolated parts. Deterministic checks, the judge and code review each have their own limits; one part's limit never changes what another reads.
- One local sidecar per deployment. The listener, each manager and each judge run in a local sidecar of their own, up to a capped number; past the cap a deployment goes to a sandbox, and code review always runs in one.
- Size is a risk signal, never a hold: a crossed size limit labels a pull request and never makes it wait.
- Grants decide automation. Whether an action runs on its own is decided from the workspace's role grants, never a hard-coded limit.
- Downstream work is another workflow. Reviewing, fixing or cleaning up a pull request is a workflow of its own, started by mail or a signal from an action; never a step inside the manager.
- API first. Every custom hub route is described in
/openapi.json. The portal and the extension wrap those routes and are never the only way to do anything. - Credentials, grants and tenants are Interchange's. Secrets live in the hub vault and reach sidecars at launch and rotation; never read them anywhere else, never persist them.
- Hosts. GitHub and Bitbucket Data Center. A repository record carries
source(absent = GitHub), every mail names it asrepoSource, and each host has its own listener, manager, judge and code review workflows. A change to host behaviour covers both, or says why not.
Check these for a stock route or primitive before touching the hub, sidecars or workflows. Links follow upstream main; the commit we run is the stock ref in vendor/interchange/VENDORED.md.
- LAYOUT.md, CONVENTIONS.md: where things live and how upstream writes code
- ARCHITECTURE.md: hub, sidecar and workflow run model
- WORKFLOW_AUTHORING.md: how workflows are written
- workflow-lifecycle-policy.md, SIDECAR_PLACEMENT.md: lifetimes, capacity release and where sidecars run
- API.md, ROUTES.md: the stock routes the portal and hub use
- INBOUND_MAIL_POLICY.md, MESSAGE.md: mail routing behind the webhook bridge
- AUTH.md, CREDENTIALS.md, GIT_ACCESS.md: sessions, the vault and git tokens
- Match existing style. No license headers; LICENSE.md is the license.
- Comments say why, when the code cannot; never what it does.
- async/await with try/catch; no
.then/.catch/.finallychains. - Named functions; no IIFEs, no anonymous callbacks beyond one-line array methods, no nested ternaries.
- No dynamic imports, except in the portal for bundle splitting.
- Fallbacks only where a real default exists. Otherwise throw, and handle errors and missing values properly.
- Leave no dead code, unused exports or aliases behind.
- Only load-bearing tests, end to end where possible.
- Tests beside the code are fast and offline; anything that runs real services lives in
e2e/. - The one exception is
tests/chain/: it starts the real hub and local sidecars but reaches no outside service (a fake GitHub and a stub decision model), and CI runs it as its own job,bun run test:chain. tests/policy-corpus/holds one policy file per case with its expected outcome, run through every reader of the policy; a new policy key needs a fixture there.tests/model/checks R1, R3 and R5 of docs/INVARIANTS.md across event orders, running the real GitHub listener and manager in one process against the hub's own routes and a fake GitHub under a deterministic policy; what it stands in for is listed there. A change to the listener, the manager, the workflows or the contracts names the rules it touches and keeps it green.- Never read
process.envin tests. - A failed chain shard is read, never rerun.
- A change to how a workflow judges or reviews states its package's eval result before and after.
- Docs change only when a person would notice: update the step or sentence that changed, and keep it short. docs/ARCHITECTURE.md is the architecture, not the implementation.