Skip to content

Coding Practices Digest

Autumn edited this page Oct 19, 2026 · 5 revisions

Coding practices digest

This page summarises ecosystem's root AGENTS.md and pipeline code and tooling decisions. The full files win where they differ. Project-buddy's target-specific rules remain in its own wiki.

This digest is reference material, not an assertion that the runtime automatically loads it. When a practice this page covers changes, update this page in the same change.

Scope

  • Ecosystem is the home of the issue pipeline under apps/issue-pipeline/, with npm workspaces, one root package-lock.json and mise tasks in each app's mise.toml.
  • Before you change the issue pipeline, read its README: a merge changes nothing that runs until the operator installs it.
  • Ecosystem's AGENTS.md sets its current rules. Site-only and project-buddy target rules are not ecosystem policy.

Design

The code follows John Ousterhout's A Philosophy of Software Design.

  • Deep modules: small interfaces over substantial functionality. No pass-through methods, thin renaming wrappers, or classes that hold one call.
  • Information hiding: each design decision lives in one module, such as the model choice, prompt assembly, the storage layout, error classification or the manual's URL scheme.
  • Pull complexity downward: a module handles its own hard cases instead of pushing options or steps onto callers.
  • Define errors out of existence: an unknown or malformed id is "not found" (undefined), and deletes and re-indexes are idempotent.
  • Layers: different layers speak their own vocabulary. Split code by the knowledge it hides, not by the order things happen.
  • Somewhat general-purpose: interfaces fit today's needs without one caller's special case.
  • Comments and names: interface comments say what a module promises, not how. Implementation comments explain only what the code can't. Names are precise and consistent.
  • Strategic, not tactical: leave the code a little better designed than you found it.

Types

  • No any, no non-null !, and no as casts except at one validated boundary.
  • External data is parsed with zod at the boundary: request bodies, form data, env vars, JSON columns and model tool inputs.
  • Ids that can be mixed up get their own types, such as ProjectId and ChatId.

Lint

  • No rule is turned off, and tests follow the same rules as other code. If code is hard to satisfy or to test, redesign its interface.
  • No dodges: computed keys, bracket reads and process.getBuiltinModule are not allowed. No biome-ignore. The root and pipeline Biome configs encode their documented process-boundary exceptions.
  • Patterns the rules force:
    • Specs use test, not it; skipped tests and test.fixme stubs fail lint.
    • Regexes are top-level, named and use the u flag.
    • Parameter and return types are explicit; interfaces use property-style signatures; exports come last; keys from an index signature are read by destructuring.
    • No ternaries, and no void on promises.
    • noSecrets flags long camelCase identifiers in strings, so test titles name the behaviour, not a long function name.

Tests

  • Tests pin promised behaviour, not internals (tests-pin-promised-behaviour): what the wiki and the README promise, reply shapes, stop codes, caps and limits, GitHub-visible effects and regression behavior. Copied constants, prompt or log text, call order, argv and whole-trace snapshots are not promised.
  • A flake is a failure (flakes-are-failures). Fix the cause or the measurement; never rerun until it passes. No test depends on timing.
  • Waits follow web-tests-under-load: wait for the event that marks work done. A clocked wait that remains is a named constant, with its worst measured time and load, set to at least 3 times that time.
  • Pipeline tests are bounded (pipeline-tests-bounded): what a test starts ends with it, through test/bounded-test-kit.mjs, and every wait has a deadline.
  • Tests and their helpers live in test/, never src/ (test-code-in-test): each in the folder its subject has under src/, so src/chats/store.ts is tested by test/chats/store.test.ts. Helpers are named fake-*.ts, *-fixtures.ts or *-test-kit.ts. src/ holds only what the app runs.

Run mise //apps/issue-pipeline:check for the full gate. The pipeline README describes its isolated test setup.

Secrets and session boundaries

  • Never print a .env* file, and never copy a secret into code, docs, logs, issues or commits.
  • In the issue pipeline, no session holds a gh token; writers commit through pipeline_commit and the job pushes (sandbox-ready-jobs).

Clone this wiki locally