Run your first contract
From zero to a rendered receipt: what OpenProse is, how the router picks your path, and the exact execution semantics of prose run.
role: file-system-state-management summary: | File-system state management for OpenProse. The normative reference for the canonical world-model artifact layout, deterministic serialization, the append-only receipt ledger, and the workspace (private scratch) vs published (canonical truth) discipline. see-also:
- ../prose.md: VM execution semantics + the render harness seam
- ../forme.md: Wiring semantics (produces the topology world-model)
- ../primitives/session.md: Session context and compaction guidelines
File-System State Management
This document describes how the OpenProse VM tracks execution state using files
under <openprose-root>. Native repositories use the repository root as
<openprose-root>. Attached repositories use repo/.agents/prose. User-global
work uses ~/.agents/prose.
This file is the normative reference for filesystem artifact layout and file
formats. prose.md summarizes the same model from the execution algorithm's
point of view; when details differ, prefer this file for paths, ownership, and
serialization formats.
Overview
File-based state persists all execution artifacts to disk. This enables:
- Inspection: See exactly what happened at each step, including intermediate work
- Resumption: Pick up interrupted runs from the last completed receipt
- Debugging: Trace through the compiled intent, workspace scratch, and the published world-model
- Auditability: The append-only receipt ledger chains every commit; the world-model is content-addressed and diffable
Key principle: Files are inspectable artifacts. The directory structure IS the execution state.
The load-bearing distinction (the invariant state/README.md states for every
backend): a node's published
world-model is the canonical, deterministically-serialized, fingerprinted
artifact — the truth downstreams subscribe to. The render's workspace is
private scratch — intermediate reasoning, working notes — and is never
fingerprinted and never subscribed to. This is not mere output-visibility
(the earlier workspace/→bindings/ distinction): it is
fingerprint-materiality. A node updates its published world-model only when
something semantically material actually changed; immaterial churn stays in the
workspace. SQL/vector indices are derived projections of the canonical
artifact, never the truth.
Directory Structure
# <openprose-root>
├── src/ # Authored OpenProse source
│ ├── research-system/
│ │ ├── index.prose.md # Conventional multi-file program root
│ │ ├── researcher.prose.md
│ │ └── synthesizer.prose.md
│ ├── patterns/
│ │ └── worker-critic.prose.md
│ └── tests/
│ └── research-system.test.prose.md
├── dist/ # Compiled intent (topology WM + canonicalizers + validators)
│ ├── manifest.next.json # Newly compiled, pending activation
│ └── manifest.active.json # Currently active compiled intent
├── runs/
│ └── {YYYYMMDD}-{HHMMSS}-{random}/
│ ├── compiled-intent.json # Topology world-model + canonicalizers + validators (snapshot)
│ ├── root.prose.md # Copy of the invoked source file
│ ├── sources/ # Source files copied at compile time
│ │ ├── researcher.prose.md
│ │ ├── critic.prose.md
│ │ └── synthesizer.prose.md
│ ├── workspace/ # Private render scratch — NEVER fingerprinted, NEVER subscribed to
│ │ ├── researcher/
│ │ │ ├── notes.md # Intermediate scratch work
│ │ │ ├── raw-results.md # Intermediate data (e.g. raw poll w/ fetched_at)
│ │ │ └── __delegate/ # Runtime delegation state (if any)
│ │ │ └── {delegate}/
│ │ │ ├── {id}.md # Request payload
│ │ │ └── {id}-response.md # Response payload
│ │ ├── critic/
│ │ │ └── evaluation.md
│ │ └── synthesizer/
│ │ └── report.md
│ ├── world-model/ # Published canonical truth (one per node) — deterministically serialized + fingerprinted
│ │ ├── caller/ # Caller-provided inputs (gateway-style)
│ │ │ └── question.md
│ │ ├── researcher/ # Researcher's published world-model artifact
│ │ │ ├── findings.md
│ │ │ ├── sources.md
│ │ │ └── .version # ContentAddress of this committed version
│ │ ├── critic/
│ │ │ ├── evaluation.md
│ │ │ └── .version
│ │ └── synthesizer/
│ │ ├── report.md
│ │ └── .version
│ ├── receipts/ # Append-only receipt ledger (one chain per node)
│ │ ├── researcher.jsonl # Receipt chain (prev pointers); status/fingerprints/wake/cost
│ │ ├── critic.jsonl
│ │ └── synthesizer.jsonl
│ ├── vm.log.md # Append-only human-readable execution log
│ └── agents/ # Run-scoped agent memory
│ └── {name}/
│ ├── memory.md
│ ├── {name}-001.md
│ └── ...
├── state/ # Durable cross-run state
│ ├── agents/
│ │ └── {name}/
│ │ ├── memory.md
│ │ └── ...
│ └── world-model/ # Durable per-node canonical truth (survives runs)
│ └── {node}/
│ ├── published/ # Current committed canonical artifact
│ ├── versions/ # Content-addressed prior versions ({ContentAddress})
│ └── receipts.jsonl # The node's durable receipt ledger
├── deps/ # Cloned dependency repos (gitignored)
│ ├── github.com/
│ │ ├── openprose/
│ │ │ └── prose/ # Full clone of github.com/openprose/prose
│ │ │ └── packages/
│ │ │ ├── std/
│ │ │ │ └── evals/
│ │ │ │ └── inspector.prose.md
│ │ │ └── co/
│ │ │ └── systems/
│ │ │ └── company-repo-checker/
│ │ │ └── index.prose.md
│ │ └── alice/
│ │ └── research/
│ │ └── ...
│ └── gitlab.com/
│ └── ...
├── prose.lock # Pinned dependency SHAs (committed to git)
└── .env # Config (simple key=value format)
# User-global OpenProse root
~/.agents/prose/
├── src/ # User/global scoped source
├── runs/ # User/global scoped run state
├── state/ # User-global durable cross-run state
│ ├── agents/
│ └── world-model/
├── deps/ # User/global scoped dependency cache
├── prose.lock
└── .env
Run ID Format
Format: {YYYYMMDD}-{HHMMSS}-{random6}
Example: 20260317-143052-a7b3c9
Segment Numbering
Agent segments use 3-digit zero-padded numbers: captain-001.md, captain-002.md, etc.
The Three Directories
The core of Prose state management is the separation of three directories:
sources/ (immutable compiled snapshots), workspace/ (private,
never-fingerprinted render scratch), and world-model/ (the published,
deterministically-serialized, fingerprinted canonical truth).
sources/ — Source Snapshots
*.prose.md files copied at compile time. These are the definitions as they were at compile time — stable snapshots even if source files change during execution.
Written by: the compile phase Read by: The VM when constructing render prompts Immutable during execution.
workspace/ — Private Render Scratch
One subdirectory per node. The render writes all its working state here — intermediate notes, drafts, raw poll data, scratch reasoning.
Written by: the render (each node writes to its own subdirectory)
Read by: only the render that owns it, and the VM for __error.md. Never fingerprinted, never subscribed to. Everything is preserved for post-run debugging.
The workspace is the render's private sandbox. Critically, immaterial churn lives and dies here: a re-poll that only bumps a fetched_at timestamp writes to workspace, the canonicalizer drops the immaterial field, the fingerprint does not move, and nothing reaches the published truth. It can contain anything:
workspace/researcher/
├── search-log.md # What searches were attempted
├── raw-results.md # Unfiltered search results (may carry fetched_at, request ids)
├── filtered-results.md # After relevance filtering
└── notes.md # Scratch thinking
world-model/ — Published Canonical Truth
One subdirectory per node (plus caller/ for external/caller inputs). The node's maintained truth — a content-addressable artifact (a directory by default), the public interface downstream nodes subscribe to.
Written by: the VM via commit_world_model, on a rendered receipt with a moved fingerprint (the canonical-serialization-before-fingerprint pass, below).
Read by: downstream renders — by reference, at a pinned content-addressed version (never inlined into context).
world-model/
├── caller/
│ └── question.md # External/caller input (gateway-style node)
├── researcher/
│ ├── findings.md # Published, structured, canonicalizable truth
│ ├── sources.md
│ └── .version # ContentAddress of this committed version
└── synthesizer/
├── report.md
└── .version
Note: report.md here is the structured truth that backs the fingerprint.
Free-form rendered prose is a derived projection excluded from the
fingerprint (the structured-backing rule in contract-markdown.md) —
otherwise an LLM re-rendering the same paragraph hashes differently every time
and falsely re-triggers downstreams. Fingerprint the structured truth; render
prose from it.
Faceted layout — one subtree per facet
When a node's ### Maintains declares facets by naming the parts (a ####
sub-heading inside ### Maintains is a facet — the named-parts rule in
contract-markdown.md), the published
artifact lays each facet out as its own subtree under the node directory:
published/<facet>/…. The directory structure is the subscription surface —
the same name is the facet's fingerprint unit, its
Requires.<facet> ↔ Maintains.<facet> subscription symbol, and its on-disk
region. The canonical competitor-activity-monitor example
(examples/competitor-activity/) declares #### funding, #### hiring, and
#### product-launches, so its published artifact is:
world-model/
└── competitor-activity-monitor/
├── competitors.md # shared, un-facetted fields (name, last_corroborated)
├── published/
│ ├── funding/ # #### funding facet subtree
│ │ └── events.md # structured funding events (round, amount, date)
│ ├── hiring/ # #### hiring facet subtree
│ │ └── roles.md # department set + open-role count
│ └── product-launches/ # #### product-launches facet subtree
│ └── launches.md # launch set + shipped status
└── .version # ContentAddress of this committed version
The fingerprinting rule with facets (see the canonical-serialization pass
below). The single authority for facet tokens is the
compiled canonicalizer that travels with the contract: it reduces the
node's structured material truth (the ### Maintains canonicalization spec,
frozen at compile, addressing material fields by their dotted structured paths)
to the { facet → token } map. The published/<facet>/… directory layout above
is a legibility convention for the on-disk artifact — it mirrors the facets so
"the directory is the state" reads literally — but the per-facet token is
not a digest of that on-disk subtree's bytes; it is what the compiled
canonicalizer computes over the facet's material structured content.
- The atomic
@atomictoken is computed over the wholepublished/tree — every facet's material content plus the shared un-facetted fields — and is always emitted. It is the diamond-reconvergence primitive and the free default. - Each declared facet additionally emits one token computed over only that
facet's material content (its
#### fundingmaterial fields). A downstream that### Requiresfundingand resolves to#### fundingsubscribes to that facet's token: a move in thehiringfacet advances thehiringtoken and the@atomictoken but not thefundingtoken, so the funding-only subscriber does not wake (the selector boundary). - Shared un-facetted fields (here
competitors.md'sname/last_corroborated) belong to no facet's material content, so they move only the@atomictoken.
Atomic-only nodes (no #### parts) keep the flat layout above — facets are
purely additive, and the @atomic token over the whole artifact is unchanged.
Correctness holds either way: the compiled canonicalizer fingerprints the
structured material truth regardless of the on-disk directory shape; the subtree
layout is the legibility surface, not a second fingerprinting convention.
The Canonical-Serialization-Before-Fingerprint Pass
This is the pass the old workspace/→bindings/ copy lacked. Publishing a
node's world-model is not a dumb file copy; it is serialize canonically →
canonicalize (drop immaterial) → fingerprint → sign receipt:
- Collect the node's published artifact files from its commit set.
- Canonically serialize the artifact deterministically: stable file ordering (sorted by normalized path), path/encoding normalization, and sorted-key JSON for any structured records (reuses the receipt's canonical-JSON machinery). The same byte sequence must result regardless of write order or filesystem enumeration order.
- Apply the compiled canonicalizer for this node (
### Maintainscanonicalization spec, frozen at compile time): drop immaterial fields (fetched_at, request ids, cosmetic ordering), normalize sets/numbers/text to declared tolerances. This yields the canonical (material) form. - Fingerprint = the compiled canonicalizer's digest over the canonical
material form, producing the
FingerprintMap— the atomic@atomictoken (over the whole material truth) always, plus one token per declared facet (over only that facet's material content; see Faceted layout above). The token authority is the compiled canonicalizer over the structured truth, not a digest of the on-diskpublished/<facet>/subtree bytes. - Compare against the node's prior receipt
fingerprints. If nothing moved, write askippedreceipt (unchanged fingerprints copied forward, emptysemantic_diff, zerocost) and publish nothing new. If a fingerprint moved, write the canonical artifact toworld-model/{node}/, stamp its.versionwith the content address, and emit arenderedreceipt carrying the newfingerprints.
The reconciler's wake decision is this fingerprint comparison — deterministic,
total, no LLM. Only a rendered receipt with a moved fingerprint propagates to
downstreams (the reconcile loop in concepts/reconciler.md).
File Formats
Compiled Intent
The compile-phase output. For filesystem runs it may be snapshotted as
compiled-intent.json. See forme.md and the compiler IR for the full format.
Contains:
- the topology world-model (Forme's output):
nodes(declared contracts),edges(resolved subscriptions:subscriber.Requires.<facet>→producer.Maintains.<facet>),entry_points, andacyclic: true - per-node canonicalizers (the frozen
### Maintainscanonicalization spec) - per-node postcondition validators (
deterministic|render-attested) contract_fingerprintsfrozen at compile
Written by: the compile phase (Forme + canonicalizer-compile + postcondition-compile)
Read by: the run phase (the reconciler resolves propagation targets from edges)
Caller / Gateway Input Files
Path: world-model/caller/{name}.md
# question
binding: input
source: caller
---
What are the latest developments in quantum computing?
Written by: The VM at run start (from CLI args, config, or user prompt)
Run-Typed Inputs
When a requires entry has type run or run[], the VM writes a structured binding with metadata instead of a plain value.
For a single run:
# subject
binding: input
source: caller
type: run
---
run: 20260406-201439-1a3369
path: <openprose-root>/runs/20260406-201439-1a3369
root: customer-discovery
status: complete
For run[]:
# runs
binding: input
source: caller
type: run[]
---
- run: 20260406-201439-1a3369
path: <openprose-root>/runs/20260406-201439-1a3369
root: customer-discovery
status: complete
- run: 20260407-031438-bf26a3
path: <openprose-root>/runs/20260407-031438-bf26a3
root: competitive-landscape
status: complete
The downstream render receives the path and can read the run's published
world-model/, receipts/, vm.log.md, and compiled intent directly. The
structured header gives the render immediate access to key metadata without
traversing the filesystem.
Resolution order for run references:
- Bare ID (e.g.,
20260406-201439-1a3369): resolves to<openprose-root>/runs/{id} ~/{id}: resolves to~/.agents/prose/runs/{id}(user scope)- Absolute path: used as-is
Written by: The VM at binding time (before any render begins)
World-Model Artifact Files
Path: workspace/{node}/{name}.md (private render scratch — never fingerprinted)
Path: world-model/{node}/{name}.md (published canonical truth — fingerprinted)
Artifact files are simple Markdown — just the structured content. No special frontmatter required:
# Findings
## Claim 1: Transformer architectures dominate NLP benchmarks
- Source: arxiv.org/abs/1706.03762
- Confidence: 0.95
## Claim 2: Scaling laws predict performance from compute
- Source: arxiv.org/abs/2001.08361
- Confidence: 0.88
Written by: the render (to workspace). The VM commits the published artifact via
commit_world_model — serialize canonically → canonicalize → fingerprint → sign — and
publishes only when a fingerprint moved.
Error Files
Path: workspace/{node}/__error.md
# Error: no-results
No relevant sources found for the topic.
Searched:
- Google Scholar: 0 relevant results
- arXiv: 2 results, both tangential
Partial data: None available.
The __ prefix signals to the VM that this is an error, not a committed artifact.
Written by: the render (when it cannot satisfy its ### Maintains). Triggers a failed receipt; nothing commits, no fingerprint moves.
vm.log.md — Append-Only Execution Log
vm.log.md is an append-only log of execution events. The VM appends entries as execution progresses.
Only the VM writes this file. Subagents never modify vm.log.md.
Format
# run:20260317-143052-a7b3c9 deep-research
upstream: [20260306-112233-f4a5b6] # optional — present when run has run-typed inputs
root: research/deep-research # always present — the invoked contract file
1→ [input] question ✓
2→ researcher ✓ rendered
3→ ∥start critic,fact-checker
3a→ critic ✓
3b→ fact-checker ✓
3→ ∥done
4→ synthesizer ✓ rendered
---end 2026-03-17T14:35:22Z
The header is the block between the # heading and the first event marker:
upstream:is written once at binding time, before any render begins. Omitted when the run has norun-typed inputs.root:is always present — the invoked contract file.- On resumption, the VM reads these as context but does not re-process them.
Event Markers
| Marker | Meaning | Example |
|---|---|---|
N→ [input] name ✓ |
Caller input bound | 1→ [input] question ✓ |
N→ node ✓ rendered |
Render committed a moved world-model | 2→ researcher ✓ rendered |
N→ node ∅ skipped |
Reconciler skipped: no fingerprint moved | 2→ researcher ∅ skipped |
N→ ∥start a,b |
Parallel renders started | 3→ ∥start critic,fact-checker |
Na→ a ✓ |
Parallel render completed | 3a→ critic ✓ |
N→ ∥done |
All parallel renders complete | 3→ ∥done |
N→ node ✗ error-name |
Render signaled an error | 3→ researcher ✗ no-results |
N→ node ⇒ delegate (delegate: {id}) |
Render yielded to a runtime delegate | 4→ server ⇒ synthesizer (delegate: req-001) |
N→ delegate ✓ |
Runtime delegate completed | 4→ synthesizer ✓ |
N→ node ⟳ (resumed) |
Render resumed after delegation | 4→ server ⟳ (resumed) |
N→ [eval] assertion ✓ |
Test assertion passed | 5→ [eval] assertion ✓ |
N→ [eval] assertion ✗ |
Test assertion failed | 5→ [eval] assertion ✗ |
---test PASS |
Test passed (all assertions satisfied) | ---test PASS |
---test FAIL (N/M assertions) |
Test failed | ---test FAIL (2/3 assertions) |
---end TIMESTAMP |
Run completed | ---end 2026-03-17T14:35:22Z |
---error TIMESTAMP msg |
Run failed | ---error 2026-03-17T... no-results |
When the VM Writes
| Event | Action |
|---|---|
| Caller input bound | Append input marker |
| Render completes | Append completion marker |
| Parallel starts/joins | Append parallel markers |
| Error occurs | Append error marker |
| Delegation spawned | Append ⇒ marker |
| Delegate completes | Append delegate ✓ marker |
| Render resumed | Append ⟳ marker |
| Test assertion evaluated | Append [eval] marker |
| Test suite result | Append ---test marker |
| Run ends | Append end marker |
The VM does NOT rewrite the entire file. Each write is a single line append.
Resumption
To resume an interrupted run:
- Read the
receipts/ledger — the append-only chain is the source of truth; find the last committed receipt per node - Read the compiled intent — get the topology and propagation edges
- Scan
world-model/— confirm published canonical artifacts (and their.version) - Re-derive reconciler dirty/coalesce state from unconsumed upstream receipts and continue
Who Writes What
| Artifact | Written By | When |
|---|---|---|
| compiled intent | the compile phase | Before execution |
root.prose.md |
the compile phase | Before execution |
sources/*.prose.md |
the compile phase | Before execution |
world-model/caller/*.md |
VM | At entry / gateway boot |
workspace/{node}/* |
the render | During the render |
workspace/{node}/__delegate/{delegate}/{id}.md |
the render | Before delegation yield |
workspace/{node}/__delegate/{delegate}/{id}-response.md |
VM | After delegate completes |
world-model/{node}/* + .version |
VM (commit_world_model) |
On a rendered receipt with a moved fingerprint |
receipts/{node}.jsonl |
VM | After each render or skip |
vm.log.md |
VM | After each event |
runs/{id}/agents/{name}/memory.md |
Execution-scoped agent | During the render |
runs/{id}/agents/{name}/{name}-NNN.md |
Execution-scoped agent | During the render |
state/agents/{name}/memory.md |
Durable cross-run agent | During the render |
state/agents/{name}/{name}-NNN.md |
Durable cross-run agent | During the render |
state/world-model/{node}/published/ + versions/ + receipts.jsonl |
VM | On durable commit |
Key principle: The VM orchestrates. The render writes its working state to its private workspace. The VM publishes the canonical world-model via the canonical-serialization-before-fingerprint pass and signs a receipt — never a dumb copy.
The Commit-and-Sign Protocol
This replaces the old copy-on-return for nodes. When a render completes:
- The render writes all its working state to
workspace/{node}/. - The render returns a confirmation listing its committed artifact files and
attesting its
### Maintainspostconditions (no separate judge beat). - The VM runs the canonical-serialization-before-fingerprint pass (serialize canonically → apply the compiled canonicalizer → fingerprint).
- The VM compares the new
FingerprintMapagainst the node's prior receipt.- No fingerprint moved → write a
skippedreceipt (unchanged fingerprints copied forward, emptysemantic_diff, zerocost); publish nothing. - A fingerprint moved → write the canonical artifact to
world-model/{node}/, stamp.version, and emit arenderedreceipt with the newfingerprints.
- No fingerprint moved → write a
- The VM appends the receipt to
receipts/{node}.jsonl(with itsprevpointer) and a marker tovm.log.md.
Publishing is write world-model + sign receipt. Only a rendered receipt with a
moved fingerprint propagates to downstreams.
If the render wrote __error.md instead:
- VM reads
workspace/{node}/__error.md - VM emits a
failedreceipt — a failed render commits nothing; the prior world-model stands and no fingerprint moves (failure = no-commit; seeconcepts/reconciler.md) - VM appends error marker to
vm.log.md
Agent Memory Files
Agent memory lives under runs/{id}/agents/{name}/ for execution-scoped
sessions and under state/agents/{name}/ for durable cross-run sessions.
{agent-scope}/{name}/memory.md
The agent's current accumulated state:
# Agent Memory: captain
## Current Understanding
The project is implementing a research pipeline for quantum computing.
Researcher produces good breadth but sometimes lacks depth on subtopics.
## Decisions Made
- 2026-03-17: Approved initial research scope, flagged need for deeper source verification
- 2026-03-17: Set confidence threshold at 0.7 for claim inclusion
## Open Concerns
- Source diversity is low — too many arXiv papers, not enough industry reports
{agent-scope}/{name}/{name}-NNN.md
Prior segment records:
# Segment 001
timestamp: 2026-03-17T14:32:15Z
## Summary
- Reviewed: researcher output (findings.md, sources.md)
- Found: 12 claims extracted, 3 below confidence threshold
- Decided: Accept 9 claims, request broader source search for rejected 3
- Next: Review critic evaluation, verify source diversity improved
Memory Scoping
| Scope | Declaration | Path | Lifetime |
|---|---|---|---|
| Execution (default) | ### Runtime with persist: true |
<openprose-root>/runs/{id}/agents/{name}/ |
Dies with run |
| Project | ### Runtime with persist: project |
<openprose-root>/state/agents/{name}/ |
Survives runs |
| User | ### Runtime with persist: user |
~/.agents/prose/state/agents/{name}/ |
Survives projects |
<openprose-root>/.env
Simple key=value configuration:
OPENPROSE_DEFAULT_MODEL=opus
OPENPROSE_MAX_PARALLEL=5
Nested Imports
When a run imports and invokes another OpenProse program (via installed dependency or local file), the imported program runs in its own subdirectory:
<openprose-root>/runs/{id}/imports/{handle}--{slug}/
├── compiled-intent.json
├── root.prose.md
├── sources/
├── workspace/
├── world-model/
├── receipts/
├── vm.log.md
├── imports/ # Further nesting
│ └── ...
└── agents/
Same structure recursively, enabling unlimited nesting depth.
Summary
Prose file-system state management separates private scratch from published, fingerprinted truth:
sources/— immutable source snapshots (what was compiled)workspace/— private render scratch (how a node did its work) — never fingerprinted, never subscribed toworld-model/— the published canonical truth per node (deterministically serialized + fingerprinted) — what downstreams subscribe toreceipts/— the append-only receipt ledger (the source of truth for reconciler state)
The compiled intent defines the topology. The reconciler walks it by comparing fingerprints — deterministic, total, no LLM. The render writes to workspace. The VM commits the canonical world-model through the canonical-serialization-before-fingerprint pass and signs a receipt — never a dumb copy. SQL/vector indices, when present, are derived projections of the canonical truth. Everything is on disk, everything is inspectable, everything is auditable through the signed receipt chain.