AGENTS
AGENTS.md
tcm-ts is Unison's content-addressed codebase model for plain TypeScript, plus an app platform on top
(inferred client/server placement, server functions, jobs, typed tables). Its docs are pages of its codebase:
start with tcmts.docs.README (tcm_view, or the docs site at https://tcm.codes/docs);
tcmts.docs.developing has the codebase's layout.
Working in tcm's codebase
tcm is developed in its own codebase, and nowhere else: this repository only says how to get it (pnpm tcm makes
codebase/ from tcm's server). There are no source files to edit.
With the tcm MCP server (this repository's .mcp.json), use its tools: tcm_status to start, tcm_find, tcm_view and
tcm_at to read, tcm_patch for a small change, tcm_edit then tcm_update for a bigger one, tcm_todo, tcm_test. Without
it, pnpm tcm <command> is the CLI. The tcm doing this is the last build pnpm verify passed, not the code being
changed: tcm_test tests the change, TCM_LIVE=1 pnpm tcm … runs it (from the codebase), and live: true on tcm_edit,
tcm_patch, tcm_check, tcm_update, tcm_add and tcm_test uses it, to use a change to tcm before it's verified
(tcm_cli with live and cwd runs it on a codebase made for a repro).
Keep the docs current
tcmts.docs documents every user-visible feature, one page per area (index in tcmts.docs.README). It describes
what the code does now. Pages are files of the codebase: tcm_edit tcmts.docs.cli writes cli.md to change and
save with tcm_update.
- Every change that adds, changes or removes user-visible behaviour updates the docs with it: a command, flag, API, error message users act on, guarantee or limitation.
- Put it on the page for its area. A new area gets a new page, listed in the
tcmts.docs.READMEindex (and in the README's feature list,tcmts.README, if it's a headline feature). - New CLI commands or flags also go in
tcmts.docs.cliand the command's definitions: its route and help intcmts.cli.commands(routeFind,helpFind:tcm help,--helpand shell completion read them) and its handler intcmts.cli.run(runFind);tcmts.docs.developingsays how they fit. - Fixed or newly found limits are updated in
tcmts.docs.limitations. - Check claims against the code, not memory or older docs. Remove what's no longer true.
- The README stays short: a pitch, quick start, and links into the docs.
- The examples (
tcmts.examples) must keep working.tcmts.cli.test.e2e.examplesbuilds and runs them; when a feature changes how code is written, update the examples too. Their files are kept as written, so tcm's codebase doesn't typecheck them:pnpm examples:checkdoes, in seconds, after a change to one.
Verifying a change
Run pnpm verify when a change is done; it names any failing tests. A change on a session's branch (each MCP
session has one: tcm_status names it) is verified there, TCM_BRANCH=<branch> pnpm verify: that checks it all
without making it the known-good tcm, which waits for the change to land on main (when the user says to) and main
to be verified. Plain pnpm verify checks main. It's a definition in tcm's codebase
(tcmts.dev.verify, run with pnpm tcm run): it checks the codebase (tcm todo, tcm verify), runs its test
definitions, builds the docs site, and packs tcm-ts and runs the end-to-end tests against that, all side by side.
Tests run again only where code they ran changed, so with nothing changed it takes under a second, and a few
seconds to a few minutes otherwise.
pnpm test (tcm test) runs the tests the change reaches: the quick check while working.
New behaviour gets a test, written as test definitions (export const testX = () => …). End-to-end tests, running
tcm as a program, go in tcmts.cli.test.e2e (helpers in tcmts.cli.test.e2e.harness; each test independent, since
each runs as a program of its own, cached by the code it ran); what they need as files they import from the
codebase (tcmts.fixtures). Tests that call code directly go in a test namespace beside the code, cached by hash.
Rules
- Hashes are pinned. The hash format (v2,
IR_VERSIONintcmts.core.hash) is pinned bytcmts.core.test.golden;tcmts.core.slots(the order the IR visits children in) is part of it. Change hashes only on purpose: bumpIR_VERSION, add the step from the last format's IR (tcmts.core.migrate.IR_STEPS), and re-pin, and add the old format's codebase as a fixture (tcmts.fixtures.codebase-v1, made with the known-good tcm before the bump) fortcmts.cli.test.e2e.migrate.tcm migratemoves codebases, tcm's own included:pnpm verifymigrates it with the new tcm before making that tcm the known-good one, keeping both as they were. History hashes (namespaces and causals, which codebases compare when they sync) are pinned the same way bytcmts.store.test.history. - Table layouts move by steps. A change to
tcmts.store.SCHEMAchangesLAYOUT, which older codebases are in: add the step from the last layout totcmts.store.LAYOUT_STEPS, and that layout's codebase as a fixture (tcmts.fixtures.codebase-layout-<layout>, made with the known-good tcm before the change) fortcmts.cli.test.e2e.migrate.pnpm verifymigrates tcm's codebase as it does for a new hash format. tcmts.cli.server_api.createServerHostmust stay self-contained: its source is written to.tcm/cache/tcm-host.js, so it can only use what comes in throughdeps.- No explicit client/server boundaries (no
"use server"): placement is inferred. - Follow Unison's design where it applies; it doesn't cover frontend, so there we decide.
- Prefer Vite for browser tooling.
History
- tcm's history is the record of changes (
tcm history): each command that changes names is an entry. Keep each change to one thing, and give it a message saying what and why:messageon tcm_patch, tcm_update, tcm_add, tcm_mv, tcm_rm and tcm_resolve (-mon the CLI), a line, then more after a blank line where it helps. It's the entry's title intcm historyand the web UI;tcm describe <n> -m …changes it afterwards. - Landing a branch (tcm_merge) takes a
messagetoo: what the whole branch did and why, for whoever reads main's history. Say the same in a release's notes and a contribution. - The repository's own few files (README, AGENTS.md, package.json, scripts/codebase.sh) are written from the
codebase by
pnpm repository; commit them when they change, ending the message withCo-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>when an agent wrote the change. - Work stays on its branch until the user says to land it on main (then tcm_merge, approved, with its message); never land it otherwise.
- Never push (
tcm push,tcm contributeor git) or publish; that's done by hand. Contributing from outside istcmts.docs.contributing.