OpenProse

Contracts

Write requirements in Contract Markdown. Learn the five contract kinds and the sections that define inputs, maintained state, required steps, and limits.

Contracts

A contract states requirements and the context needed to interpret and apply them. Authors specify what the agent must accomplish, the conditions it must satisfy, and the choices it may make. Humans and agents can both author and reuse contracts.

This page describes the public skill's Contract Markdown format: *.prose.md files with YAML frontmatter and recognized ### sections. The five kinds support standing work, one-time calls, external inputs, tests, and reusable coordination. Contract authoring explains how to use these building blocks to express requirements together.

The sections declare requirements and interfaces. The selected host supplies tools and runtime behavior; see Harness-agnostic for that boundary and implementation limits.

Frontmatter and identity

A contract opens with YAML frontmatter. Two fields carry weight:

  • kind: names which of the five contract kinds this is (below). This is the one field that changes how the file is executed.
  • name: is the human-facing slug.

An optional id: gives a responsibility or gateway a source identity that survives name: and filename renames. Without it, the slug is the identity. The language repository's scripts/mint-contract-id.mjs tool mints the 26-character base32 value. The compiled node key identifies a particular mount; it is distinct from the optional source id:.

The five kinds

kind: selects one of five authored kinds. Each has a different run model.

KindRun modelPurpose
responsibilityServed (continuously reconciled)A mounted DAG node with requirements for state maintained over time.
functionCalled (one-shot)A stateless, ephemeral helper. Bind ### Parameters, run one render, return ### Returns. No Forme phase, no world-model.
gatewayMounted as external-drivenSugar for an external-driven responsibility. Compiles into a trigger registration for the serving host; refuses a direct run.
testVia the test pathFixtures plus natural-language assertions against a subject responsibility or function.
patternInstantiated at compile timeA reusable coordination algorithm, expanded into nodes at compile time. Never directly run.

There is no kind: service (it was renamed to function) and no kind: system (deleted). Cross-node composition is a Forme-wired subscription between responsibilities; intra-node composition is an imperative call inside one render. There is never an internally-autowired graph kind.

The rest of this page focuses on responsibility: its declared inputs, maintained state, and conditions for carrying out the work. Functions use the separate call interface described below.

The recognized sections

### Description is a summary for readers. ### Goal states the intended result. Use the recognized semantic sections for the requirements that guide execution.

The following sections describe a responsibility's subscriptions, maintained state, and wake source: ### Requires, ### Maintains, and ### Continuity. ### Invariants states limits that must hold during the work; ### Execution can specify required steps. Use the sections applicable to the contract.

### Maintains: the world-model schema (four jobs at once)

### Maintains is the schema for the state this node maintains. It does four jobs in one section:

  1. It types the maintained truth, the shape of the world-model the node owns.
  2. It carries the canonicalization spec: which fields are material and how they normalize. This compiles into the node's fingerprint, the cheap content identity the run phase compares.
  3. It declares facets (below), the named parts of the truth.
  4. It states postconditions that a render must satisfy before it may commit.

There is no separate judge and no ### Criteria section in this format. ### Maintains states postconditions: deterministic validators can check some, while semantic conditions rely on render self-attestation. The language requires a render that cannot satisfy its postconditions to leave prior state unchanged and report failure. Actual enforcement and receipt detail depend on the host; see implementation limits.

Facets make subscription structural

