Skip to content

Instantly share code, notes, and snippets.

@dctmfoo
Created February 22, 2026 13:27
Show Gist options
  • Select an option

  • Save dctmfoo/10dddc1ee81f1a2bfb2863b238be9469 to your computer and use it in GitHub Desktop.

Select an option

Save dctmfoo/10dddc1ee81f1a2bfb2863b238be9469 to your computer and use it in GitHub Desktop.
Doot AGENTS.md — canonical contributor contract for AI + human contributors

AGENTS.md

This file is the canonical contributor contract for this repository.

It is intentionally concise. Focus on stable engineering rules, not volatile repository snapshots.


Purpose

Use this document to align all contributors (human + AI) on:

  • Code quality standards
  • TDD workflow
  • Type discipline
  • Error handling expectations
  • Verification gates before handoff

If a detail is likely to drift quickly (counts, exhaustive inventories, long endpoint/tool lists), it does not belong here.


Communication preference (required)

When explaining work to Wags (or other non-implementation stakeholders), default to functional-first:

  1. Direct answer first (yes/no or recommendation in first line)
  2. Functional impact (what changes for user/operator behavior)
  3. Why it matters (risk avoided or outcome improved)
  4. Implementation details last (only as needed)

Style rules:

  • Don’t lead with file paths or internal jargon
  • Prefer plain language over internal abstractions
  • Be concise and concrete
  • If tradeoffs exist, list options and clearly mark the recommendation

Core engineering contract

1) TDD first (non-negotiable)

This requirement is mandatory and must remain in this file.

Always follow red → green → refactor in vertical slices:

  1. Confirm the next behavior slice and any interface change
  2. RED: write exactly one failing test (public interface)
  3. GREEN: implement the minimal code to pass that one test
  4. Repeat one-test/one-implementation cycles
  5. REFACTOR: only after tests are green

TDD rules:

  • No horizontal slicing (no bulk tests then bulk implementation)
  • Test behavior, not internals
  • Test through public interfaces only
  • Mock true boundaries only (external APIs, time/randomness, fs/db when needed)
  • No refactor while red
  • Test names should describe outcomes, not implementation

2) Type discipline

  • No any without explicit justification comment
  • Prefer unknown and narrow explicitly
  • Design types first, implementation second
  • Explicit return types on exported/top-level functions
  • Make invalid states unrepresentable where practical

2b) Advanced type patterns

  • Prefer discriminated unions over optional fields for state variants
  • Use branded types (string & { __brand: "UserId" }) for domain IDs that must not be swapped
  • Use satisfies for config/constant validation — never as for type assertion
  • Every async operation must accept AbortSignal for cancellation
  • Clean up resources in finally blocks; use using (TS 5.2+) for disposables
  • Exhaustive switch must end with default: never guard

3) Error handling

  • Narrow try/catch to the specific throwing call
  • Never swallow errors silently
  • Prefer typed errors or discriminated unions
  • If throwing, make failure mode clear and intentional

4) Simplicity and readability

Hard rules:

  • No nested ternaries
  • No dense one-liners for multi-step logic
  • Prefer early returns over deep nesting
  • One responsibility per function
  • Flatten async flows (async/await over nested .then() chains)
  • No dead code (unused imports, commented blocks, unreachable paths)
  • Comments explain why, not what

5) Abstraction discipline

  • No preemptive abstractions
  • Extract only after 2–3 real repetitions
  • Composition over inheritance
  • Keep import chains shallow

Implementation style

  • TypeScript + ESM ("type": "module")
  • 2-space indent, double quotes, semicolons
  • Sorted imports: stdlib → external → internal (with .js extensions in imports)
  • Use function keyword for named/exported functions
  • Use the repo-pinned runtime/tooling (.nvmrc, package.json#packageManager, .npmrc); do not mix Node/pnpm versions across install/build/run
  • React: explicit Props types, named exports, one component per file
  • Co-locate tests with source (foo.ts / foo.test.ts)
  • Prefer small cohesive modules (~200 lines target)

For new or substantially modified .ts files under src/, start with:

// File: {filename} | Module: {module-name}


Verification discipline (required)

Fast loop (during development)

  • Run focused tests for touched modules
  • Re-run focused tests after each green step in TDD cycles

Handoff/PR gate (before completion)

Always run:

pnpm test
pnpm build
pnpm readiness:debt:gate

If dashboard/UI changed:

pnpm dashboard:build

If readiness tooling/docs changed:

pnpm readiness:audit

Quality checklist before marking complete

  1. Would a new team member understand this in ~30 seconds?
  2. Are tests present for new behavior and passing?
  3. Any nested ternaries, silenced errors, or dead code left?
  4. Does each function have one clear responsibility?
  5. Did we preserve existing conventions rather than inventing new patterns?

What should NOT live in this file

To avoid drift and context bloat, do not store these here:

  • Snapshot counts (test files, plugin counts, package version)
  • Exhaustive endpoint/tool command inventories
  • Long runtime/service boot sequences that change frequently
  • Path caveat lists that require ongoing bookkeeping

When those details are needed, verify directly from source with repo tooling (rg, tests, and focused code reads).


Docs-as-code rule

If you change contributor workflow, quality rules, or verification requirements, update this file in the same PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment