Contract Graph · Concept 02

Contracts

One durable, machine-readable promise for every owned software boundary—and one route to the next smaller piece of context.

One artifact per boundary

Contract Graph represents a repository as connected contracts. Every governed directory owns one canonical file:

<unit>/.agents/cg/contract.yaml

The repository root owns .agents/cg/contract.yaml. Parent, dependency, and routing edges live in that node rather than in companion maps. A human-readable Markdown view can be projected from the YAML, but it is not a second source of truth.

The contract is a durable promise for one owned software boundary. It explains what the unit owns, how its parent uses it, what crosses the boundary, where context continues, and what verifies a change.

The recursive model

repository → module → (submodule)*
           → component | library → implementation

Every node uses the same schema. Its kind expresses architectural scale without changing the meaning of the other fields. Depth is mixed and uncapped: one module may be a leaf while another continues through several smaller, self-sufficient boundaries.

Hierarchy is the primary route. Lateral dependency edges can connect siblings or shared libraries, but they do not confer ownership. Every contract must remain reachable from the repository root through composition edges.

What a contract records

FieldMeaning
id, name, kind, unitStable identity, architectural scale, and the directory this boundary owns.
summary, purposeWhat distinguishes the unit and how its parent uses it.
responsibilitiesWhat the boundary owns, permits, and explicitly forbids.
surfaceThe concrete entry points callers use and the promises they observe.
invariantsStable truths, linked to executable verification or explicit debt.
relationsParent, children, composition state, and lateral dependencies.
rulesRepository-owned product rules that bind this boundary; global structural rules apply automatically.
verificationThe smallest commands that prove named invariants.
routesTask phrases and the canonical contracts they select.
agentWhat an agent reads first and checks before changing the unit.

Unknown structured fields are rejected so misspellings cannot silently become unused data. Optional assumptions, exceptions, and namespaced extensions carry truth that does not belong in the core model.

Declared surfaces are concrete promises

Every non-repository boundary declares at least one surface. A surface names its stable identity, path, exported symbols when relevant, accepted inputs, returned results, observable failures, and guarantees.

“Public” here means public to the boundary's callers—not necessarily public on the internet. A surface may be a class, module of functions, HTTP resource, schema, command, or event. The form stays language-native.

The first structural pattern is a small service: named operations take parameters, do the work, and return a completed result. Construction, algorithms, mutable internals, persistence, framework types, and vendor types stay behind that call.

A new entry point or an internal bypass is a structural change. It cannot be hidden as a local implementation detail.

Composition has explicit state

Every node declares exactly one composition state:

  • leaf: the smallest owned boundary; it has no children.
  • composed: responsibility is decomposed into one or more child contracts.
  • unmapped: a root-only transition after brownfield initialization and before warmup discovers the real top-level boundaries.

Contract references are explicit repository-relative paths. Parent and child edges must be reciprocal, and a child must sit inside its parent's governed unit.

Invariants and verification are reciprocal

An invariant names the verification entries that prove it, and each verification entry names the invariants it covers. The verifier checks both directions.

An invariant without executable verification must carry explicit debt. This makes an acknowledged gap different from an accidentally empty field, without pretending that debt is enforcement.

A rule is enforced only when its detector exists, blocks, and has a test that proves it fails on demand.

Routing belongs to contracts

Routes live on the contract that has enough context to choose among its descendants. A route carries a stable ID, one or more task phrases, and one or more canonical contract paths.

The repository contract routes broad product language into top-level capabilities. A module can then route more specific language into its components. The CLI performs deterministic phrase matching rather than asking the model to invent the first edge.

cg contract route --task "refund failed after checkout"
cg contract context --id billing
cg contract children --id billing

What graph verification proves

cg verify rejects malformed contracts, duplicate identity or ownership, missing references, invalid hierarchy transitions, non-reciprocal edges, cycles, unreachable nodes, impossible composition states, missing surface paths, unknown rule IDs, broken invariant links, and permanent contracts that cite transient plans as authority.

These checks prove the authored graph is internally closed. They do not yet prove the implementation contains no undeclared child, that every named symbol is exported, or that imports obey every declared dependency. Those require language-specific correspondence detectors.

Public schemas

The canonical JSON Schemas are served from their stable sarada.io identities. Editors and validators can resolve them directly without depending on a repository checkout.

Browse all public schemas →