A #### sub-heading inside ### Maintains declares a facet, a named part of the truth. The facet's name is, at once, three things:

  • its fingerprint unit (the canonicalizer emits one token per facet, plus an always-on atomic token over the whole truth);
  • its subscription symbol (a consumer names it in ### Requires, and the reconciler wakes that consumer only when that facet's token moves: Requires.<facet> ↔ Maintains.<facet>);
  • and its region of the world-model.

With no named parts, the whole state is one atomic facet. Named facets reuse the heading hierarchy and the Requires↔Maintains connection. The parts you define in ### Maintains determine what downstream nodes can subscribe to.

### Requires: what the node subscribes to

### Requires names the upstream facets this node consumes. Forme matches each entry to a producer's ### Maintains facet and draws the subscription edge. ### Requires is the input side of the memo key: the run phase fingerprints the node's contract together with its subscribed inputs, and re-renders only when one of them moves.

### Continuity: the wake source

### Continuity declares when, beyond a subscribed input changing, a node should re-render. It is not a schedule. A node is input-driven by default (it wakes when a subscribed facet moves). ### Continuity adds one of:

  • a self-driven cadence, for truth that goes stale on its own. A valid_until freshness state lives in the world-model as data; ### Continuity carries only the policy that reads it on a forecast cadence. When a valid_until lapses, the harness mechanically moves the facet's fingerprint and wakes the node. No model call decides that time has passed.
  • external-driven, which marks a kind: gateway so an ingress event wakes it.

The author states the requirements in these sections. A serving host provides fingerprinting, cadence, receipts, and subscription processing. Its supported wake sources determine when it attempts the work.

Functions: the call interface

A kind: function does not maintain a world-model and is not part of the DAG. It declares a plain call interface instead of the four-jobs schema:

  • ### Parameters: the inputs bound at call time.
  • ### Returns: the return value of its single render.

A lone function has no Forme phase: bind parameters, spawn one render, return ### Returns. It is the stateless, ephemeral helper.

A contract in full

The following retained source snapshots illustrate how a responsibility and its gateway connect. They predate the current section cleanup and are shown verbatim; ### Continuity recheck in the gateway is an older heading. For current runnable source, use the skill 0.18.0 basic-unit-suite.

Read the responsibility top to bottom: the > description states intent for a human, ### Requires names the single facet it subscribes to, ### Maintains types the CountSummary truth and declares one #### structured facet with an explicit postcondition, and ### Continuity declares it input-driven, so it wakes only when its counts input moves.

count-summary.prose.md
---
name: count-summary
kind: responsibility
---

# Count Summary

> The single responsibility that turns the gateway's `counts` facet into a
> threshold-aware summary (U02). It reads its prior world-model by reference,
> writes a new `CountSummary`, and signs a receipt naming the upstream receipt it
> consumed. It skips when `counts` has not moved (U03).

### Requires

- `counts`: the numeric tallies. *(Maintained by `counter-events.counts`.)*

This is the only subscribed input. `count-summary` is **input-driven**: it wakes
iff the `counts` facet fingerprint moves. A metadata-only event moves only
`raw_events`, so this node stays dark while `Raw Event Auditor` wakes (U05).

### Maintains

The `CountSummary` world-model — the structured summary the alerting chain reads.

- `total` — the material event count.
- `by_kind` — the per-kind tallies.
- `threshold_crossed` — whether `total` reached the alert threshold.
- `explanation` — a short rationale string.

#### structured

The whole summary is material: any change to `total`, `by_kind`, or
`threshold_crossed` moves this node's truth and propagates to `Alert State`.

**Postcondition:** `total` equals the count of accepted material events;
`threshold_crossed` is true iff `total ≥ threshold`. Self-policed before signing —
no separate judge beat.

### Execution

Read the `counts` facet and the prior summary by reference, fold the per-kind
totals, set `threshold_crossed`, and commit the structured summary.

### Continuity

input-driven

And here is the gateway that feeds it. A gateway has no ### Requires (its input arrives from outside the graph). Notice how ### Maintains splits the ledger into two #### facets, counts and raw_events, so a metadata-only event moves raw_events (waking the auditor) without moving counts (the summary above stays dark). That split is the subscription wiring.

counter-events.prose.md
---
name: counter-events
kind: gateway
---

# Counter Events

> The gateway — the system's ingress. It has no `### Requires` (its input arrives
> from outside the graph), it `### Maintains` the canonical `CounterEventLedger`,
> and its `### Continuity` is **external-driven**, which is how Forme registers it
> as the single DAG entry point (U11).

### Continuity

external-driven

A webhook, a poll, or a manual kick becomes one external wake at the system's
edge. The gateway folds each accepted counter event into the canonical ledger and
projects two **independent facets** so a downstream subscriber wakes only on the
slice it actually depends on (U05). Replaying the same event id is a no-op — the
ledger dedups by id, so a re-delivery produces a byte-identical world-model and
the gateway memo-skips (U01/U03).

### Receives

- A counter event: `{ id, kind, value, material? }`. An event with
  `material: false` is **accepted into the audit trail but excluded from the
  tallies** — it is the metadata-only event that moves `raw_events` without moving
  `counts`.

### Maintains

The `CounterEventLedger` — the standing truth every downstream responsibility
subscribes to. Its canonicalization splits the truth into the two facets below, so
a change to one slice never spuriously wakes a subscriber of the other.

- `high_water_mark` — the running material event total.
- `counts_by_kind` — the per-kind material tallies.
- `accepted_event_ids` — the full accepted id set (material and metadata-only).
- `last_seen_at` — an immaterial monotone marker (it never appears in a facet, so
  it cannot wake a subscriber on its own).

#### counts

The numeric tallies (`high_water_mark`, `counts_by_kind`) over **material events
only**. Moves when a material event is accepted; does NOT move on a metadata-only
event. `Count Summary` and `Count Trend` subscribe here.

#### raw_events

The accepted-event id set plus duplicate / malformed flags. Moves whenever the
accepted set changes — including a metadata-only event. `Raw Event Auditor`
subscribes here.

### Emits

- count-summary
- raw-event-auditor
- count-trend

Forme keys the wake on the producing node; the subscribers above resolve their
edges to this gateway's `counts` / `raw_events` facets.

### Continuity recheck

A weekday 09:00 self-kick may re-scan even when no webhook fires; a byte-identical
re-scan memo-skips, so the self-kick costs nothing when nothing changed.

These examples combine a gateway's published inputs with a responsibility's requirements for a summary. The declared interfaces make the composition inspectable. Evidence and checks still determine whether a particular result satisfies those requirements.

Where to go next

For the full language semantics, the authoritative source is the OpenProse spec (01-Language.md) and the loaded open-prose SKILL. If the docs and the skill ever disagree, trust the skill.

On this page