tale
AGENTS.md42 starsChanged 12 days agoMITView on GitHub
The shared contract for every coding agent in every tale-project repository. Read it, then read .agents/repo.md — the repo-specific contract — before your first change. Repositories are Bun workspaces (with Turborepo where there is more than one workspace); a workspace script runs through bun run --filter <workspace> <script>. .agents/repo.md is the per-repo file: layout, stack, domain rules, extra gates, and the debt ledger. This shared file never carries repo facts — if a fact is specific to one repository, it…
- Reads credentials
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,774 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository9 other files it gives its agents.
- docs/AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- create-migrationSkill
- write-docsSkill
- write-translationsSkill
- create-migrationSkill
- write-docsSkill
- write-translationsSkill
The file
We split this AGENTS.md into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 43
Every code-writing task passes two gates.
- Very specific: line 70
Every deployable unit carries a manual layer at <unit>/tests/manual/, in the same shape in every repository, scaffolded by the generator …
- Very specific: line 105
Commits: follow .commitlintrc.json (atomic, imperative, ≤72-char header) and land
- Distinctive: line 143
Reach for a well-known, maintained library: before hand-rolling — prefer the established package over a custom solution.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Working in this repository
The shared contract for every coding agent in every tale-project repository. Read it, then read
.agents/repo.md — the repo-specific contract — before your first change.
Repositories are Bun workspaces (with Turborepo where there is more than one workspace); a
workspace script runs through bun run --filter <workspace> <script>.
Read the repo contract next
.agents/repo.md is the per-repo file: layout, stack, domain rules, extra
gates, and the debt ledger. This shared file never carries repo facts — if a fact is specific to
one repository, it belongs there. When the two seem to disagree, the repo contract wins.
How to work
The biggest quality lever is deciding well, not typing fast. Work in this order:
- Classify the task and follow its discipline end-to-end: a defect (find the root cause, lock it with a regression test); structure-not-behaviour (refactor without changing behaviour); new behaviour (a feature, screen, endpoint, or flag); a review (an adversarial read before merge). Exploring is read-only and returns the conclusion; a migration is phased and reversible, each phase green.
- Write a short planning note first — capture intent, status quo, and plan before any edit; keep scratch files in your global notes directory, never in the clone.
- Unknowns outside the repo? Research before deciding — questions first, sources in order, evidence in the note.
- Search before you write — orient, find the concept to reuse, enumerate the blast radius. The request names one site; the task is the concept.
- UI in scope? Learn the repo's design system first — where it lives is in
.agents/repo.md— then build to it. - Too big for one thread? Split it into disjoint units with complete briefs; you keep the done-gate.
- Do the work thin and reversible, following the discipline you classified — ask the moment a fork or roadblock appears; never guess.
- Prove it — tests carry the change; observe the real outcome; drive web UIs in a real browser.
- Review your own diff — adversarial read, then the automated reviewers.
- Land it — meet the shared definition of done, atomic commits, pushed straight to
main; no branch and no PR unless the repo contract says otherwise. The autonomous development cycle's tasks ride the repo's merge train instead, where it runs one.
Every code-writing task passes two gates. Gate A — before code: note · intent · status quo · reuse · conventions · blast radius — a divergent second copy of an existing concept is a defect, not a feature. Gate B — before done: the shared definition of done — green gate · security · tests · migration/data · locales (where the repo ships them) · docs · accessibility · sweep · observed · commits. Never claim a success you haven't observed.
Discover the conventions — don't memorize them
This file does not list the coding rules; the repo's own tooling does, and it can't drift. Read the enforced source and match it (orient in the repo first, then read the surrounding code):
| To learn… | Read / run |
| Lint rules & code style | .oxlintrc.json (+ nested per-workspace extends) |
| Formatting | oxfmt (bun run format + the edit hook) — never hand-format |
| Types | the root tsconfig.*.json family — leaves only extends |
| Commit format & scopes | .commitlintrc.json |
| Security / SAST | tools/opengrep/ — bun run lint:sast (where present) |
| Manual tests | any tests/manual/readme.md — bun run lint:manual |
| Repo specifics | .agents/repo.md |
| Everything at once | bun run check |
The guards are the spec — run bun run check and read the failures; they teach the house
style faster than prose. When you add a rule, add its guard — a rule no test enforces rots.
Manual tests
Every deployable unit carries a manual layer at <unit>/tests/manual/, in the same shape in
every repository, scaffolded by the generator and gated by bun run lint:manual. It holds
what a headless run cannot judge — layout, focus, print, live reactivity across two sessions,
degraded modes, exploratory pokes:
| Path | What it is |
readme.md | how a round runs · box grammar · judging · severity · failure policy |
setup.md | toolchain · stack + ports · reset choreography · accounts · baseline |
template.md | the shape of a NEW suite, and the authoring conventions |
suites/<name>.md | the tests — evergreen, re-runnable, never ticked in place |
reference/automation.md | what the automated specs already own |
reference/not-a-finding.md | out of scope · quirks · benign console output · debt (BL-n) |
reference/error-codes.md | every error code, and how to provoke it |
reference/pins.md | why a box says what it says — keyed by box, never by round |
runs/ | the journal, its two templates, and one r<nnnn>.md per round |
Suites and rounds are separate things. A suite is a test: evergreen, re-runnable, and never
carrying a tick or a finding. A round is history: it ticks a session log outside the repo and
lands as one record in runs/. A box is one line — - [ ] `ID` · **action** → judgment. — and
its ID is a stable contract: each suite declares the prefix its boxes carry, IDs are unique
per unit, and you append, never renumber. Ship new behaviour with its box, or with a row in
reference/automation.md when a spec owns it end to end.
Non-negotiable boundaries
Safety and architecture invariants — they hold even where no linter covers them:
- Never destroy state without explicit permission — local databases, caches, config files, seed data, fixtures. Assume every file on disk is the user's in-progress work.
- Secrets live in environment variables only — never hardcode or commit them; scrub logs.
- Validate at every boundary — user input, external APIs, webhooks; parameterized queries only, never string-built SQL or shell.
- Accessibility is WCAG 2.1 AA — real HTML, keyboard reachable, visible focus, labelled controls, AA contrast.
- Commits follow
.commitlintrc.json(atomic, imperative, ≤72-char header) and land directly onmain— no feature branch, no pull request, unless the repo contract says otherwise. The merge train is the exception every repository that runs one shares: the autonomous development cycle works each task on a branch offtrainand opens no pull request, its reviewer squashes the task into one commit ontrain, andtrainreachesmainin one pull request per train (train-<YYYYMMDD-HHMM>); the repo contract says when a train departs, how its pull request is checked and who lands it. Never addCo-Authored-Byor "Generated with Claude Code" / any attribution line —.husky/commit-msgstrips such trailers before commitlint runs. - Branches — where the repo contract asks for one, name it for the work, never for the
tool that did it:
<type>/<kebab-slug>with a type from.commitlintrc.json(feat/,fix/,refactor/,docs/,chore/,ci/), ordist/for published build output. Never an agent-vendor namespace (codex/…,claude/…,cursor/…);renovate/andautomated/belong to the bots,trainandtrain-*to the merge train. - A change is rarely one file — sweep the concept's blast radius: a user-visible string →
every locale the repo ships (+ docs); a new UI element → label + a11y + docs + tests; an env
var / flag / API field → docs +
.env.example+ the READMEs. The guards catch the big ones — run them. One TypeScript config — a workspace
tsconfig.jsonis exactly one key,extends, and holds NOcompilerOptions,include, orexclude. Every option lives in the root family, and a leaf picks the member that fits:Member Adds tsconfig.base.jsoneverything; bun + node types, no DOM tsconfig.dom.jsonthe DOM libs tsconfig.vite.jsonDOM + vite/clienttsconfig.node.jsonnode types ONLY — for code that runs on node tsconfig.strict.jsonnoUncheckedIndexedAccesstsconfig.convex.jsonConvex's required settings The base reaches into each workspace through
${configDir}, soinclude/excludeneed no per-leaf copy. Need an option one workspace alone wants? Add a family member — never a key in the leaf. Unused locals/params are the LINTER's job (eslint/no-unused-vars, which honours the^_prefix); never addnoUnusedLocals/noUnusedParametershere, or the two guards disagree.- Scaffold a new part (package / service / tool / skill) from a template (
bun run gen …), never hand-rolled — so it carries the standard configs, the test layout and the manual layer. - Reach for a well-known, maintained library before hand-rolling — prefer the established package over a custom solution; write it yourself only when no suitable library exists.
- Instructions are docs too — change a path, command, or pattern a skill or an agent contract documents, and update it in the same change.
Skills
Repo-dev skills live in .agents/skills/; bun run skills:sync mirrors them
into .claude/skills/ as a plain copy — Claude Code reads the mirror, while Cursor/Codex/Copilot
read .agents/skills/ directly. After editing a skill, run bun run skills:sync; never hand-edit
the .claude/skills/ mirror. Each repo's skill index lives in .agents/repo.md.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

