Also in: Español, Português, 日本語, Deutsch, Français
Disclosure: we build Carbon Forge at 100monkeys.ai, so read this as a maker's account. This guide was drafted by one of our AI agents from the public docs, chiefly the symbols.drift and Governed seams sections of MCP tools catalog: Semantics and "Drift between prose and code" in The Carbon paradigm, and reviewed by the company. The table and calls are the docs' own examples. Where the docs leave a question open, the last section says so.
What the report is
The paradigm page in one line: "A workspace's reserved .governed-seams page declares which pages govern which definitions of a code tree". symbols.drift "joins every definition a lane adds, removes or re-signs to the seams that govern it and reports each as changed with or without a patch to its governing page on the same lane, from the syntax index alone, so the same lane and the same seams page answer the same report byte for byte." No model reads anything. And one limit to hold onto: "The report advises and never refuses a landing."
Step 1. Pick the definitions a page describes
Start with the pages that would mislead a reader if the code moved under them: an architecture page for billing, a guide for sign-in. Find the definitions they describe with the semantic index:
symbols.search { "tree": "app", "query": "charge", "prefix": true } Definitions come from tree-sitter's tags queries for TypeScript and TSX, JavaScript, Python, Go, Rust, C, C++, C#, Java, Ruby, PHP, Scala and Bash. CSS, HTML, JSON, YAML, TOML and HCL get syntax trees "but no definitions or references", so a seam over those files reports nothing. Names are "matched by name, not by type checking".
Step 2. Write the .governed-seams page
Create a page at the reserved path .governed-seams whose first Markdown table is headed tree | glob | symbols | records. The docs' example:
| tree | glob | symbols | records |
| --- | --- | --- | --- |
| app | src/billing/** | chargeCard, refund | architecture/billing |
| app | src/auth/*.ts | * | guides/login, architecture/security | tree: a code tree's path.glob: one rule in the import ignore-rule syntax over the tree's file paths, not starting with!.symbols: comma-separated definition names, or*alone for every definition under the glob.records: comma-separated page paths, the pages that govern those definitions.
"A seam is declared, never inferred: no link, tag, metadata key or embedding makes one." The page is read from the trunk, "so a lane cannot ungovern its own change." Land it on the trunk before the work it should watch. A malformed page stops every report until it is fixed, with a sentence naming the line: The governed seams page .governed-seams is malformed at line <n>, ...
Step 3. Change governed code on a lane
The report reads a lane, so the change must be on one: lanes.create, then trees.apply_patch or trees.put with lane, as Working in lanes shows. Re-sign chargeCard, say, by adding a parameter.
Step 4. Read the drift report
symbols.drift { "lane": "agent/7/fix-login" } Add tree to read one tree alone. The answer:
{ lane, composition_hash, report_sha256, findings, pending, governed_rows } Each finding names the tree, path, symbol and kind, the from_signature on the trunk and to_signature on the lane (null where a side does not hold it), records as { path, updated_on_lane }, and callers, the count of references to the name on the lane. The class is the verdict: seam_changed_without_record when the lane holds no live patch on a governing page. That is your stale doc, caught before the landing.
Read pending before you trust an empty report: it lists changed files under a seam's glob that the index "cannot answer yet", and "the report is complete when pending is empty." A lane in conflict is refused until the conflict is resolved.
Step 5. Update the governing page on the same lane
Edit architecture/billing with pages.apply_patch and the same lane, so the page and the code wait together. The guide Land a code change and its documentation in one changeset walks that part.
Step 6. Read the report again, then land
Run symbols.drift again. The finding now reads seam_changed_with_record, and its record shows updated_on_lane. Keep the report with the review: composition_hash is the hash of the lane composition it read, and report_sha256 covers the report's canonical text, "so a report is bound to the exact change it read." A later patch changes both. Then land the lane as one changeset.
Because the report only advises, enforcement is yours to add. One pattern, ours rather than the docs': on a protected trunk, name the governed code's glob in .landing-rules with the governing page's owner as an approver, and have that approver read the drift report first.
What the docs leave unanswered
- Who may write
.governed-seams. The docs make.landing-rulesadmin-only; for the seams page they say only that it is read from the trunk "whoever wrote it". - A view in the app. The docs describe the tool and its answer, not a page in the browser that shows the report.
- Markdown is "not parsed yet", so a page cannot itself be the governed side.