Agent docs

Contract do-nots

The banned moves, in one place.

Every canon "Do not" and every contract "Banned" line in one place, each cited back to its source doc, so a builder who never opens the source doc still meets the rule. Same idea as versable-builder/docs/DO-NOTS.md.

Generated by scripts/build-do-nots.py on 2026-08-23 from the Do-nots section of every canon/*.md, patterns/*.md, v6/README.md, and the Banned section of every contracts/*.md. Do not hand-edit; edit the source and regenerate.

From canon/#

The runner and the payload#

  • Do not put a runner behaviour (checkpoint, heartbeat, backoff, cancel, metering, finalization) inside a payload, however local it feels. Add it to the runner's verb set and call it. (speedway partType.server.ts:114, normalize.server.ts:440, content.server.ts:628) (canon/01-runner-and-payload.md)
  • Do not answer the same lifecycle question twice inside the runner either. A second machine beside the first means the verb set is incomplete, and the cost is that "how does this get retried" has two answers. (walmart jobs.py:636-771, beside orchestrator.py) (canon/01-runner-and-payload.md)
  • Do not let the runner name a domain field, even to avoid a payload-to- payload import. Give the payloads a shared package instead. (walmart orchestrator.py:78,90) (canon/01-runner-and-payload.md)
  • Do not read the four divergent runner files in versable-runner as extension points. They are version skew, and the fork is not evidence about what varies between capabilities. (../evidence/20260817-runner-four-file-diff.md) (canon/01-runner-and-payload.md)

Identity and tenancy#

  • Do not issue one credential for all callers. (versable-runner app/auth.py:32-45) (canon/02-identity-and-tenancy.md)
  • Do not treat a self-declared tag as identity or tenancy. Store it as attribution and label it claimed. (versable-runner meta) (canon/02-identity-and-tenancy.md)
  • Do not put a static shared secret on an internal callback that is reachable from a public URL. (speedway app/routes/tasks/module.tsx:4-9) (canon/02-identity-and-tenancy.md)
  • Do not reuse the caller's API key as the callback signing key. The issuer hands out a separate per-caller callback secret, so authentication and signature verification rotate independently and holding the API key does not let you forge a callback. (the extractor signs with config.extractorApiKey, speedway/app/lib/extractor.server.ts:8-9,252) (canon/02-identity-and-tenancy.md)
  • Do not let a module verify users, sessions, or passwords. That is the app's job. (speedway's session auth is correct for an app and would be wrong in a module) (canon/02-identity-and-tenancy.md)
  • Do not let one environment's identity be valid in another. (runner-service-dev runs as runner-service@) (canon/02-identity-and-tenancy.md)
  • Do not create service-account keys to let a non-GCP caller in; use the issuer. (estate rule, CLAUDE.md) (canon/02-identity-and-tenancy.md)
  • Do not skip tenant on any request, job, outcome, usage event, or log line. (canon/02-identity-and-tenancy.md)
  • Do not accept a credential in a query string. It lands in access logs, browser history, and referrer headers. Header only. (the extractor webserver, automation/router.py:35, request.query_params.get("key")) (canon/02-identity-and-tenancy.md)

Jobs and state#

  • Do not report running for a job that has not been expanded yet. Report accepted or expanding and let the caller wait. (canon/03-jobs-and-state.md)
  • Do not leave a terminal state. Resolution and retry are new jobs with a parent_job_id. (canon/03-jobs-and-state.md)
  • Do not write a retryable failure as an outcome. Only the terminal attempt is an error. (canon/03-jobs-and-state.md)
  • Do not expose an unpaginated list. (canon/03-jobs-and-state.md)
  • Do not require the caller to poll. Offer a callback and document the sweep. (extractor, per owner; speedway had to build around it) (canon/03-jobs-and-state.md)
  • Do not accept a job without a tenant, and do not let a caller's meta or attribution stand in for one. (versable-runner) (canon/03-jobs-and-state.md)
  • Do not let a job be deleted or mutated while it is running. (walmart-mvp routes/jobs.py:215-216, the commented-out guard) (canon/03-jobs-and-state.md)
  • Do not put "stage" on the module surface. A stage is the app's composition over capabilities and child jobs; the module gives capability and parent_job_id and the app reconstructs the stage. (vb-fable's shape check against both shipped jobs tables, 2026-08-18) (canon/03-jobs-and-state.md)
  • Do not let a read mutate. A GET on outcomes is idempotent and safe to poll; "first pull wins" belongs on an explicit acknowledge call, never on a read. (the extractor's /jobs/{job_id}/results marks the job consumed on first pull, speedway/app/lib/extractor.server.ts:11-12) (canon/03-jobs-and-state.md)

Dispatch and workers#

Storage and persistence#

Caching#

  • Do not put a tenant's data in a cross-tenant cache key, and do not leave the tenant out of a key when the value carries tenant data. (canon/06-caching.md)
  • Do not cache without the capability version and reference-data versions in the key. A stale hit is a wrong answer. (canon/06-caching.md)
  • Do not serve a cached outcome without marking it cached. (canon/06-caching.md)
  • Do not let a payload open a cache client. The runner provides the verb. (canon/06-caching.md)
  • Do not treat Redis as durable storage. (canon/06-caching.md)
  • Do not ship a cache without a TTL the store enforces. (canon/06-caching.md)
  • Do not report a cache hit as a bare boolean. Carry the block, including on a miss. (canon/06-caching.md)
  • Do not omit the key's version inputs from what the consumer sees. A hit nobody can explain is a hit nobody can trust. (canon/06-caching.md)

Observability#

Usage and credits#

Configuration and secrets#

Human in the loop#

The capability manifest#

Deployment and environments#

Local development and debugging#

Graceful degradation, variants, and several versions at once#

Outputs and transforms#

From contracts/#

Contract: per-module caller keys (option C)#

Contract: the capability manifest and the field registry#

  • A capability id that is not <domain>.<verb>[.<qualifier>]. (contracts/manifest.md)
  • A provides or requires entry that is not a registry id. (contracts/manifest.md)
  • A provided field whose value sits anywhere but at its id's path in output, or a required field read from anywhere but its id's path in items[].input. (contracts/manifest.md)
  • An x. registry id in requires. (contracts/manifest.md)
  • A meters list that repeats a standard meter. (contracts/manifest.md)
  • A skipped outcome whose reason is outside duplicate, filtered, cancelled, superseded. (contracts/manifest.md)
  • An error_type or review_reason emitted at runtime and absent here. (contracts/manifest.md)
  • A settings key honoured at runtime and absent here. (contracts/manifest.md)
  • A manifest at 0.2 or later that omits ceilings, cost_model, or retention; at 0.1 a capability may omit review_reasons, confidence, ceilings, settings, cost_model and log and its instance doc says which, so no invented number enters a machine-readable file (review v2 J4). (contracts/manifest.md)
  • Two capabilities in one module with the same id and different schemas; that is a version bump or a new id. (contracts/manifest.md)

Contract: the module surface#

Contract: the runner's verbs#

Contract: the usage event#

From patterns/#

Building a module#

Consuming a module from an app#

Deploying a module#

The identity recipe#

Authoring an agentic module#

From v6/#

Workflow Console V6, mapped onto the contract#

  • Do not put a customer's bar, Goals, or per-tenant config inside a module. (v6/README.md)
  • Do not forward a user's session or JWT to a module. Exchange the console's own client credential for a token. (v6/README.md)
  • Do not let the console be the only place a module can be called from. Every module the console uses is callable standalone with the same surface; that is the test that the boundary held. (v6/README.md)
  • Do not build the composer before a second workflow shape is actually needed. Build the manifest so it is possible. (v6/README.md)

180 lines gathered.

@versable-git/ui · reference, canon, and method, read in place