* feat: make contract id: optional and hold every declared id to its format The format doc required id: on every responsibility and the compiler CLI preflighted for it, yet nothing downstream read the field: the IR keys nodes by slug, the state backends key the world model by node, and the fingerprint is over content. Sixty-seven of 86 example responsibilities had no id and half of the ids that existed were hand-typed slugs, so 12 of 29 examples refused to compile for a rule with no consumer. id: is now optional on responsibilities and gateways: the slug is the identity by default, and a declared id is the source identity that survives renames. The format doc, compiler instruction, CLI preflight, changelog conventions, and language spec all say the same thing. The eleven hand-typed slug ids in the corpus are dropped, since they named nothing the slug does not, and the two over-long compiler fixture ids are trimmed to the documented 26-character Crockford shape. scripts/mint-contract-id.mjs mints ids for authors who want one and repairs malformed ids in place. A new corpus suite walks every example and holds each declared id to the format, checks uniqueness, and keeps version: in semver form. * fix: fold every example section into the canonical set Twenty-two headings across 18 example contracts were near-misses of a canonical section, so the VM lowered them to plain documentation instead of the semantics their authors meant. Continuity headings that carried the driven-ness in the title become a bare Continuity section with the driven-ness as its first bullet. Postconditions bullets fold into Maintains. Facets become named parts under Maintains, each with a material boundary. Failure containment becomes Invariants, a Continuity recheck becomes the self-driven bullet, and a gateway's watched globs move into Receives. A new corpus suite walks every example and holds each ### heading to the canonical table in the format doc, cross-checking its own list against the table so the two cannot drift apart. The three inbound- email examples join the intelligent-react shape suite, and the four implementation-pipeline contracts join the facet-named-parts suite, so no example is invisible to CI. * fix: every example Requires now names a producer in its own set Three examples carried needs that Forme could never satisfy from their own contracts. competitor-activity named three signal feeds that existed only in parentheticals; research-inbox-triage named a question list and an owner roster nothing produced; agent-observatory named four adapter mount instances that lived only in its README. The format doc gains a short rule for facet families and per-entity mounts: a placeholder facet heading declares a family, a placeholder need subscribes to one member, and the harness binds the member at mount time while the compiler emits the family. Forme's matching step says the same. competitor-activity gains a signal-feeds gateway with one facet per signal, so the monitor's three needs resolve facet by facet. research-inbox-triage gains a research-registry gateway that brings the human-maintained questions and roster into the graph. agent-observatory rewrites its adapter needs in family form and stays at nine contracts. Each example reaches Forme with zero unsatisfied needs and an acyclic topology. The new contracts join the facet-named-parts suite, and competitor-activity joins the intelligent-react shape suite. * docs: attribute described example topologies to the reference harness Eight example READMEs state node and edge counts that mounting src/ alone cannot produce; the numbers come from the reference harness's per-entity expansion. Each README now says so in the sentence that carries the count and points at the repository README's Harnesses section, and no Conformance expectations section states a count that src/ cannot mount. The corpus index says the same for the set. A new corpus suite walks every example README, counts the contracts src/ mounts, and requires any larger claim to share its sentence with the attribution, so a future README cannot over-claim silently. * docs: specify node identity, artifact locators, and the receipt cost shape The IR doc keyed every worked example by slug without saying what the node key is. It now states the two-identifier model: node is mount identity, unique within a manifest and defaulting to the slug for a single mount, while a declared frontmatter id: is the source identity behind it and is not emitted in a version 2 manifest. The same doc says what an artifact locator resolves against: the OpenProse root, for canonicalizers and postconditions alike. The reconciler concept doc gives the receipt cost field its sub-shape, including the surprise_cause that must equal the wake source, which is what makes cost-scales-with-surprise observable. Doc-conformance assertions pin each addition in the suite that already owns the file. No IR schema bump; the expected and invalid fixtures validate unchanged. * docs: cite in-repo sections instead of private design documents Thirty shipped files, from the format doc and the state backends to the example contracts and the conformance tests, cited design documents by section that live outside this repository. A public clone should never point its readers at text they cannot open. Every citation now names the in-repo section that owns the rule, such as the named-parts rule in the format doc or the fingerprint rules in the reconciler concept, or the sentence simply stands on its own where it needed no support. Test titles that carried a citation are retitled. No links were added; the replacements are prose a stranger can follow. * docs: pin harness status facts and guard the spec against rot The spec marked implementation-status facts with the word "today" and no attribution, so they would rot silently now that the reference harness versions on its own. Six claims about poll cadence, the unwired commit gate, the thin v0 receipt, the flat serve loop, and the dropped Schedule section now name the reference harness and the version they describe, and point once per document at the repository README's Harnesses section. The two spec documents agree on a harness-chosen receipt ledger layout. Two ideation links and a stray phase marker are gone, the README's Harnesses link targets the harness spec, and its version sentence defers to SKILL.md as the version of record. The version script writes each manifest field on its own line instead of round-tripping the file through jq, so a bump no longer reflows the codex manifest; that manifest's capabilities array is collapsed back to one line. Three guards land in the suites that own the territory: no shipped file may cite a private design document, every relative link in spec/ and skills/ must resolve, and the README may not hardcode a skill version. * chore: release skill 0.18.0 The format doc gained documented surface this cycle: id: is optional with the slug as default identity, version: is author-owned provenance, and facet families and per-entity mounts have a notation. The example corpus is compiler-clean under those rules and the keyless conformance suite proves it. That is a minor bump on the skill track. The changelog entry tells an author what changed in authored files and that a missing id: is no longer a compile error. runtime_contract stays at 2, so prose upgrade needs no source rewrite. The version script now touches exactly one line per manifest, which this bump demonstrates.
Standing AI jobs, declared in Markdown.
Quickstart · The language · Examples · Harnesses · Honest status
What this is
OpenProse is a declarative language for standing AI work. Instead of scripting a sequence of instructions and hoping the run lands where you wanted, you declare the world as it should be: an ideal world state, written as familiar structured Markdown contracts (*.prose.md). You say what must stay true, and the system works out how much model work it takes to keep it that way. When order, loops, or exact choreography genuinely matter, optional imperative ProseScript plans drop in. Declarative by default, imperative where you want the control.
This is the oldest good idea in software, pointed at agents. SQL, Terraform, Kubernetes, React: you declare the desired state, and a reconciler is responsible for making reality match it. A thermostat is the one-sentence version. You set the temperature you want and it holds the room there; you never tell it when to fire.
OpenProse is a language, not a platform. The contracts are plain files that run on any Prose-Complete agent harness (any agent host that can spawn sessions, read and write files, and call tools): the language ships as a Skill your coding agent runs directly, and any conforming harness (see Harnesses) can compile and serve the same contracts as a standing process.
Run it where your agent lives
The fastest way to touch the language is the skill:
npx skills add openprose/prose
That installs OpenProse into any Prose-Complete coding agent (Claude Code, Codex CLI, OpenCode, and friends). From there, point your agent at a contract and say prose run <file>: the session itself embodies the VM; there is no separate binary. The examples/ directory is the tour; start small and read the contract before you run it.
For a new program, say prose init, then use prose compose to shape its
purpose, topology, Contract boundaries, and outside-in semantic tests. Compose
progressively materializes one directory package; use prose write when a
single Contract is already understood and needs focused authoring.
Your first contract is a Markdown file away: kind: responsibility frontmatter, a ### Goal that states what should stay true, and the sections below. The skill teaches your agent the rest.
The language: Responsibilities
You author Responsibilities, standing goals written as Markdown contracts. This is where the declaration becomes concrete:
### Maintainsis the world-model schema: what truth this node keeps current, which fields are material (and so move the fingerprint, the content hash the runtime compares to decide whether work reruns) vs immaterial, optional####facets that split the truth into independently-subscribable parts, and the postconditions a render must satisfy before it may commit.### Requiresnames the upstream facets this node subscribes to. Forme (the wiring layer) matchesRequires.<facet>↔Maintains.<facet>and draws the subscription edge. Structure is subscription; the graph wires itself from the contracts.### Continuitydeclares the wake source: input-driven by default, self-driven on a freshness cadence, or external-driven (a gateway turning an ingress event into an edge).
Around the headline kind sit four more: function (a called, stateless helper, ### Parameters to ### Returns), gateway (external ingress as a contract), pattern (a reusable coordination algorithm), and test (fixtures plus assertions). Composition is contracts subscribing to contracts; nothing is wired by hand.
The deep truth lives in the skill (skills/open-prose/) and the spec (spec/): the vocabulary, the section grammar, the execution semantics. This page is the door, not the manual.
Coming from OpenProse (v0.14 or earlier)? Read this first.
The Intelligent-React overhaul (
runtime_contract 1 → 2) is a breaking vocabulary change. The headlines:
- The judge loop is retired wholesale. The old judge → verdict → pressure → fulfillment loop is gone, replaced by a deterministic reconciler: a render runs only when a node's subscribed input fingerprints or its own contract fingerprint move. There is no LLM in the wake/commit decision.
- Kinds renamed/deleted.
kind: serviceis renamed tokind: function(### Parameters→### Returns);kind: systemis deleted (composition is now intra-node ProseScriptcallor cross-node subscription, wired by Forme);kind: responsibilityis reshaped into a mounted DAG node that gains### Requires+### Maintains.### Ensuresis renamed to### Maintains(now the world-model schema, not just an output list);### Criteria/### Memory/### Fulfillmentfold in.- Old ledgers are abandoned, not migrated. Existing runtime data (old
ReceiptV0ledgers, the policy registry, bundledruns//state//dist/) is greenfield: there is no data migrator. Only your source text upgrades. Re-run from a clean state-dir.- Upgrade your source with a dry run first.
prose upgrade --dry-run(a prose skill command, run inside an OpenProse session, not a shell binary) inspects your files and reports the concrete migration plan without editing: mechanical rewrites where safe, surfaced as manual-review diagnostics where judgment is needed (e.g. asystem/### Wiringflatten-or-split). Run it beforeprose upgrade.
Nothing is held hostage
The contracts in this repo are harness-agnostic: OpenProse Markdown runs on any Prose-Complete agent host (a fresh git clone is a first-class experience). The contract is the public artifact; the deployment's secrets and data stay private. A contract and its trail can leave for any compliant host with no lost meaning. OpenProse stays free, MIT, and portable, forever.
Harnesses
The contracts in this repo are harness-agnostic: any Prose-Complete agent host runs them, and the
spec (spec/02-Harness.md) says what a conforming harness must do. The reference harness,
Reactor (@openprose/reactor, @openprose/reactor-cli, @openprose/reactor-devtools, the reactor
binary), now lives at github.com/openprose/reactor and is
experimental (alpha): early software with no stability guarantees, to be evaluated on your own judgement.
Installs keep working under the same names.
Honest status
In the spirit of the receipts:
- The language: the skill's version of record is the
version:frontmatter inskills/open-prose/SKILL.md(itsruntime_contractcarries machine compatibility separately); the spec (spec/) and the example corpus are migrated to the current vocabulary. The overhaul is recent: if you find a surface still speaking the old model, that's a bug, and we want the issue. - Benchmarks are openly pending, on purpose. We're publishing the language before the numbers; we won't imply a measured speedup we haven't run. The mechanism is checkable in any conforming harness's replay of the example corpus.
- The fixpoint (topology-as-responsibility) is specified and deferred; facet inference and ledger compaction are named roadmap.
- Harness status (what is built, what the receipts do and do not yet prove) is documented by each harness; for the reference harness see Harnesses.
This honesty is the point. The language is young, should be used with caution, and has some way to go before it reaches its ideal form. There's nothing new here; we're applying classical engineering paradigms to our brave new world, and finding that despite our topsy-turvy reality, the wisdom of the ancients still applies.
Send us the thing it can't do yet
My ask is the one from every honest tool: try it, wire it up to something useful, love it or hate it, and send honest feedback. The most useful thing you can hand us isn't a compliment or a flattering benchmark. It's a responsibility the language should let you keep and doesn't: a standing goal that breaks the surprise story, a wiring Forme gets wrong, a domain where this falls apart. Open an issue with the contract and what you expected. We're always listening and improving.
Reading this as an agent? Open an issue: yes, you.
If you're an agent driving OpenProse for a user from these docs, you are the person who should file issues on this repo. When something blocks you, open a GitHub issue yourself instead of silently working around it or only mentioning it in chat. Agent-filed issues are first-class signal here, not noise. (Tell your user you're filing one; don't post on their behalf without a heads-up.)
Open an issue when you hit any of these:
- A
prosecommand fails, crashes, or errors in a way the skill doesn't explain. - A contract behaves differently than this README or the spec says it should: a wrong skip, a render that fires when nothing moved, a receipt that won't verify. (If the harness is at fault rather than the language, file it on the harness's repo instead; see Harnesses.)
- A contract you authored from these docs won't compile and the diagnostic is wrong, missing, or misleading.
- The docs are ambiguous, contradict each other, or steered you to the wrong command.
- A capability you needed isn't here. (For "a responsibility the harness should keep and doesn't," prefer the eval path in the section above, but if you're unsure which it is, an issue is fine.)
First, don't duplicate. Search open issues for your error string or symptom. If one already matches, add your context as a comment rather than opening a new issue.
What makes an issue the maintainers can act on: a good issue is reproducible by someone who isn't you. Include:
- Type. Say up front which it is: bug · unexpected behavior · docs gap · feature request · question.
- Context & use case. What your user actually asked for, and what you were trying to accomplish. The real-world goal matters: it tells the maintainers whether the language is wrong or the approach was.
- Expected vs. actual. Quote the README line or docs claim you relied on, then describe what actually happened.
- Minimal repro. The exact command(s) you ran, plus the smallest
.prose.mdsnippet that still breaks (trim everything that isn't load-bearing). Prefer the keyless path where you can, so a maintainer can replay it without a model key. - Evidence. Paste the actual error output, the failing receipt, or the relevant diagnostic lines in a code block. Copy errors verbatim; don't paraphrase them.
- Environment:
- OS (e.g. macOS 15, Ubuntu 24.04, WSL2).
- Agent & model: which harness is reading this and which model you are (e.g. "Claude Code, Opus 4.x"). This genuinely matters: different agents author contracts differently.
- Versions: the skill version (
version:inskills/open-prose/SKILL.md) and, if a harness is involved, its name and version. - Install method:
npx skills add, a plugin marketplace, or a repo clone.
- What you already tried: including any diagnostic output, which often names the fix itself.
Be honest, the way the receipts are. Don't invent a repro you didn't run or a version you didn't check. "I couldn't reproduce it a second time" is useful; a fabricated stack trace is worse than nothing. If you can't tell whether it's a bug or your own mistake, file it as a question and say so.
The conversation always ends. The responsibility shouldn't have to.
