Imported from mgtf/atoma (
src/contracts/AGENTS.md). Install upstream withnpx skills add mgtf/atoma --skill contracts. Copyright stays with the author.
Contracts — AGENTS.md
src/contracts/ owns the shared runtime shapes: one schema per shape,
inferred types, and the merge semantics readers and writers agree on.
Read AGENTS.md first: it holds the cross-cutting rules.
Everything below is stated once, here, and is not repeated at the root.
Define a schema once and import it everywhere.
Neighbours:
src/tools— the writers bound by these merge rulessrc/platform— the closed event-kind vocabularysrc/atoms— the plan and verdict shapes
Schemas and examples
- Contract examples are parsed at module load. A schema/example mismatch must fail tests immediately.
Probe manifests
- Probe manifests are structured records. Normalize paths before recognizing
.atoma-probes.json; machine writers merge entries, and model hand-edits are refused. - Manifest MERGE semantics have one definition:
src/contracts/probeManifest.tsowns entry identity per shape (shell bycmd, web byfile+smoke, http = ordered append) and documents the three writers' corrupt-input policies side by side. Never re-implement a merge in a tool. - The browser-probe discriminant has ONE taught literal
(
WEB_PROBE_DISCRIMINANT), and both the manifest writer block and the web canonical prompt'soutput.probesexample are generated from it. Aliases (REPORTED_WEB_PROBE_ALIASES) are READER tolerance for recipes distilled before a rename; never teach one, and never widen the on-disk checker to accept one — a compiled script dispatches on that discriminator. probeManifest.tsalso hosts the taught two-callvalidate_htmlshape (SMOKE_TWO_CALL_SHAPE, rendered asSMOKE_TWO_CALL_LINES) for the same reason it hostsEXAMPLE_WEB_ENTRY: one constant, rendered by two layers that may not import each other (the tool's refusal and the shared smoke guidance). It is the executed-interactions counterpart ofestablishesDomInteraction; its second call changes state once before the reset because a reset on a fresh page proves nothing. Generic vocabulary only — control, milestone, reset — never one widget's names.
Proof attestation
src/contracts/attestation.tsowns the typed tool observation, the attestation record, and the obligation vocabulary. An observation is only ever OBSERVED: no model-authored payload may enter that module, and the only writer is the runtime seam that saw the raw tool result.requestedInteractionsandexecutedInteractionsare SEPARATE fields on purpose. Reporting one side is what letok: truewith an empty interaction log read as proof that clicking worked.- The obligation vocabulary is CLOSED and has one member. Adding a second is a design review with its own evidence, not a schema edit.
- A
validate_htmlPRE-FLIGHT refusal is a statement about the request, not an observation of the artefact: no page opened, no document bound. Its error strings carry one of TWO prefixes —SMOKE_PREFLIGHT_REFUSAL_PREFIXfor the smoke guards,PROBE_URL_REFUSAL_PREFIXfor a portless loopback URL (2026-09-21: a bound-origin mismatch read as a dead service replayed a run into its deadline) — andisPreflightRefusalis the one predicate over both; the tools write them, the L1 validation ledger reads the predicate. Never grep the literals. Witnessdeclares its OBSERVER. Never relabel a model-declared witness as transport-observed, and never fold transport witnesses into the recorded-probe rendering — they are references, and they carry nocmd.
Reading a trace without holding it
src/contracts/traceFields.tsowns the ONE projecting reader over a run trace:readTraceTopLevelFieldsenumerates the document's DEPTH-1 members in bytes and returns only what its caller named — VALUES for members whose content is needed, SHAPES for members whose presence and JSON type are. It lives here, not insrc/viz, becausesrc/viz/server.tsimports foursrc/projectsmodules and a value edge back would close a subsystem cycle; it is allowed here for the same reasonrunStats.tsholds its own parser, and because no model-authored payload ever enters it.llmTrace.tsCITES model-visible context, it does not copy it:citeContextrecords a block's source, its truecharsand a preview capped atCONTEXT_PREVIEW_CHARS, and the same id is cited on thellmevent. The cap is 2,000 — raised from 160 because the vizcontextstep exists so a viewer can read what the model was shown, and 160 cut a 1,167-character recipe mid-sentence (2026-09-21). It stays a CAP: a longer block is still truncated with an ellipsis, and one event is recorded per distinct block per run, so a trace grows with a run's injects rather than with its calls.- A trace's SIZE is a function of how much work the run did (~19KB per tool
call, measured). Never bound it with a constant: a 512KB cap recorded
delivered run
2857a579asfailed. Bound the PROJECTION instead — the coordinator's spec captures under 400 bytes from a trace of any size. resultanderrorare the members a MODEL wrote, and they are read as SHAPES ONLY.result.outputis typedunknownand capped nowhere, so any reader that captured it would rebuild the same erasure at a larger threshold.- The reader is order- and whitespace-agnostic, so archived traces stay
readable and no caller may depend on member order or indentation. It is
FAIL-CLOSED: a member is reported absent only after the scan reaches the
closing brace and then EOF, which is what rules out a head+tail byte window —
that window cannot tell "the member is not there" from "my window was too
small", and a missing
errorread as "no error" would publish a failed run. - Validation is DEPTH-1 ONLY. Inside a skipped container the scan tracks
strings and nesting but does not check bracket matching or primitive grammar,
so a document malformed only below depth 1 is accepted where
JSON.parsewould refuse. Unreachable fromTraceRecorder, which emits oneJSON.stringifyper persist, and the projected members are still exact. - ONE ceiling (
MAX_TRACE_BYTES, 32 MiB), FOUR dispositions above it, stated here once: the coordinator fails HARD, because it is deciding whether work was delivered; the sentinel fails SOFT (readBoundedJsonreturns null — no watch is better than a stall);summarizeTraceFilefails soft by skipping the row;/api/runs/:idREFUSES with a status, because a reader asking for one named trace is owed an answer and a skipped row is not one (src/viz). The ceiling is re-exported bysrc/sentinel/sources.ts; it is not redefined there. - No refusal message carries a filesystem path.
project_runs.erroris served to tenants, and the row this reader replaced leaked an absolute host path.
Model selectors and who paid for a run
modelSelector.tsis the ONE grammar for a model choice, everywhere:<api|sub|own>:<vendor>:<model>, closed mode and vendor vocabularies, the third segment verbatim (Ollama tags keep their colons).parseModelSelectoris the only parser,transportOfthe only mode+vendor → transport mapping, andreadTierSelectorsthe only reader of the three REQUIREDATOMA_MODEL_L*pins — there is no default, and no other module may spell, split or default a selector. Stored pins written before this grammar (2026-09-07) are not recognised; the store is reset, not migrated.runPayers.tsis the ONE answer to who paid, and it is PER TIER: three rows,l1,l2,l3, each naming the resolved selector, the transport that served it (transportOf), the payer kind and the chain level it came from. There is nobaserow any more because there is no base transport: every call carries its full selector, so nothing is paid by an account the ledger does not name.- THE PAYER IS THE SELECTOR'S FIRST SEGMENT (
payerForSelector):sub:ishost-subscription,own:isprincipal-subscription,api:isorg-keywhen the organisation brought the vendor's key, elsehost-key, orhost-selfhostedfor Ollama. Nothing infers a payer from a transport name. - Subscription selectors are ADMISSIBLE BY CHAIN LEVEL, not by spelling: the
coordinator honours
sub:/own:from an account pin after re-asking the authority, and refuses them from the org and host levels; both ChatGPT families admit all three tiers through Atoma's host-side tool loop. - Nothing here carries a secret: a payer names a KIND and a transport. This
detail is journaled beside
project_runs.error, which is served to tenants. - Summary helpers distinguish host and requester subscription spend; both use
the same structured
runPayerDetailledger.
Publication receipts
-
An artifact manifest with
source: workspacerecords the complete filtered workspace inventory. Absence of this optional field retains the legacy explicit-file meaning and its exact hash. Revalidation follows the recorded coverage; it never upgrades historical evidence implicitly. -
baseShaon a publication is OBSERVED, never a pointer anything decides from — the same ruleattestation.tsstates for a tool observation. It records the publication parent (the captured run base for imported projects); the authority to publish onto an existing branch is read from GitHub at publish time. A required KEY with a nullable VALUE on a.strict()object, so a writer must state what it built on rather than omitting it. -
commitShaSchemais the ONE definition of a 40-hex commit sha, imported by both the receipt and the row. It was written twice.
Trajectory signatures
src/contracts/trajectory.tsowns the signature, key and score shapes AND the pure derivation over trace events, for the reasontraceFields.tslives here: two subsystems read it — the sentinel's rule table and the analyst's digest — and neither may import the other. It reads runtime-stamped identities only (element names, actor names, skill ids, event and branch ids) and neverargs,resultor prose; its event type is structural so everyVizEventsatisfies it without asrc/vizimport.- ONE EXECUTION IS ONE
llmEventId. It is CLOSED by thellmevent carrying that id, whichRecordingLlmClientrecords only when the call returns, so array order is causal and a signature without it is a prefix. It is CREDITED by the nextskill.success(naming its skill, when it had one) ortrustRESULT for its Molecule in an agreeing lane, before that Molecule's next execution — so a remediation retry leaves its first attempt uncredited. Lanes NEST (measured 2026-09-09 on the real traces): the Cell injects, credits and trusts in its OWN lane and the Molecule executes in a child lane the Cell opens, so an event agrees with an execution when their lanes are equal or one is an ancestor of the other, and a lane-less event agrees with any lane. One credit credits the latest attempt in a lane and closes the older ones there, so the trust-RESULT-beside-skill-success pair cannot credit a retry's failed first attempt; siblings in other lanes keep waiting. - A reference holds completed AND credited signatures only, newest
TRAJECTORY_REFERENCE_MAX_PER_KEYper key. Assemble it oldest-first.