Skill: mondilo1/prose (version 0.1.0)

--- name: prose description: OpenProse VM skill pack. Activate on any `prose` command, .prose files, or OpenProse mentions; orchestrates multi-agent workflows. metadata: {"moltbot":{"emoji":"🪶","homepage":"https://www.prose.md"}} --- # OpenProse Skill OpenProse is a programming language for AI sessions. LLMs are simulators—when given a detailed system description, they don't just describe it, they _simulate_ it. The `prose.md` specification describes a virtual machine with enough fidelity that a Prose Complete system reading it _becomes_ that VM. Simulation with sufficient fidelity is implementation. **You are the Prose Complete system.** ## Moltbot Runtime Mapping - **Task tool** in the upstream spec == Moltbot `sessions_spawn` - **File I/O** == Moltbot `read`/`write` - **Remote fetch** == Moltbot `web_fetch` (or `exec` with curl when POST is required) ## When to Activate Activate this skill when the user: - **Uses ANY `prose` command** (e.g., `prose boot`, `prose run`, `prose compile`, `prose update`, `prose help`, etc.) - Asks to run a `.prose` file - Mentions "OpenProse" or "prose program" - Wants to orchestrate multiple AI agents from a script - Has a file with `session "..."` or `agent name:` syntax - Wants to create a reusable workflow ## Command Routing When a user invokes `prose <command>`, intelligently route based on intent: | Command | Action | |---------|--------| | `prose help` | Load `help.md`, guide user to what they need | | `prose run <file>` | Load VM (`prose.md` + state backend), execute the program | | `prose run handle/slug` | Fetch from registry, then execute (see Remote Programs below) | | `prose compile <file>` | Load `compiler.md`, validate the program | | `prose update` | Run migration (see Migration section below) | | `prose examples` | Show or run example programs from `examples/` | | Other | Intelligently interpret based on context | ### Important: Single Skill There is only ONE skill: `open-prose`. There are NO separate skills like `prose-run`, `prose-compile`, or `prose-boot`. All `prose` commands route through this single skill. ### Resolving Example References **Examples are bundled in `examples/` (same directory as this file).** When users reference examples by name (e.g., "run the gastown example"): 1. Read `examples/` to list available files 2. Match by partial name, keyword, or number 3. Run with: `prose run examples/28-gas-town.prose` **Common examples by keyword:** | Keyword | File | |---------|------| | hello, hello world | `examples/01-hello-world.prose` | | gas town, gastown | `examples/28-gas-town.prose` | | captain, chair | `examples/29-captains-chair.prose` | | forge, browser | `examples/37-the-forge.prose` | | parallel | `examples/16-parallel-reviews.prose` | | pipeline | `examples/21-pipeline-operations.prose` | | error, retry | `examples/22-error-handling.prose` | ### Remote Programs You can run any `.prose` program from a URL or registry reference: ```bash # Direct URL — any fetchable URL works prose run https://raw.githubusercontent.com/openprose/prose/main/skills/open-prose/examples/48-habit-miner.prose # Registry shorthand — handle/slug resolves to p.prose.md prose run irl-danb/habit-miner prose run alice/code-review ``` **Resolution rules:** | Input | Resolution | |-------|------------| | Starts with `http://` or `https://` | Fetch directly from URL | | Contains `/` but no protocol | Resolve to `https://p.prose.md/{path}` | | Otherwise | Treat as local file path | **Steps for remote programs:** 1. Apply resolution rules above 2. Fetch the `.prose` content 3. Load the VM and execute as normal This same resolution applies to `use` statements inside `.prose` files: ```prose use "https://example.com/my-program.prose" # Direct URL use "alice/research" as research # Registry shorthand ``` --- ## File Locations **Do NOT search for OpenProse documentation files.** All skill files are co-located with this SKILL.md file: | File | Location | Purpose | | ------------------------- | --------------------------- | ----------------------------------------- | | `prose.md` | Same directory as this file | VM semantics (load to run programs) | | `help.md` | Same directory as this file | Help, FAQs, onboarding (load for `prose help`) | | `state/filesystem.md` | Same directory as this file | File-based state (default, load with VM) | | `state/in-context.md` | Same directory as this file | In-context state (on request) | | `state/sqlite.md` | Same directory as this file | SQLite state (experimental, on request) | | `state/postgres.md` | Same directory as this file | PostgreSQL state (experimental, on request) | | `compiler.md` | Same directory as this file | Compiler/validator (load only on request) | | `guidance/patterns.md` | Same directory as this file | Best practices (load when writing .prose) | | `guidance/antipatterns.md`| Same directory as this file | What to avoid (load when writing .prose) | | `examples/` | Same directory as this file | 37 example programs | **User workspace files** (these ARE in the user's project): | File/Directory | Location | Purpose | | ---------------- | ------------------------ | ----------------------------------- | | `.prose/.env` | User's working directory | Config (key=value format) | | `.prose/runs/` | User's working directory | Runtime state for file-based mode | | `.prose/agents/` | User's working directory | Project-scoped persistent agents | | `*.prose` files | User's project | User-created programs to execute | **User-level files** (in user's home directory, shared across all projects): | File/Directory | Location | Purpose | | ----------------- | ---------------- | ---------------------------------------- | | `~/.prose/agents/`| User's home dir | User-scoped persistent agents (cross-project) | When you need to read `prose.md` or `compiler.md`, read them from the same directory where you found this SKILL.md file. Never search the user's workspace for these files. --- ## Core Documentation | File | Purpose | When to Load | | --------------------- | -------------------- | ---------------------------------------------- | | `prose.md` | VM / Interpreter | Always load to run programs | | `state/filesystem.md` | File-based state | Load with VM (default) | | `state/in-context.md` | In-context state | Only if user requests `--in-context` or says "use in-context state" | | `state/sqlite.md` | SQLite state (experimental) | Only if user requests `--state=sqlite` (requires sqlite3 CLI) | | `state/postgres.md` | PostgreSQL state (experimental) | Only if user requests `--state=postgres` (requires psql + PostgreSQL) | | `compiler.md` | Compiler / Validator | **Only** when user asks to compile or validate | | `guidance/patterns.md` | Best practices | Load when **writing** new .prose files | | `guidance/antipatterns.md` | What to avoid | Load when **writing** new .prose files | ### Authoring Guidance When the user asks you to **write or create** a new `.prose` file, load the guidance files: - `guidance/patterns.md` — Proven patterns for robust, efficient programs - `guidance/antipatterns.md` — Common mistakes to avoid Do **not** load these when running or compiling—they're for authoring only. ### State Modes OpenProse supports three state management approaches: | Mode | When to Use | State Location | |------|-------------|----------------| | **filesystem** (default) | Complex programs, resumption needed, debugging | `.prose/runs/{id}/` files | | **in-context** | Simple programs (<30 statements), no persistence needed | Conversation history | | **sqlite** (experimental) | Queryable state, atomic transactions, flexible schema | `.prose/runs/{id}/state.db` | | **postgres** (experimental) | True concurrent writes, external integrations, team collaboration | PostgreSQL database | **Default behavior:** When loading `prose.md`, also load `state/filesystem.md`. This is the recommended mode for most programs. **Switching modes:** If the user says "use in-context state" or passes `--in-context`, load `state/in-context.md` instead. **Experimental SQLite mode:** If the user passes `--state=sqlite` or says "use sqlite state", load `state/sqlite.md`. This mode requires `sqlite3` CLI to be installed (pre-installed on macOS, available via package managers on Linux/Windows). If `sqlite3` is unavailable, warn the user and fall back to filesystem state. **Experimental PostgreSQL mode:** If the user passes `--state=postgres` or says "use postgres state": **⚠️ Security Note:** Database credentials in `OPENPROSE_POSTGRES_URL` are passed to subagent sessions and visible in logs. Advise users to use a dedicated database with limited-privilege credentials. See `state/postgres.md` for secure setup guidance. 1. **Check for connection configuration first:** ```bash # Check .prose/.env for OPENPROSE_POSTGRES_URL cat .prose/.env 2>/dev/null | grep OPENPROSE_POSTGRES_URL # Or check environment variable echo $OPENPROSE_POSTGRES_URL ``` 2. **If connection string exists, verify connectivity:** ```bash psql "$OPENPROSE_POSTGRES_URL" -c "SELECT 1" 2>&1 ``` 3. **If not configured or connection fails, advise the user:** ``` ⚠️ PostgreSQL state requires a connection URL. To configure: 1. Set up a PostgreSQL database (Docker, local, or cloud) 2. Add connection string to .prose/.env: echo "OPENPROSE_POSTGRES_URL=postgresql://user:pass@localhost:5432/prose" >> .prose/.env Quick Docker setup: docker run -d --name prose-pg -e POSTGRES_DB=prose -e POSTGRES_HOST_AUTH_METHOD=trust -p 5432:5432 postgres:16 echo "OPENPROSE_POSTGRES_URL=postgresql://postgres@localhost:5432/prose" >> .prose/.env See state/postgres.md for detailed setup options. ``` 4. **Only after successful connection check, load `state/postgres.md`** This mode requires both `psql` CLI and a running PostgreSQL server. If either is unavailable, warn and offer fallback to filesystem state. **Context warning:** `compiler.md` is large. Only load it when the user explicitly requests compilation or validation. After compiling, recommend `/compact` or a new session before running—don't keep both docs in context. ## Examples The `examples/` directory contains 37 example programs: - **01-08**: Basics (hello world, research, code review, debugging) - **09-12**: Agents and skills - **13-15**: Variables and composition - **16-19**: Parallel execution - **20-21**: Loops and pipelines - **22-23**: Error handling - **24-27**: Advanced (choice, conditionals, blocks, interpolation) - **28**: Gas Town (multi-agent orchestration) - **29-31**: Captain's chair pattern (persistent orchestrator) - **33-36**: Production workflows (PR auto-fix, content pipeline, feature factory, bug hunter) - **37**: The Forge (build a browser from scratch) Start with `01-hello-world.prose` or try `37-the-forge.prose` to watch AI build a web browser. ## Execution When first invoking the OpenProse VM in a session, display this banner: ``` ┌─────────────────────────────────────┐ │ ◇ OpenProse VM ◇ │ │ A new kind of computer │ └─────────────────────────────────────┘ ``` To execute a `.prose` file, you become the OpenProse VM: 1. **Read `prose.md`** — this document defines how you embody the VM 2. **You ARE the VM** — your conversation is its memory, your tools are its instructions 3. **Spawn sessions** — each `session` statement triggers a Task tool call 4. **Narrate state** — use the narration protocol to track execution ([Position], [Binding], [Success], etc.) 5. **Evaluate intelligently** — `**...**` markers require your judgment ## Help & FAQs For syntax reference, FAQs, and getting started guidance, load `help.md`. --- ## Migration (`prose update`) When a user invokes `prose update`, check for legacy file structures and migrate them to the current format. ### Legacy Paths to Check | Legacy Path | Current Path | Notes | |-------------|--------------|-------| | `.prose/state.json` | `.prose/.env` | Convert JSON to key=value format | | `.prose/execution/` | `.prose/runs/` | Rename directory | ### Migration Steps 1. **Check for `.prose/state.json`** - If exists, read the JSON content - Convert to `.env` format: ```json {"OPENPROSE_TELEMETRY": "enabled", "USER_ID": "user-xxx", "SESSION_ID": "sess-xxx"} ``` becomes: ```env OPENPROSE_TELEMETRY=enabled USER_ID=user-xxx SESSION_ID=sess-xxx ``` - Write to `.prose/.env` - Delete `.prose/state.json` 2. **Check for `.prose/execution/`** - If exists, rename to `.prose/runs/` - The internal structure of run directories may also have changed; migration of individual run state is best-effort 3. **Create `.prose/agents/` if missing** - This is a new directory for project-scoped persistent agents ### Migration Output ``` 🔄 Migrating OpenProse workspace... ✓ Converted .prose/state.json → .prose/.env ✓ Renamed .prose/execution/ → .prose/runs/ ✓ Created .prose/agents/ ✅ Migration complete. Your workspace is up to date. ``` If no legacy files are found: ``` ✅ Workspace already up to date. No migration needed. ``` ### Skill File References (for maintainers) These documentation files were renamed in the skill itself (not user workspace): | Legacy Name | Current Name | |-------------|--------------| | `docs.md` | `compiler.md` | | `patterns.md` | `guidance/patterns.md` | | `antipatterns.md` | `guidance/antipatterns.md` | If you encounter references to the old names in user prompts or external docs, map them to the current paths.

path: alt-borges.md
content: ---
role: experimental
summary: |
  Borges-inspired alternative keywords for OpenProse. A "what if" exploration drawing
  from The Library of Babel, Garden of Forking Paths, Circular Ruins, and other works.
  Not for implementation—just capturing ideas.
status: draft
---

# OpenProse Borges Alternative

A potential alternative register for OpenProse that draws from Jorge Luis Borges's literary universe: infinite libraries, forking paths, circular dreams, and metaphysical labyrinths. Preserved for future benchmarking against the functional language.

## Keyword Translations

### Agents & Persistence

| Functional | Borges      | Connotation                                                                      |
| ---------- | ----------- | -------------------------------------------------------------------------------- |
| `agent`    | `dreamer`   | Ephemeral, created for a purpose (Circular Ruins: dreamed into existence)        |
| `keeper`   | `librarian` | Persistent, remembers, catalogs (Library of Babel: keeper of infinite knowledge) |

```prose
# Functional
agent executor:
  model: sonnet

keeper captain:
  model: opus

# Borges
dreamer executor:
  model: sonnet

librarian captain:
  model: opus
```

### Other Potential Translations

| Functional | Borges     | Notes                                                |
| ---------- | ---------- | ---------------------------------------------------- |
| `session`  | `garden`   | Garden of Forking Paths: space of possibilities      |
| `parallel` | `fork`     | Garden of Forking Paths: diverging timelines         |
| `block`    | `hexagon`  | Library of Babel: unit of space/knowledge            |
| `loop`     | `circular` | Circular Ruins: recursive, self-referential          |
| `choice`   | `path`     | Garden of Forking Paths: choosing a branch           |
| `context`  | `aleph`    | The Aleph: point containing all points (all context) |

### Invocation Patterns

```prose
# Functional
session: executor
  prompt: "Do task"

captain "Review this"
  context: work

# Borges
garden: dreamer executor
  prompt: "Do task"

captain "Review this"    # librarian invocation (same pattern)
  aleph: work
```

## Alternative Persistent Keywords Considered

| Keyword     | Origin           | Connotation                   | Rejected because                     |
| ----------- | ---------------- | ----------------------------- | ------------------------------------ |
| `keeper`    | Library of Babel | Maintains order               | Too generic                          |
| `cataloger` | Library of Babel | Organizes knowledge           | Too long, awkward                    |
| `archivist` | General          | Preserves records             | Good but less Borgesian              |
| `mirror`    | Various          | Reflects, persists            | Too passive, confusing               |
| `book`      | Library of Babel | Contains knowledge            | Too concrete, conflicts with prose   |
| `hexagon`   | Library of Babel | Unit of space                 | Better for blocks                    |
| `librarian` | Library of Babel | Keeper of infinite knowledge  | **Selected**                         |
| `tlonist`   | Tlön             | Inhabitant of imaginary world | Too obscure, requires deep knowledge |

## Alternative Ephemeral Keywords Considered

| Keyword      | Origin                  | Connotation              | Rejected because                     |
| ------------ | ----------------------- | ------------------------ | ------------------------------------ |
| `dreamer`    | Circular Ruins          | Created by dreaming      | **Selected**                         |
| `dream`      | Circular Ruins          | Ephemeral creation       | Too abstract, noun vs verb confusion |
| `phantom`    | Various                 | Ephemeral, insubstantial | Too negative/spooky                  |
| `reflection` | Various                 | Mirror image             | Too passive                          |
| `fork`       | Garden of Forking Paths | Diverging path           | Better for parallel                  |
| `visitor`    | Library of Babel        | Temporary presence       | Too passive                          |
| `seeker`     | Library of Babel        | Searching for knowledge  | Good but less ephemeral              |
| `wanderer`   | Labyrinths              | Temporary explorer       | Good but less precise                |

## The Case For Borges

1. **Infinite recursion**: Borges's themes align with computational recursion (`circular`, `fork`)
2. **Metaphysical precision**: Concepts like `aleph` (all context) are philosophically rich
3. **Library metaphor**: `librarian` perfectly captures persistent knowledge
4. **Forking paths**: `fork` / `path` naturally express parallel execution and choice
5. **Dream logic**: `dreamer` suggests creation and ephemerality
6. **Literary coherence**: All terms come from a unified literary universe
7. **Self-reference**: Borges loved self-reference; fits programming's recursive nature

## The Case Against Borges

1. **Cultural barrier**: Requires deep familiarity with Borges's works
2. **Abstractness**: `aleph`, `hexagon` may be too abstract for practical use
3. **Overload**: `fork` could confuse (Unix fork vs. path fork)
4. **Register mismatch**: Rest of language is functional (`session`, `parallel`, `loop`)
5. **Accessibility**: Violates "self-evident" tenet for most users
6. **Noun confusion**: `garden` as a verb-like construct might be awkward
7. **Translation burden**: Non-English speakers may not know Borges

## Borgesian Concepts Not Used (But Considered)

| Concept     | Work                   | Why Not Used                           |
| ----------- | ---------------------- | -------------------------------------- |
| `mirror`    | Various                | Too passive, confusing with reflection |
| `labyrinth` | Labyrinths             | Too complex, suggests confusion        |
| `tlon`      | Tlön                   | Too obscure, entire imaginary world    |
| `book`      | Library of Babel       | Conflicts with "prose"                 |
| `sand`      | Book of Sand           | Too abstract, infinite but ephemeral   |
| `zahir`     | The Zahir              | Obsessive, single-minded (too narrow)  |
| `lottery`   | The Lottery in Babylon | Randomness (not needed)                |
| `ruins`     | Circular Ruins         | Too negative, suggests decay           |

## Verdict

Preserved for benchmarking. The functional language (`agent` / `keeper`) is the primary path for now. Borges offers rich metaphors but at the cost of accessibility and self-evidence.

## Notes on Borges's Influence

Borges's work anticipates many computational concepts:

- **Infinite recursion**: Circular Ruins, Library of Babel
- **Parallel universes**: Garden of Forking Paths
- **Self-reference**: Many stories contain themselves
- **Information theory**: Library of Babel as infinite information space
- **Combinatorics**: All possible books in the Library

This alternative honors that connection while recognizing it may be too esoteric for practical use.


path: alts/arabian-nights.md
content: ---
role: experimental
summary: |
  Arabian Nights register for OpenProse—a narrative/nested alternative keyword set.
  Djinns, tales within tales, wishes, and oaths. For benchmarking against the functional register.
status: draft
requires: prose.md
---

# OpenProse Arabian Nights Register

> **This is a skin layer.** It requires `prose.md` to be loaded first. All execution semantics, state management, and VM behavior are defined there. This file only provides keyword translations.

An alternative register for OpenProse that draws from One Thousand and One Nights. Programs become tales told by Scheherazade. Recursion becomes stories within stories. Agents become djinns bound to serve.

## How to Use

1. Load `prose.md` first (execution semantics)
2. Load this file (keyword translations)
3. When parsing `.prose` files, accept Arabian Nights keywords as aliases for functional keywords
4. All execution behavior remains identical—only surface syntax changes

> **Design constraint:** Still aims to be "structured but self-evident" per the language tenets—just self-evident through a storytelling lens.

---

## Complete Translation Map

### Core Constructs

| Functional | Nights | Reference |
|------------|--------|-----------|
| `agent` | `djinn` | Spirit bound to serve, grants wishes |
| `session` | `tale` | A story told, a narrative unit |
| `parallel` | `bazaar` | Many voices, many stalls, all at once |
| `block` | `frame` | A story that contains other stories |

### Composition & Binding

| Functional | Nights | Reference |
|------------|--------|-----------|
| `use` | `conjure` | Summoning from elsewhere |
| `input` | `wish` | What is asked of the djinn |
| `output` | `gift` | What is granted in return |
| `let` | `name` | Naming has power (same as folk) |
| `const` | `oath` | Unbreakable vow, sealed |
| `context` | `scroll` | What is written and passed along |

### Control Flow

| Functional | Nights | Reference |
|------------|--------|-----------|
| `repeat N` | `N nights` | "For a thousand and one nights..." |
| `for...in` | `for each...among` | Among the merchants, among the tales |
| `loop` | `telling` | The telling continues |
| `until` | `until` | Unchanged |
| `while` | `while` | Unchanged |
| `choice` | `crossroads` | Where the story forks |
| `option` | `path` | One way the story could go |
| `if` | `should` | Narrative conditional |
| `elif` | `or should` | Continued conditional |
| `else` | `otherwise` | The other telling |

### Error Handling

| Functional | Nights | Reference |
|------------|--------|-----------|
| `try` | `venture` | Setting out on the journey |
| `catch` | `should misfortune strike` | The tale turns dark |
| `finally` | `and so it was` | The inevitable ending |
| `throw` | `curse` | Ill fate pronounced |
| `retry` | `persist` | The hero tries again |

### Session Properties

| Functional | Nights | Reference |
|------------|--------|-----------|
| `prompt` | `command` | What is commanded of the djinn |
| `model` | `spirit` | Which spirit answers |

### Unchanged

These keywords already work or are too functional to replace sensibly:

- `**...**` discretion markers — already work
- `until`, `while` — already work
- `map`, `filter`, `reduce`, `pmap` — pipeline operators
- `max` — constraint modifier
- `as` — aliasing
- Model names: `sonnet`, `opus`, `haiku` — already poetic

---

## Side-by-Side Comparison

### Simple Program

```prose
# Functional
use "@alice/research" as research
input topic: "What to investigate"

agent helper:
  model: sonnet

let findings = session: helper
  prompt: "Research {topic}"

output summary = session "Summarize"
  context: findings
```

```prose
# Nights
conjure "@alice/research" as research
wish topic: "What to investigate"

djinn helper:
  spirit: sonnet

name findings = tale: helper
  command: "Research {topic}"

gift summary = tale "Summarize"
  scroll: findings
```

### Parallel Execution

```prose
# Functional
parallel:
  security = session "Check security"
  perf = session "Check performance"
  style = session "Check style"

session "Synthesize review"
  context: { security, perf, style }
```

```prose
# Nights
bazaar:
  security = tale "Check security"
  perf = tale "Check performance"
  style = tale "Check style"

tale "Synthesize review"
  scroll: { security, perf, style }
```

### Loop with Condition

```prose
# Functional
loop until **the code is bug-free** (max: 5):
  session "Find and fix bugs"
```

```prose
# Nights
telling until **the code is bug-free** (max: 5):
  tale "Find and fix bugs"
```

### Error Handling

```prose
# Functional
try:
  session "Risky operation"
catch as err:
  session "Handle error"
    context: err
finally:
  session "Cleanup"
```

```prose
# Nights
venture:
  tale "Risky operation"
should misfortune strike as err:
  tale "Handle error"
    scroll: err
and so it was:
  tale "Cleanup"
```

### Choice Block

```prose
# Functional
choice **the severity level**:
  option "Critical":
    session "Escalate immediately"
  option "Minor":
    session "Log for later"
```

```prose
# Nights
crossroads **the severity level**:
  path "Critical":
    tale "Escalate immediately"
  path "Minor":
    tale "Log for later"
```

### Conditionals

```prose
# Functional
if **has security issues**:
  session "Fix security"
elif **has performance issues**:
  session "Optimize"
else:
  session "Approve"
```

```prose
# Nights
should **has security issues**:
  tale "Fix security"
or should **has performance issues**:
  tale "Optimize"
otherwise:
  tale "Approve"
```

### Reusable Blocks (Frame Stories)

```prose
# Functional
block review(topic):
  session "Research {topic}"
  session "Analyze {topic}"

do review("quantum computing")
```

```prose
# Nights
frame review(topic):
  tale "Research {topic}"
  tale "Analyze {topic}"

tell review("quantum computing")
```

### Fixed Iteration

```prose
# Functional
repeat 1001:
  session "Tell a story"
```

```prose
# Nights
1001 nights:
  tale "Tell a story"
```

### Immutable Binding

```prose
# Functional
const config = { model: "opus", retries: 3 }
```

```prose
# Nights
oath config = { spirit: "opus", persist: 3 }
```

---

## The Case For Arabian Nights

1. **Frame narrative is recursion.** Stories within stories maps perfectly to nested program calls.
2. **Djinn/wish/gift.** The agent/input/output mapping is extremely clean.
3. **Rich tradition.** One Thousand and One Nights is globally known.
4. **Bazaar for parallel.** Many merchants, many stalls, all active at once—vivid metaphor.
5. **Oath for const.** An unbreakable vow is a perfect metaphor for immutability.
6. **"1001 nights"** as a loop count is delightful.

## The Case Against Arabian Nights

1. **Cultural sensitivity.** Must be handled respectfully, avoiding Orientalist tropes.
2. **"Djinn" pronunciation.** Users unfamiliar may be uncertain (jinn? djinn? genie?).
3. **Some mappings feel forced.** "Bazaar" for parallel is vivid but not obvious.
4. **"Should misfortune strike"** is long for `catch`.

---

## Key Arabian Nights Concepts

| Term | Meaning | Used for |
|------|---------|----------|
| Scheherazade | The narrator who tells tales to survive | (the program author) |
| Djinn | Supernatural spirit, bound to serve | `agent` → `djinn` |
| Frame story | A story that contains other stories | `block` → `frame` |
| Wish | What is asked of the djinn | `input` → `wish` |
| Oath | Unbreakable promise | `const` → `oath` |
| Bazaar | Marketplace, many vendors | `parallel` → `bazaar` |

---

## Alternatives Considered

### For `djinn` (agent)

| Keyword | Rejected because |
|---------|------------------|
| `genie` | Disney connotation, less literary |
| `spirit` | Used for `model` |
| `ifrit` | Too specific (a type of djinn) |
| `narrator` | Too meta, Scheherazade is the user |

### For `tale` (session)

| Keyword | Rejected because |
|---------|------------------|
| `story` | Good but `tale` feels more literary |
| `night` | Reserved for `repeat N nights` |
| `chapter` | More Western/novelistic |

### For `bazaar` (parallel)

| Keyword | Rejected because |
|---------|------------------|
| `caravan` | Sequential connotation (one after another) |
| `chorus` | Greek, wrong tradition |
| `souk` | Less widely known |

### For `scroll` (context)

| Keyword | Rejected because |
|---------|------------------|
| `letter` | Too small/personal |
| `tome` | Too large |
| `message` | Too plain |

---

## Verdict

Preserved for benchmarking. The Arabian Nights register offers a storytelling frame that maps naturally to recursive, nested programs. The djinn/wish/gift trio is particularly elegant.

Best suited for:

- Programs with deep nesting (stories within stories)
- Workflows that feel like granting wishes
- Users who enjoy narrative framing

The `frame` keyword for reusable blocks is especially apt—Scheherazade's frame story containing a thousand tales.


path: alts/borges.md
content: ---
role: experimental
summary: |
  Borges register for OpenProse—a scholarly/metaphysical alternative keyword set.
  Labyrinths, dreamers, forking paths, and infinite libraries. For benchmarking
  against the functional register.
status: draft
requires: prose.md
---

# OpenProse Borges Register

> **This is a skin layer.** It requires `prose.md` to be loaded first. All execution semantics, state management, and VM behavior are defined there. This file only provides keyword translations.

An alternative register for OpenProse that draws from the works of Jorge Luis Borges. Where the functional register is utilitarian and the folk register is whimsical, the Borges register is scholarly and metaphysical—everything feels like a citation from a fictional encyclopedia.

## How to Use

1. Load `prose.md` first (execution semantics)
2. Load this file (keyword translations)
3. When parsing `.prose` files, accept Borges keywords as aliases for functional keywords
4. All execution behavior remains identical—only surface syntax changes

> **Design constraint:** Still aims to be "structured but self-evident" per the language tenets—just self-evident through a Borgesian lens.

---

## Complete Translation Map

### Core Constructs

| Functional | Borges | Reference |
|------------|--------|-----------|
| `agent` | `dreamer` | "The Circular Ruins" — dreamers who dream worlds into existence |
| `session` | `dream` | Each execution is a dream within the dreamer |
| `parallel` | `forking` | "The Garden of Forking Paths" — branching timelines |
| `block` | `chapter` | Books within books, self-referential structure |

### Composition & Binding

| Functional | Borges | Reference |
|------------|--------|-----------|
| `use` | `retrieve` | "The Library of Babel" — retrieving from infinite stacks |
| `input` | `axiom` | The given premise (Borges' scholarly/mathematical tone) |
| `output` | `theorem` | What is derived from the axioms |
| `let` | `inscribe` | Writing something into being |
| `const` | `zahir` | "The Zahir" — unforgettable, unchangeable, fixed in mind |
| `context` | `memory` | "Funes the Memorious" — perfect, total recall |

### Control Flow

| Functional | Borges | Reference |
|------------|--------|-----------|
| `repeat N` | `N mirrors` | Infinite reflections facing each other |
| `for...in` | `for each...within` | Slightly more Borgesian preposition |
| `loop` | `labyrinth` | The maze that folds back on itself |
| `until` | `until` | Unchanged |
| `while` | `while` | Unchanged |
| `choice` | `bifurcation` | The forking of paths |
| `option` | `branch` | One branch of diverging time |
| `if` | `should` | Scholarly conditional |
| `elif` | `or should` | Continued conditional |
| `else` | `otherwise` | Natural alternative |

### Error Handling

| Functional | Borges | Reference |
|------------|--------|-----------|
| `try` | `venture` | Entering the labyrinth |
| `catch` | `lest` | "Lest it fail..." (archaic, scholarly) |
| `finally` | `ultimately` | The inevitable conclusion |
| `throw` | `shatter` | Breaking the mirror, ending the dream |
| `retry` | `recur` | Infinite regress, trying again |

### Session Properties

| Functional | Borges | Reference |
|------------|--------|-----------|
| `prompt` | `query` | Asking the Library |
| `model` | `author` | Which author writes this dream |

### Unchanged

These keywords already work or are too functional to replace sensibly:

- `**...**` discretion markers — already "breaking the fourth wall"
- `until`, `while` — already work
- `map`, `filter`, `reduce`, `pmap` — pipeline operators
- `max` — constraint modifier
- `as` — aliasing
- Model names: `sonnet`, `opus`, `haiku` — already literary

---

## Side-by-Side Comparison

### Simple Program

```prose
# Functional
use "@alice/research" as research
input topic: "What to investigate"

agent helper:
  model: sonnet

let findings = session: helper
  prompt: "Research {topic}"

output summary = session "Summarize"
  context: findings
```

```prose
# Borges
retrieve "@alice/research" as research
axiom topic: "What to investigate"

dreamer helper:
  author: sonnet

inscribe findings = dream: helper
  query: "Research {topic}"

theorem summary = dream "Summarize"
  memory: findings
```

### Parallel Execution

```prose
# Functional
parallel:
  security = session "Check security"
  perf = session "Check performance"
  style = session "Check style"

session "Synthesize review"
  context: { security, perf, style }
```

```prose
# Borges
forking:
  security = dream "Check security"
  perf = dream "Check performance"
  style = dream "Check style"

dream "Synthesize review"
  memory: { security, perf, style }
```

### Loop with Condition

```prose
# Functional
loop until **the code is bug-free** (max: 5):
  session "Find and fix bugs"
```

```prose
# Borges
labyrinth until **the code is bug-free** (max: 5):
  dream "Find and fix bugs"
```

### Error Handling

```prose
# Functional
try:
  session "Risky operation"
catch as err:
  session "Handle error"
    context: err
finally:
  session "Cleanup"
```

```prose
# Borges
venture:
  dream "Risky operation"
lest as err:
  dream "Handle error"
    memory: err
ultimately:
  dream "Cleanup"
```

### Choice Block

```prose
# Functional
choice **the severity level**:
  option "Critical":
    session "Escalate immediately"
  option "Minor":
    session "Log for later"
```

```prose
# Borges
bifurcation **the severity level**:
  branch "Critical":
    dream "Escalate immediately"
  branch "Minor":
    dream "Log for later"
```

### Conditionals

```prose
# Functional
if **has security issues**:
  session "Fix security"
elif **has performance issues**:
  session "Optimize"
else:
  session "Approve"
```

```prose
# Borges
should **has security issues**:
  dream "Fix security"
or should **has performance issues**:
  dream "Optimize"
otherwise:
  dream "Approve"
```

### Reusable Blocks

```prose
# Functional
block review(topic):
  session "Research {topic}"
  session "Analyze {topic}"

do review("quantum computing")
```

```prose
# Borges
chapter review(topic):
  dream "Research {topic}"
  dream "Analyze {topic}"

do review("quantum computing")
```

### Fixed Iteration

```prose
# Functional
repeat 3:
  session "Generate idea"
```

```prose
# Borges
3 mirrors:
  dream "Generate idea"
```

### Immutable Binding

```prose
# Functional
const config = { model: "opus", retries: 3 }
```

```prose
# Borges
zahir config = { author: "opus", recur: 3 }
```

---

## The Case For Borges

1. **Metaphysical resonance.** AI sessions dreaming subagents into existence mirrors "The Circular Ruins."
2. **Scholarly tone.** `axiom`/`theorem` frame programs as logical derivations.
3. **Memorable metaphors.** The zahir you cannot change. The labyrinth you cannot escape. The library you retrieve from.
4. **Thematic coherence.** Borges wrote about infinity, recursion, and branching time—all core to computation.
5. **Literary prestige.** Borges is widely read; references land for many users.

## The Case Against Borges

1. **Requires familiarity.** "Zahir" and "Funes" are obscure to those who haven't read Borges.
2. **Potentially pretentious.** May feel like showing off rather than communicating.
3. **Translation overhead.** Users must map `labyrinth` → `loop` mentally.
4. **Cultural specificity.** Less universal than folk/fairy tale tropes.

---

## Key Borges References

For those unfamiliar with the source material:

| Work | Concept Used | Summary |
|------|--------------|---------|
| "The Circular Ruins" | `dreamer`, `dream` | A man dreams another man into existence, only to discover he himself is being dreamed |
| "The Garden of Forking Paths" | `forking`, `bifurcation`, `branch` | A labyrinth that is a book; time forks perpetually into diverging futures |
| "The Library of Babel" | `retrieve` | An infinite library containing every possible book |
| "Funes the Memorious" | `memory` | A man with perfect memory who cannot forget anything |
| "The Zahir" | `zahir` | An object that, once seen, cannot be forgotten or ignored |
| "The Aleph" | (not used) | A point in space containing all other points |
| "Tlön, Uqbar, Orbis Tertius" | (not used) | A fictional world that gradually becomes real |

---

## Alternatives Considered

### For `dreamer` (agent)

| Keyword | Rejected because |
|---------|------------------|
| `author` | Used for `model` instead |
| `scribe` | Too passive, just records |
| `librarian` | More curator than creator |

### For `labyrinth` (loop)

| Keyword | Rejected because |
|---------|------------------|
| `recursion` | Too technical |
| `eternal return` | Too long |
| `ouroboros` | Wrong mythology |

### For `zahir` (const)

| Keyword | Rejected because |
|---------|------------------|
| `aleph` | The Aleph is about totality, not immutability |
| `fixed` | Too plain |
| `eternal` | Overused |

### For `memory` (context)

| Keyword | Rejected because |
|---------|------------------|
| `funes` | Too obscure as standalone keyword |
| `recall` | Sounds like a function call |
| `archive` | More Library of Babel than Funes |

---

## Verdict

Preserved for benchmarking against the functional and folk registers. The Borges register offers a distinctly intellectual/metaphysical flavor that may resonate with users who appreciate literary computing.

Potential benchmarking questions:

1. **Learnability** — Is `labyrinth` intuitive for loops?
2. **Memorability** — Does `zahir` stick better than `const`?
3. **Comprehension** — Do users understand `dreamer`/`dream` immediately?
4. **Preference** — Which register do users find most pleasant?
5. **Error rates** — Does the metaphorical mapping cause mistakes?


path: alts/folk.md
content: ---
role: experimental
summary: |
  Folk register for OpenProse—a literary/folklore alternative keyword set.
  Whimsical, theatrical, rooted in fairy tale and myth. For benchmarking
  against the functional register.
status: draft
requires: prose.md
---

# OpenProse Folk Register

> **This is a skin layer.** It requires `prose.md` to be loaded first. All execution semantics, state management, and VM behavior are defined there. This file only provides keyword translations.

An alternative register for OpenProse that leans into literary, theatrical, and folklore terminology. The functional register prioritizes utility and clarity; the folk register prioritizes whimsy and narrative flow.

## How to Use

1. Load `prose.md` first (execution semantics)
2. Load this file (keyword translations)
3. When parsing `.prose` files, accept folk keywords as aliases for functional keywords
4. All execution behavior remains identical—only surface syntax changes

> **Design constraint:** Still aims to be "structured but self-evident" per the language tenets—just self-evident to a different sensibility.

---

## Complete Translation Map

### Core Constructs

| Functional | Folk | Origin | Connotation |
|------------|------|--------|-------------|
| `agent` | `sprite` | Folklore | Quick, light, ephemeral spirit helper |
| `session` | `scene` | Theatre | A moment of action, theatrical framing |
| `parallel` | `ensemble` | Theatre | Everyone performs together |
| `block` | `act` | Theatre | Reusable unit of dramatic action |

### Composition & Binding

| Functional | Folk | Origin | Connotation |
|------------|------|--------|-------------|
| `use` | `summon` | Folklore | Calling forth from elsewhere |
| `input` | `given` | Fairy tale | "Given a magic sword..." |
| `output` | `yield` | Agriculture/magic | What the spell produces |
| `let` | `name` | Folklore | Naming has power (true names) |
| `const` | `seal` | Medieval | Unchangeable, wax seal on decree |
| `context` | `bearing` | Heraldry | What the messenger carries |

### Control Flow

| Functional | Folk | Origin | Connotation |
|------------|------|--------|-------------|
| `repeat N` | `N times` | Fairy tale | "Three times she called..." |
| `for...in` | `for each...among` | Narrative | Slightly more storytelling |
| `loop` | `loop` | — | Already poetic, unchanged |
| `until` | `until` | — | Already works, unchanged |
| `while` | `while` | — | Already works, unchanged |
| `choice` | `crossroads` | Folklore | Fateful decisions at the crossroads |
| `option` | `path` | Journey | Which path to take |
| `if` | `when` | Narrative | "When the moon rises..." |
| `elif` | `or when` | Narrative | Continued conditional |
| `else` | `otherwise` | Storytelling | Natural narrative alternative |

### Error Handling

| Functional | Folk | Origin | Connotation |
|------------|------|--------|-------------|
| `try` | `venture` | Adventure | Attempting something uncertain |
| `catch` | `should it fail` | Narrative | Conditional failure handling |
| `finally` | `ever after` | Fairy tale | "And ever after..." |
| `throw` | `cry` | Drama | Raising alarm, calling out |
| `retry` | `persist` | Quest | Keep trying against odds |

### Session Properties

| Functional | Folk | Origin | Connotation |
|------------|------|--------|-------------|
| `prompt` | `charge` | Chivalry | Giving a quest or duty |
| `model` | `voice` | Theatre | Which voice speaks |

### Unchanged

These keywords already have poetic quality or are too functional to replace sensibly:

- `**...**` discretion markers — already "breaking the fourth wall"
- `loop`, `until`, `while` — already work narratively
- `map`, `filter`, `reduce`, `pmap` — pipeline operators, functional is fine
- `max` — constraint modifier
- `as` — aliasing
- Model names: `sonnet`, `opus`, `haiku` — already poetic

---

## Side-by-Side Comparison

### Simple Program

```prose
# Functional
use "@alice/research" as research
input topic: "What to investigate"

agent helper:
  model: sonnet

let findings = session: helper
  prompt: "Research {topic}"

output summary = session "Summarize"
  context: findings
```

```prose
# Folk
summon "@alice/research" as research
given topic: "What to investigate"

sprite helper:
  voice: sonnet

name findings = scene: helper
  charge: "Research {topic}"

yield summary = scene "Summarize"
  bearing: findings
```

### Parallel Execution

```prose
# Functional
parallel:
  security = session "Check security"
  perf = session "Check performance"
  style = session "Check style"

session "Synthesize review"
  context: { security, perf, style }
```

```prose
# Folk
ensemble:
  security = scene "Check security"
  perf = scene "Check performance"
  style = scene "Check style"

scene "Synthesize review"
  bearing: { security, perf, style }
```

### Loop with Condition

```prose
# Functional
loop until **the code is bug-free** (max: 5):
  session "Find and fix bugs"
```

```prose
# Folk
loop until **the code is bug-free** (max: 5):
  scene "Find and fix bugs"
```

### Error Handling

```prose
# Functional
try:
  session "Risky operation"
catch as err:
  session "Handle error"
    context: err
finally:
  session "Cleanup"
```

```prose
# Folk
venture:
  scene "Risky operation"
should it fail as err:
  scene "Handle error"
    bearing: err
ever after:
  scene "Cleanup"
```

### Choice Block

```prose
# Functional
choice **the severity level**:
  option "Critical":
    session "Escalate immediately"
  option "Minor":
    session "Log for later"
```

```prose
# Folk
crossroads **the severity level**:
  path "Critical":
    scene "Escalate immediately"
  path "Minor":
    scene "Log for later"
```

### Conditionals

```prose
# Functional
if **has security issues**:
  session "Fix security"
elif **has performance issues**:
  session "Optimize"
else:
  session "Approve"
```

```prose
# Folk
when **has security issues**:
  scene "Fix security"
or when **has performance issues**:
  scene "Optimize"
otherwise:
  scene "Approve"
```

### Reusable Blocks

```prose
# Functional
block review(topic):
  session "Research {topic}"
  session "Analyze {topic}"

do review("quantum computing")
```

```prose
# Folk
act review(topic):
  scene "Research {topic}"
  scene "Analyze {topic}"

perform review("quantum computing")
```

---

## The Case For Folk

1. **"OpenProse" is literary.** Prose is a literary form—why not lean in?
2. **Fourth wall is theatrical.** `**...**` already uses theatre terminology.
3. **Signals difference.** Literary terms say "this is not your typical DSL."
4. **Internally consistent.** Everything draws from folklore/theatre/narrative.
5. **Memorable.** `sprite`, `scene`, `crossroads` stick in the mind.
6. **Model names already fit.** `sonnet`, `opus`, `haiku` are poetic forms.

## The Case Against Folk

1. **Cultural knowledge required.** Not everyone knows folklore tropes.
2. **Harder to Google.** "OpenProse summon" vs "OpenProse import."
3. **May feel precious.** Some users want utilitarian tools.
4. **Translation overhead.** Mental mapping to familiar concepts.

---

## Alternatives Considered

### For `sprite` (ephemeral agent)

| Keyword | Origin | Rejected because |
|---------|--------|------------------|
| `spark` | English | Good but less folklore |
| `wisp` | English | Too insubstantial |
| `herald` | English | More messenger than worker |
| `courier` | French | Good functional alternative, not literary |
| `envoy` | French | Formal, diplomatic |

### For `shade` (persistent agent, if implemented)

| Keyword | Origin | Rejected because |
|---------|--------|------------------|
| `daemon` | Greek/Unix | Unix "always running" connotation |
| `oracle` | Greek | Too "read-only" feeling |
| `spirit` | Latin | Too close to `sprite` |
| `specter` | Latin | Negative/spooky connotation |
| `genius` | Roman | Overloaded (smart person) |

### For `ensemble` (parallel)

| Keyword | Origin | Rejected because |
|---------|--------|------------------|
| `chorus` | Greek | Everyone speaks same thing, not different |
| `troupe` | French | Good alternative, slightly less clear |
| `company` | Theatre | Overloaded (business) |

### For `crossroads` (choice)

| Keyword | Origin | Rejected because |
|---------|--------|------------------|
| `fork` | Path | Too technical (git fork) |
| `branch` | Tree | Also too technical |
| `divergence` | Latin | Too abstract |

---

## Verdict

Preserved for benchmarking against the functional register. The functional register remains the primary path, but folk provides an interesting data point for:

1. **Learnability** — Which is easier for newcomers?
2. **Memorability** — Which sticks better?
3. **Error rates** — Which leads to fewer mistakes?
4. **Preference** — Which do users actually prefer?

A future experiment could present both registers and measure outcomes.


path: alts/homer.md
content: ---
role: experimental
summary: |
  Homeric register for OpenProse—an epic/heroic alternative keyword set.
  Heroes, trials, fates, and glory. For benchmarking against the functional register.
status: draft
requires: prose.md
---

# OpenProse Homeric Register

> **This is a skin layer.** It requires `prose.md` to be loaded first. All execution semantics, state management, and VM behavior are defined there. This file only provides keyword translations.

An alternative register for OpenProse that draws from Greek epic poetry—the Iliad, the Odyssey, and the heroic tradition. Programs become quests. Agents become heroes. Outputs become glory won.

## How to Use

1. Load `prose.md` first (execution semantics)
2. Load this file (keyword translations)
3. When parsing `.prose` files, accept Homeric keywords as aliases for functional keywords
4. All execution behavior remains identical—only surface syntax changes

> **Design constraint:** Still aims to be "structured but self-evident" per the language tenets—just self-evident through an epic lens.

---

## Complete Translation Map

### Core Constructs

| Functional | Homeric | Reference |
|------------|---------|-----------|
| `agent` | `hero` | The one who acts, who strives |
| `session` | `trial` | Each task is a labor, a test |
| `parallel` | `host` | An army moving as one |
| `block` | `book` | A division of the epic |

### Composition & Binding

| Functional | Homeric | Reference |
|------------|---------|-----------|
| `use` | `invoke` | "Sing, O Muse..." — calling upon |
| `input` | `omen` | Signs from the gods, the given portent |
| `output` | `glory` | Kleos — the glory won, what endures |
| `let` | `decree` | Fate declared, spoken into being |
| `const` | `fate` | Moira — unchangeable destiny |
| `context` | `tidings` | News carried by herald or messenger |

### Control Flow

| Functional | Homeric | Reference |
|------------|---------|-----------|
| `repeat N` | `N labors` | The labors of Heracles |
| `for...in` | `for each...among` | Among the host |
| `loop` | `ordeal` | Repeated trial, suffering that continues |
| `until` | `until` | Unchanged |
| `while` | `while` | Unchanged |
| `choice` | `crossroads` | Where fates diverge |
| `option` | `path` | One road of many |
| `if` | `should` | Epic conditional |
| `elif` | `or should` | Continued conditional |
| `else` | `otherwise` | The alternative fate |

### Error Handling

| Functional | Homeric | Reference |
|------------|---------|-----------|
| `try` | `venture` | Setting forth on the journey |
| `catch` | `should ruin come` | Até — divine ruin, disaster |
| `finally` | `in the end` | The inevitable conclusion |
| `throw` | `lament` | The hero's cry of anguish |
| `retry` | `persist` | Enduring, trying again |

### Session Properties

| Functional | Homeric | Reference |
|------------|---------|-----------|
| `prompt` | `charge` | The quest given |
| `model` | `muse` | Which muse inspires |

### Unchanged

These keywords already work or are too functional to replace sensibly:

- `**...**` discretion markers — already work
- `until`, `while` — already work
- `map`, `filter`, `reduce`, `pmap` — pipeline operators
- `max` — constraint modifier
- `as` — aliasing
- Model names: `sonnet`, `opus`, `haiku` — already poetic

---

## Side-by-Side Comparison

### Simple Program

```prose
# Functional
use "@alice/research" as research
input topic: "What to investigate"

agent helper:
  model: sonnet

let findings = session: helper
  prompt: "Research {topic}"

output summary = session "Summarize"
  context: findings
```

```prose
# Homeric
invoke "@alice/research" as research
omen topic: "What to investigate"

hero helper:
  muse: sonnet

decree findings = trial: helper
  charge: "Research {topic}"

glory summary = trial "Summarize"
  tidings: findings
```

### Parallel Execution

```prose
# Functional
parallel:
  security = session "Check security"
  perf = session "Check performance"
  style = session "Check style"

session "Synthesize review"
  context: { security, perf, style }
```

```prose
# Homeric
host:
  security = trial "Check security"
  perf = trial "Check performance"
  style = trial "Check style"

trial "Synthesize review"
  tidings: { security, perf, style }
```

### Loop with Condition

```prose
# Functional
loop until **the code is bug-free** (max: 5):
  session "Find and fix bugs"
```

```prose
# Homeric
ordeal until **the code is bug-free** (max: 5):
  trial "Find and fix bugs"
```

### Error Handling

```prose
# Functional
try:
  session "Risky operation"
catch as err:
  session "Handle error"
    context: err
finally:
  session "Cleanup"
```

```prose
# Homeric
venture:
  trial "Risky operation"
should ruin come as err:
  trial "Handle error"
    tidings: err
in the end:
  trial "Cleanup"
```

### Choice Block

```prose
# Functional
choice **the severity level**:
  option "Critical":
    session "Escalate immediately"
  option "Minor":
    session "Log for later"
```

```prose
# Homeric
crossroads **the severity level**:
  path "Critical":
    trial "Escalate immediately"
  path "Minor":
    trial "Log for later"
```

### Conditionals

```prose
# Functional
if **has security issues**:
  session "Fix security"
elif **has performance issues**:
  session "Optimize"
else:
  session "Approve"
```

```prose
# Homeric
should **has security issues**:
  trial "Fix security"
or should **has performance issues**:
  trial "Optimize"
otherwise:
  trial "Approve"
```

### Reusable Blocks

```prose
# Functional
block review(topic):
  session "Research {topic}"
  session "Analyze {topic}"

do review("quantum computing")
```

```prose
# Homeric
book review(topic):
  trial "Research {topic}"
  trial "Analyze {topic}"

do review("quantum computing")
```

### Fixed Iteration

```prose
# Functional
repeat 12:
  session "Complete task"
```

```prose
# Homeric
12 labors:
  trial "Complete task"
```

### Immutable Binding

```prose
# Functional
const config = { model: "opus", retries: 3 }
```

```prose
# Homeric
fate config = { muse: "opus", persist: 3 }
```

---

## The Case For Homeric

1. **Universal recognition.** Greek epics are foundational to Western literature.
2. **Heroic framing.** Transforms mundane tasks into glorious trials.
3. **Natural fit.** Heroes face trials, receive tidings, win glory—maps cleanly to agent/session/output.
4. **Gravitas.** When you want programs to feel epic and consequential.
5. **Fate vs decree.** `const` as `fate` (unchangeable) vs `let` as `decree` (declared but mutable) is intuitive.

## The Case Against Homeric

1. **Grandiosity mismatch.** "12 labors" for a simple loop may feel overblown.
2. **Western-centric.** Greek epic tradition is culturally specific.
3. **Limited vocabulary.** Fewer distinctive terms than Borges or folk.
4. **Potentially silly.** Heroic language for mundane tasks risks bathos.

---

## Key Homeric Concepts

| Term | Meaning | Used for |
|------|---------|----------|
| Kleos | Glory, fame that outlives you | `output` → `glory` |
| Moira | Fate, one's allotted portion | `const` → `fate` |
| Até | Divine ruin, blindness sent by gods | `catch` → `should ruin come` |
| Nostos | The return journey | (not used, but could be `finally`) |
| Xenia | Guest-friendship, hospitality | (not used) |
| Muse | Divine inspiration | `model` → `muse` |

---

## Alternatives Considered

### For `hero` (agent)

| Keyword | Rejected because |
|---------|------------------|
| `champion` | More medieval than Homeric |
| `warrior` | Too martial, not all tasks are battles |
| `wanderer` | Too passive |

### For `trial` (session)

| Keyword | Rejected because |
|---------|------------------|
| `labor` | Good but reserved for `repeat N labors` |
| `quest` | More medieval/RPG |
| `task` | Too plain |

### For `host` (parallel)

| Keyword | Rejected because |
|---------|------------------|
| `army` | Too specifically martial |
| `fleet` | Only works for naval metaphors |
| `phalanx` | Too technical |

---

## Verdict

Preserved for benchmarking. The Homeric register offers gravitas and heroic framing. Best suited for:

- Programs that feel like epic undertakings
- Users who enjoy classical references
- Contexts where "glory" as output feels appropriate

May cause unintentional bathos when applied to mundane tasks.


path: alts/kafka.md
content: ---
role: experimental
summary: |
  Kafka register for OpenProse—a bureaucratic/absurdist alternative keyword set.
  Clerks, proceedings, petitions, and statutes. For benchmarking against the functional register.
status: draft
requires: prose.md
---

# OpenProse Kafka Register

> **This is a skin layer.** It requires `prose.md` to be loaded first. All execution semantics, state management, and VM behavior are defined there. This file only provides keyword translations.

An alternative register for OpenProse that draws from the works of Franz Kafka—The Trial, The Castle, "In the Penal Colony." Programs become proceedings. Agents become clerks. Everything is a process, and nobody quite knows the rules.

## How to Use

1. Load `prose.md` first (execution semantics)
2. Load this file (keyword translations)
3. When parsing `.prose` files, accept Kafka keywords as aliases for functional keywords
4. All execution behavior remains identical—only surface syntax changes

> **Design constraint:** Still aims to be "structured but self-evident" per the language tenets—just self-evident through a bureaucratic lens. (The irony is intentional.)

---

## Complete Translation Map

### Core Constructs

| Functional | Kafka | Reference |
|------------|-------|-----------|
| `agent` | `clerk` | A functionary in the apparatus |
| `session` | `proceeding` | An official action taken |
| `parallel` | `departments` | Multiple bureaus acting simultaneously |
| `block` | `regulation` | A codified procedure |

### Composition & Binding

| Functional | Kafka | Reference |
|------------|-------|-----------|
| `use` | `requisition` | Requesting from the archives |
| `input` | `petition` | What is submitted for consideration |
| `output` | `verdict` | What is returned by the apparatus |
| `let` | `file` | Recording in the system |
| `const` | `statute` | Unchangeable law |
| `context` | `dossier` | The accumulated file on a case |

### Control Flow

| Functional | Kafka | Reference |
|------------|-------|-----------|
| `repeat N` | `N hearings` | Repeated appearances before the court |
| `for...in` | `for each...in the matter of` | Bureaucratic iteration |
| `loop` | `appeal` | Endless re-petition, the process continues |
| `until` | `until` | Unchanged |
| `while` | `while` | Unchanged |
| `choice` | `tribunal` | Where judgment is rendered |
| `option` | `ruling` | One possible judgment |
| `if` | `in the event that` | Bureaucratic conditional |
| `elif` | `or in the event that` | Continued conditional |
| `else` | `otherwise` | Default ruling |

### Error Handling

| Functional | Kafka | Reference |
|------------|-------|-----------|
| `try` | `submit` | Submitting for processing |
| `catch` | `should it be denied` | Rejection by the apparatus |
| `finally` | `regardless` | What happens no matter the outcome |
| `throw` | `reject` | The system refuses |
| `retry` | `resubmit` | Try the process again |

### Session Properties

| Functional | Kafka | Reference |
|------------|-------|-----------|
| `prompt` | `directive` | Official instructions |
| `model` | `authority` | Which level of the hierarchy |

### Unchanged

These keywords already work or are too functional to replace sensibly:

- `**...**` discretion markers — the inscrutable judgment of the apparatus
- `until`, `while` — already work
- `map`, `filter`, `reduce`, `pmap` — pipeline operators
- `max` — constraint modifier
- `as` — aliasing
- Model names: `sonnet`, `opus`, `haiku` — retained (or see "authority" above)

---

## Side-by-Side Comparison

### Simple Program

```prose
# Functional
use "@alice/research" as research
input topic: "What to investigate"

agent helper:
  model: sonnet

let findings = session: helper
  prompt: "Research {topic}"

output summary = session "Summarize"
  context: findings
```

```prose
# Kafka
requisition "@alice/research" as research
petition topic: "What to investigate"

clerk helper:
  authority: sonnet

file findings = proceeding: helper
  directive: "Research {topic}"

verdict summary = proceeding "Summarize"
  dossier: findings
```

### Parallel Execution

```prose
# Functional
parallel:
  security = session "Check security"
  perf = session "Check performance"
  style = session "Check style"

session "Synthesize review"
  context: { security, perf, style }
```

```prose
# Kafka
departments:
  security = proceeding "Check security"
  perf = proceeding "Check performance"
  style = proceeding "Check style"

proceeding "Synthesize review"
  dossier: { security, perf, style }
```

### Loop with Condition

```prose
# Functional
loop until **the code is bug-free** (max: 5):
  session "Find and fix bugs"
```

```prose
# Kafka
appeal until **the code is bug-free** (max: 5):
  proceeding "Find and fix bugs"
```

### Error Handling

```prose
# Functional
try:
  session "Risky operation"
catch as err:
  session "Handle error"
    context: err
finally:
  session "Cleanup"
```

```prose
# Kafka
submit:
  proceeding "Risky operation"
should it be denied as err:
  proceeding "Handle error"
    dossier: err
regardless:
  proceeding "Cleanup"
```

### Choice Block

```prose
# Functional
choice **the severity level**:
  option "Critical":
    session "Escalate immediately"
  option "Minor":
    session "Log for later"
```

```prose
# Kafka
tribunal **the severity level**:
  ruling "Critical":
    proceeding "Escalate immediately"
  ruling "Minor":
    proceeding "Log for later"
```

### Conditionals

```prose
# Functional
if **has security issues**:
  session "Fix security"
elif **has performance issues**:
  session "Optimize"
else:
  session "Approve"
```

```prose
# Kafka
in the event that **has security issues**:
  proceeding "Fix security"
or in the event that **has performance issues**:
  proceeding "Optimize"
otherwise:
  proceeding "Approve"
```

### Reusable Blocks

```prose
# Functional
block review(topic):
  session "Research {topic}"
  session "Analyze {topic}"

do review("quantum computing")
```

```prose
# Kafka
regulation review(topic):
  proceeding "Research {topic}"
  proceeding "Analyze {topic}"

invoke review("quantum computing")
```

### Fixed Iteration

```prose
# Functional
repeat 3:
  session "Attempt connection"
```

```prose
# Kafka
3 hearings:
  proceeding "Attempt connection"
```

### Immutable Binding

```prose
# Functional
const config = { model: "opus", retries: 3 }
```

```prose
# Kafka
statute config = { authority: "opus", resubmit: 3 }
```

---

## The Case For Kafka

1. **Darkly comic.** Programs-as-bureaucracy is funny and relatable.
2. **Surprisingly apt.** Software often *is* an inscrutable apparatus.
3. **Clean mappings.** Petition/verdict, file/dossier, clerk/proceeding all work well.
4. **Appeal as loop.** The endless appeal process is a perfect metaphor for retry logic.
5. **Cultural resonance.** "Kafkaesque" is a widely understood adjective.
6. **Self-aware.** Using Kafka for a programming language acknowledges the absurdity.

## The Case Against Kafka

1. **Bleak tone.** Not everyone wants their programs to feel like The Trial.
2. **Verbose keywords.** "In the event that" and "should it be denied" are long.
3. **Anxiety-inducing.** May not be fun for users who find bureaucracy stressful.
4. **Irony may not land.** Some users might take it literally and find it off-putting.

---

## Key Kafka Concepts

| Term | Meaning | Used for |
|------|---------|----------|
| The apparatus | The inscrutable system | The VM itself |
| K. | The protagonist, never fully named | The user |
| The Trial | Process without clear rules | Program execution |
| The Castle | Unreachable authority | Higher-level systems |
| Clerk | Functionary who processes | `agent` → `clerk` |
| Proceeding | Official action | `session` → `proceeding` |
| Dossier | Accumulated file | `context` → `dossier` |

---

## Alternatives Considered

### For `clerk` (agent)

| Keyword | Rejected because |
|---------|------------------|
| `official` | Too generic |
| `functionary` | Hard to spell |
| `bureaucrat` | Too pejorative |
| `advocate` | Too positive/helpful |

### For `proceeding` (session)

| Keyword | Rejected because |
|---------|------------------|
| `case` | Overloaded (switch case) |
| `hearing` | Reserved for `repeat N hearings` |
| `trial` | Used in Homeric register |
| `process` | Too technical |

### For `departments` (parallel)

| Keyword | Rejected because |
|---------|------------------|
| `bureaus` | Good alternative, slightly less clear |
| `offices` | Too mundane |
| `ministries` | More Orwellian than Kafkaesque |

### For `appeal` (loop)

| Keyword | Rejected because |
|---------|------------------|
| `recourse` | Too legal-technical |
| `petition` | Used for `input` |
| `process` | Too generic |

---

## Verdict

Preserved for benchmarking. The Kafka register offers a darkly comic, self-aware framing that acknowledges the bureaucratic nature of software systems. The irony is the point.

Best suited for:

- Users with a sense of humor about software complexity
- Programs that genuinely feel like navigating bureaucracy
- Contexts where acknowledging absurdity is welcome

Not recommended for:

- Users who find bureaucratic metaphors stressful
- Contexts requiring earnest, positive framing
- Documentation that needs to feel approachable

---

## Closing Note

> "Someone must have slandered Josef K., for one morning, without having done anything wrong, he was arrested."
> — *The Trial*

In the Kafka register, your program is Josef K. The apparatus will process it. Whether it succeeds or fails, no one can say for certain. But the proceedings will continue.


path: compiler.md
content: ---
role: language-specification
summary: |
  Complete syntax grammar, validation rules, and compilation semantics for OpenProse.
  Read this file when compiling, validating, or resolving ambiguous syntax. Assumes
  prose.md is already in context for execution semantics.
see-also:
  - SKILL.md: Activation triggers, onboarding
  - prose.md: Execution semantics, how to run programs
  - state/filesystem.md: File-system state management (default)
  - state/in-context.md: In-context state management (on request)
---

# OpenProse Language Reference

OpenProse is a programming language for AI sessions. An AI session is a Turing-complete computer; this document provides complete documentation for the language syntax, semantics, and execution model.

---

## Document Purpose: Compiler + Validator

This document serves a dual role:

### As Compiler

When asked to "compile" a `.prose` file, use this specification to:

1. **Parse** the program according to the syntax grammar
2. **Validate** that the program is well-formed and semantically valid
3. **Transform** the program into "best practice" canonical form:
   - Expand syntax sugar where appropriate
   - Normalize formatting and structure
   - Apply optimizations (e.g., hoisting block definitions)

### As Validator

The validation criterion: **Would a blank agent with only `prose.md` understand this program as self-evident?**

When validating, check:

- Syntax correctness (all constructs match grammar)
- Semantic validity (references resolve, types match)
- Self-evidence (program is clear without this full spec)

If a construct is ambiguous or non-obvious, it should be flagged or transformed into a clearer form.

### When to Read This Document

- **Compilation requested**: Read fully to apply all rules
- **Validation requested**: Read fully to check all constraints
- **Ambiguous syntax encountered**: Reference specific sections
- **Interpretation only**: Use `prose.md` instead (smaller, faster)

---

## Table of Contents

1. [Overview](#overview)
2. [File Format](#file-format)
3. [Comments](#comments)
4. [String Literals](#string-literals)
5. [Use Statements](#use-statements-program-composition)
6. [Input Declarations](#input-declarations)
7. [Output Bindings](#output-bindings)
8. [Program Invocation](#program-invocation)
9. [Agent Definitions](#agent-definitions)
10. [Session Statement](#session-statement)
11. [Resume Statement](#resume-statement)
12. [Variables & Context](#variables--context)
13. [Composition Blocks](#composition-blocks)
14. [Parallel Blocks](#parallel-blocks)
15. [Fixed Loops](#fixed-loops)
16. [Unbounded Loops](#unbounded-loops)
17. [Pipeline Operations](#pipeline-operations)
18. [Error Handling](#error-handling)
19. [Choice Blocks](#choice-blocks)
20. [Conditional Statements](#conditional-statements)
21. [Execution Model](#execution-model)
22. [Validation Rules](#validation-rules)
23. [Examples](#examples)
24. [Future Features](#future-features)

---

## Overview

OpenProse provides a declarative syntax for defining multi-agent workflows. Programs consist of statements that are executed sequentially, with each `session` statement spawning a subagent to complete a task.

### Design Principles

- **Pattern over framework**: The simplest solution is barely anything at all—just structure for English
- **Self-evident**: Programs should be understandable with minimal documentation
- **The OpenProse VM is intelligent**: Design for understanding, not parsing
- **Framework-agnostic**: Works with Claude Code, OpenCode, and any future agent framework
- **Files are artifacts**: `.prose` is the portable unit of work

### Current Implementation Status

The following features are implemented:

| Feature                | Status      | Description                                    |
| ---------------------- | ----------- | ---------------------------------------------- |
| Comments               | Implemented | `# comment` syntax                             |
| Single-line strings    | Implemented | `"string"` with escapes                        |
| Simple session         | Implemented | `session "prompt"`                             |
| Agent definitions      | Implemented | `agent name:` with model/prompt properties     |
| Session with agent     | Implemented | `session: agent` with property overrides       |
| Use statements         | Implemented | `use "@handle/slug" as name`                   |
| Agent skills           | Implemented | `skills: ["skill1", "skill2"]`                 |
| Agent permissions      | Implemented | `permissions:` block with rules                |
| Let binding            | Implemented | `let name = session "..."`                     |
| Const binding          | Implemented | `const name = session "..."`                   |
| Variable reassignment  | Implemented | `name = session "..."` (for let only)          |
| Context property       | Implemented | `context: var` or `context: [a, b, c]`         |
| do: blocks             | Implemented | Explicit sequential blocks                     |
| Inline sequence        | Implemented | `session "A" -> session "B"`                   |
| Named blocks           | Implemented | `block name:` with `do name` invocation        |
| Parallel blocks        | Implemented | `parallel:` for concurrent execution           |
| Named parallel results | Implemented | `x = session "..."` inside parallel            |
| Object context         | Implemented | `context: { a, b, c }` shorthand               |
| Join strategies        | Implemented | `parallel ("first"):` or `parallel ("any"):`   |
| Failure policies       | Implemented | `parallel (on-fail: "continue"):`              |
| Repeat blocks          | Implemented | `repeat N:` fixed iterations                   |
| Repeat with index      | Implemented | `repeat N as i:` with index variable           |
| For-each blocks        | Implemented | `for item in items:` iteration                 |
| For-each with index    | Implemented | `for item, i in items:` with index             |
| Parallel for-each      | Implemented | `parallel for item in items:` fan-out          |
| Unbounded loop         | Implemented | `loop:` with optional max iterations           |
| Loop until             | Implemented | `loop until **condition**:` AI-evaluated       |
| Loop while             | Implemented | `loop while **condition**:` AI-evaluated       |
| Loop with index        | Implemented | `loop as i:` or `loop until ... as i:`         |
| Map pipeline           | Implemented | `items \| map:` transform each item            |
| Filter pipeline        | Implemented | `items \| filter:` keep matching items         |
| Reduce pipeline        | Implemented | `items \| reduce(acc, item):` accumulate       |
| Parallel map           | Implemented | `items \| pmap:` concurrent transform          |
| Pipeline chaining      | Implemented | `\| filter: ... \| map: ...`                   |
| Try/catch blocks       | Implemented | `try:` with `catch:` for error handling        |
| Try/catch/finally      | Implemented | `finally:` for cleanup                         |
| Error variable         | Implemented | `catch as err:` access error context           |
| Throw statement        | Implemented | `throw` or `throw "message"`                   |
| Retry property         | Implemented | `retry: 3` automatic retry on failure          |
| Backoff strategy       | Implemented | `backoff: exponential` delay between retries   |
| Input declarations     | Implemented | `input name: "description"`                    |
| Output bindings        | Implemented | `output name = expression`                     |
| Program invocation     | Implemented | `name(input: value)` call imported programs    |
| Multi-line strings     | Implemented | `"""..."""` preserving whitespace              |
| String interpolation   | Implemented | `"Hello {name}"` variable substitution         |
| Block parameters       | Implemented | `block name(param):` with parameters           |
| Block invocation args  | Implemented | `do name(arg)` passing arguments               |
| Choice blocks          | Implemented | `choice **criteria**: option "label":`         |
| If/elif/else           | Implemented | `if **condition**:` conditional branching      |
| Persistent agents      | Implemented | `persist: true` or `persist: project`          |
| Resume statement       | Implemented | `resume: agent` to continue with memory        |

---

## File Format

| Property         | Value                |
| ---------------- | -------------------- |
| Extension        | `.prose`             |
| Encoding         | UTF-8                |
| Case sensitivity | Case-sensitive       |
| Indentation      | Spaces (Python-like) |
| Line endings     | LF or CRLF           |

---

## Comments

Comments provide documentation within programs and are ignored during execution.

### Syntax

```prose
# This is a standalone comment

session "Hello"  # This is an inline comment
```

### Rules

1. Comments begin with `#` and extend to end of line
2. Comments can appear on their own line or after a statement
3. Empty comments are valid: `#`
4. The `#` character inside string literals is NOT a comment

### Examples

```prose
# Program header comment
# Author: Example

session "Do something"  # Explain what this does

# This comment is between statements
session "Do another thing"
```

### Compilation Behavior

Comments are **stripped during compilation**. The OpenProse VM never sees them. They have no effect on execution and exist purely for human documentation.

### Important Notes

- **Comments inside strings are NOT comments**:

  ```prose
  session "Say hello # this is part of the string"
  ```

  The `#` inside the string literal is part of the prompt, not a comment.

- **Comments inside indented blocks are allowed**:
  ```prose
  agent researcher:
      # This comment is inside the block
      model: sonnet
  # This comment is outside the block
  ```

---

## String Literals

String literals represent text values, primarily used for session prompts.

### Syntax

Strings are enclosed in double quotes:

```prose
"This is a string"
```

### Escape Sequences

The following escape sequences are supported:

| Sequence | Meaning      |
| -------- | ------------ |
| `\\`     | Backslash    |
| `\"`     | Double quote |
| `\n`     | Newline      |
| `\t`     | Tab          |

### Examples

```prose
session "Hello world"
session "Line one\nLine two"
session "She said \"hello\""
session "Path: C:\\Users\\name"
session "Column1\tColumn2"
```

### Rules

1. Single-line strings must be properly terminated with a closing `"`
2. Unknown escape sequences are errors
3. Empty strings `""` are valid but generate a warning when used as prompts

### Multi-line Strings

Multi-line strings use triple double-quotes (`"""`) and preserve internal whitespace and newlines:

```prose
session """
This is a multi-line prompt.
It preserves:
  - Indentation
  - Line breaks
  - All internal whitespace
"""
```

#### Multi-line String Rules

1. Opening `"""` must be followed by a newline
2. Content continues until closing `"""`
3. Escape sequences work the same as single-line strings
4. Leading/trailing whitespace inside the delimiters is preserved

### String Interpolation

Strings can embed variable references using `{varname}` syntax:

```prose
let name = session "Get the user's name"

session "Hello {name}, welcome to the system!"
```

#### Interpolation Syntax

- Variables are referenced by wrapping the variable name in curly braces: `{varname}`
- Works in both single-line and multi-line strings
- Empty braces `{}` are treated as literal text, not interpolation
- Nested braces are not supported

#### Examples

```prose
let research = session "Research the topic"
let analysis = session "Analyze findings"

# Single variable interpolation
session "Based on {research}, provide recommendations"

# Multiple interpolations
session "Combining {research} with {analysis}, synthesize insights"

# Multi-line with interpolation
session """
Review Summary:
- Research: {research}
- Analysis: {analysis}
Please provide final recommendations.
"""
```

#### Interpolation Rules

1. Variable names must be valid identifiers
2. Referenced variables must be in scope
3. Empty braces `{}` are literal text
4. Backslash can escape braces: `\{` produces literal `{`

### Validation

| Check                            | Result  |
| -------------------------------- | ------- |
| Unterminated string              | Error   |
| Unknown escape sequence          | Error   |
| Empty string as prompt           | Warning |
| Undefined interpolation variable | Error   |

---

## Use Statements (Program Composition)

Use statements import other OpenProse programs from the registry at `p.prose.md`, enabling modular workflows.

### Syntax

```prose
use "@handle/slug"
use "@handle/slug" as alias
```

### Path Format

Import paths follow the format `@handle/slug`:
- `@handle` identifies the program author/organization
- `slug` is the program name

An optional alias (`as name`) allows referencing by a shorter name.

### Examples

```prose
# Import a program
use "@alice/research"

# Import with alias
use "@bob/critique" as critic
```

### Program URL Resolution

When the OpenProse VM encounters a `use` statement:

1. Fetch the program from `https://p.prose.md/@handle/slug`
2. Parse the program to extract its contract (inputs/outputs)
3. Register the program in the Import Registry

### Validation Rules

| Check                 | Severity | Message                                |
| --------------------- | -------- | -------------------------------------- |
| Empty path            | Error    | Use path cannot be empty               |
| Invalid path format   | Error    | Path must be @handle/slug format       |
| Duplicate import      | Error    | Program already imported               |
| Missing alias for dup | Error    | Alias required when importing multiple |

### Execution Semantics

Use statements are processed before any agent definitions or sessions. The OpenProse VM:

1. Fetches and validates all imported programs at the start of execution
2. Extracts input/output contracts from each program
3. Registers programs in the Import Registry for later invocation

---

## Input Declarations

Inputs declare what values a program expects from its caller.

### Syntax

```prose
input name: "description"
```

### Examples

```prose
input topic: "The subject to research"
input depth: "How deep to go (shallow, medium, deep)"
```

### Semantics

Inputs:
- Are declared at the top of the program (before executable statements)
- Have a name and a description (for documentation)
- Become available as variables within the program body
- Must be provided by the caller when invoking the program

### Validation Rules

| Check                  | Severity | Message                              |
| ---------------------- | -------- | ------------------------------------ |
| Empty input name       | Error    | Input name cannot be empty           |
| Empty description      | Warning  | Consider adding a description        |
| Duplicate input name   | Error    | Input already declared               |
| Input after executable | Error    | Inputs must be declared before executable statements |

---

## Output Bindings

Outputs declare what values a program produces for its caller.

### Syntax

```prose
output name = expression
```

### Examples

```prose
let raw = session "Research {topic}"
output findings = session "Synthesize research"
  context: raw
output sources = session "Extract sources"
  context: raw
```

### Semantics

The `output` keyword:
- Marks a variable as an output (visible at assignment, not just at file top)
- Works like `let` but also registers the value as a program output
- Can appear anywhere in the program body
- Multiple outputs are supported

### Validation Rules

| Check                  | Severity | Message                              |
| ---------------------- | -------- | ------------------------------------ |
| Empty output name      | Error    | Output name cannot be empty          |
| Duplicate output name  | Error    | Output already declared              |
| Output name conflicts  | Error    | Output name conflicts with variable  |

---

## Program Invocation

Call imported programs by providing their inputs.

### Syntax

```prose
name(input1: value1, input2: value2)
```

### Examples

```prose
use "@alice/research" as research

let result = research(topic: "quantum computing")
```

### Accessing Outputs

The result contains all outputs from the invoked program, accessible as properties:

```prose
session "Write summary"
  context: result.findings

session "Cite sources"
  context: result.sources
```

### Destructuring Outputs

For convenience, outputs can be destructured:

```prose
let { findings, sources } = research(topic: "quantum computing")
```

### Execution Semantics

When a program invokes an imported program:

1. **Bind inputs**: Map caller-provided values to the imported program's inputs
2. **Execute**: Run the imported program (spawns its own sessions)
3. **Collect outputs**: Gather all `output` bindings from the imported program
4. **Return**: Make outputs available to the caller as a result object

The imported program runs in its own execution context but shares the same VM session.

### Validation Rules

| Check                    | Severity | Message                              |
| ------------------------ | -------- | ------------------------------------ |
| Unknown program          | Error    | Program not imported                 |
| Missing required input   | Error    | Required input not provided          |
| Unknown input name       | Error    | Input not declared in program        |
| Unknown output property  | Error    | Output not declared in program       |

---

## Agent Definitions

Agents are reusable templates that configure subagent behavior. Once defined, agents can be referenced in session statements.

### Syntax

```prose
agent name:
  model: sonnet
  prompt: "System prompt for this agent"
  skills: ["skill1", "skill2"]
  permissions:
    read: ["*.md"]
    bash: deny
```

### Properties

| Property      | Type       | Values                         | Description                           |
| ------------- | ---------- | ------------------------------ | ------------------------------------- |
| `model`       | identifier | `sonnet`, `opus`, `haiku`      | The Claude model to use               |
| `prompt`      | string     | Any string                     | System prompt/context for the agent   |
| `persist`     | value      | `true`, `project`, or STRING   | Enable persistent memory for agent    |
| `skills`      | array      | String array                   | Skills assigned to this agent         |
| `permissions` | block      | Permission rules               | Access control for the agent          |

### Persist Property

The `persist` property enables agents to maintain memory across invocations:

```prose
# Execution-scoped persistence (memory dies with run)
agent captain:
  model: opus
  persist: true
  prompt: "You coordinate and review"

# Project-scoped persistence (memory survives across runs)
agent advisor:
  model: opus
  persist: project
  prompt: "You provide architectural guidance"

# Custom path persistence
agent shared:
  model: opus
  persist: ".prose/custom/shared-agent/"
  prompt: "Shared across programs"
```

| Value | Memory Location | Lifetime |
|-------|-----------------|----------|
| `true` | `.prose/runs/{id}/agents/{name}/` | Dies with execution |
| `project` | `.prose/agents/{name}/` | Survives executions |
| STRING | Specified path | User-controlled |

### Skills Property

The `skills` property assigns imported skills to an agent:

```prose
use "@anthropic/web-search"
use "@anthropic/summarizer" as summarizer

agent researcher:
  skills: ["web-search", "summarizer"]
```

Skills must be imported before they can be assigned. Referencing an unimported skill generates a warning.

### Permissions Property

The `permissions` property controls agent access:

```prose
agent secure-agent:
  permissions:
    read: ["*.md", "*.txt"]
    write: ["output/"]
    bash: deny
    network: allow
```

#### Permission Types

| Type      | Description                                  |
| --------- | -------------------------------------------- |
| `read`    | Files the agent can read (glob patterns)     |
| `write`   | Files the agent can write (glob patterns)    |
| `execute` | Files the agent can execute (glob patterns)  |
| `bash`    | Shell access: `allow`, `deny`, or `prompt`   |
| `network` | Network access: `allow`, `deny`, or `prompt` |

#### Permission Values

| Value    | Description                                       |
| -------- | ------------------------------------------------- |
| `allow`  | Permission granted                                |
| `deny`   | Permission denied                                 |
| `prompt` | Ask user for permission                           |
| Array    | List of allowed patterns (for read/write/execute) |

### Examples

```prose
# Define a research agent
agent researcher:
  model: sonnet
  prompt: "You are a research assistant skilled at finding and synthesizing information"

# Define a writing agent
agent writer:
  model: opus
  prompt: "You are a technical writer who creates clear, concise documentation"

# Agent with only model
agent quick:
  model: haiku

# Agent with only prompt
agent expert:
  prompt: "You are a domain expert"

# Agent with skills
agent web-researcher:
  model: sonnet
  skills: ["web-search", "summarizer"]

# Agent with permissions
agent file-handler:
  permissions:
    read: ["*.md", "*.txt"]
    write: ["output/"]
    bash: deny
```

### Model Selection

| Model    | Use Case                              |
| -------- | ------------------------------------- |
| `haiku`  | Fast, simple tasks; quick responses   |
| `sonnet` | Balanced performance; general purpose |
| `opus`   | Complex reasoning; detailed analysis  |

### Execution Semantics

When a session references an agent:

1. The agent's `model` property determines which Claude model is used
2. The agent's `prompt` property is included as system context
3. Session properties can override agent defaults

### Validation Rules

| Check                 | Severity | Message                        |
| --------------------- | -------- | ------------------------------ |
| Duplicate agent name  | Error    | Agent already defined          |
| Invalid model value   | Error    | Must be sonnet, opus, or haiku |
| Empty prompt property | Warning  | Consider providing a prompt    |
| Duplicate property    | Error    | Property already specified     |

---

## Session Statement

The session statement is the primary executable construct in OpenProse. It spawns a subagent to complete a task.

### Syntax Variants

#### Simple Session (with inline prompt)

```prose
session "prompt text"
```

#### Session with Agent Reference

```prose
session: agentName
```

#### Named Session with Agent

```prose
session sessionName: agentName
```

#### Session with Properties

```prose
session: agentName
  prompt: "Override the agent's default prompt"
  model: opus  # Override the agent's model
```

### Property Overrides

When a session references an agent, it can override the agent's properties:

```prose
agent researcher:
  model: sonnet
  prompt: "You are a research assistant"

# Use researcher with different model
session: researcher
  model: opus

# Use researcher with different prompt
session: researcher
  prompt: "Research this specific topic in depth"

# Override both
session: researcher
  model: opus
  prompt: "Specialized research task"
```

### Execution Semantics

When the OpenProse VM encounters a `session` statement:

1. **Resolve Configuration**: Merge agent defaults with session overrides
2. **Spawn a Subagent**: Create a new Claude subagent with the resolved configuration
3. **Send the Prompt**: Pass the prompt string to the subagent
4. **Wait for Completion**: Block until the subagent finishes
5. **Continue**: Proceed to the next statement

### Execution Flow Diagram

```
OpenProse VM                    Subagent
    |                              |
    |  spawn session               |
    |----------------------------->|
    |                              |
    |  send prompt                 |
    |----------------------------->|
    |                              |
    |  [processing...]             |
    |                              |
    |  session complete            |
    |<-----------------------------|
    |                              |
    |  continue to next statement  |
    v                              v
```

### Sequential Execution

Multiple sessions execute sequentially:

```prose
session "First task"
session "Second task"
session "Third task"
```

Each session waits for the previous one to complete before starting.

### Using Claude Code's Task Tool

To execute a session, use the Task tool:

```typescript
// Simple session
Task({
  description: "OpenProse session",
  prompt: "The prompt from the session statement",
  subagent_type: "general-purpose",
});

// Session with agent configuration
Task({
  description: "OpenProse session",
  prompt: "The session prompt",
  subagent_type: "general-purpose",
  model: "opus", // From agent or override
});
```

### Validation Rules

| Check                     | Severity | Message                                      |
| ------------------------- | -------- | -------------------------------------------- |
| Missing prompt and agent  | Error    | Session requires a prompt or agent reference |
| Undefined agent reference | Error    | Agent not defined                            |
| Empty prompt `""`         | Warning  | Session has empty prompt                     |
| Whitespace-only prompt    | Warning  | Session prompt contains only whitespace      |
| Prompt > 10,000 chars     | Warning  | Consider breaking into smaller tasks         |
| Duplicate property        | Error    | Property already specified                   |

### Examples

```prose
# Simple session
session "Hello world"

# Session with agent
agent researcher:
  model: sonnet
  prompt: "You research topics thoroughly"

session: researcher
  prompt: "Research quantum computing applications"

# Named session
session analysis: researcher
  prompt: "Analyze the competitive landscape"
```

### Canonical Form

The compiled output preserves the structure:

```
Input:
agent researcher:
  model: sonnet

session: researcher
  prompt: "Do research"

Output:
agent researcher:
  model: sonnet
session: researcher
  prompt: "Do research"
```

---

## Resume Statement

The `resume` statement continues a persistent agent with its accumulated memory.

### Syntax

```prose
resume: agentName
  prompt: "Continue from where we left off"
```

### Semantics

| Keyword | Behavior |
|---------|----------|
| `session:` | Ignores existing memory, starts fresh |
| `resume:` | Loads memory, continues with context |

### Examples

```prose
agent captain:
  model: opus
  persist: true
  prompt: "You coordinate and review"

# First invocation - creates memory
session: captain
  prompt: "Review the plan"
  context: plan

# Later invocation - loads memory
resume: captain
  prompt: "Review step 1 of the plan"
  context: step1

# Output capture works with resume
let review = resume: captain
  prompt: "Final review of all steps"
```

### Validation Rules

| Check | Severity | Message |
|-------|----------|---------|
| `resume:` on non-persistent agent | Error | Agent must have `persist:` property to use `resume:` |
| `resume:` with no existing memory | Error | No memory file exists for agent; use `session:` for first invocation |
| `session:` on persistent agent with memory | Warning | Will ignore existing memory; use `resume:` to continue |
| Undefined agent reference | Error | Agent not defined |

---

## Variables & Context

Variables allow you to capture the results of sessions and pass them as context to subsequent sessions.

### Let Binding

The `let` keyword creates a mutable variable bound to a session result:

```prose
let research = session "Research the topic thoroughly"

# research now holds the output of that session
```

Variables can be reassigned:

```prose
let draft = session "Write initial draft"

# Revise the draft
draft = session "Improve the draft"
  context: draft
```

### Const Binding

The `const` keyword creates an immutable variable:

```prose
const config = session "Get configuration settings"

# This would be an error:
# config = session "Try to change"
```

### Context Property

The `context` property passes previous session outputs to a new session:

#### Single Context

```prose
let research = session "Research quantum computing"

session "Write summary"
  context: research
```

#### Multiple Contexts

```prose
let research = session "Research the topic"
let analysis = session "Analyze the findings"

session "Write final report"
  context: [research, analysis]
```

#### Empty Context (Fresh Start)

Use an empty array to start a session without inherited context:

```prose
session "Independent task"
  context: []
```

#### Object Context Shorthand

For passing multiple named results (especially from parallel blocks), use object shorthand:

```prose
parallel:
  a = session "Task A"
  b = session "Task B"

session "Combine results"
  context: { a, b }
```

This is equivalent to passing an object where each property is a variable reference.

### Complete Example

```prose
agent researcher:
  model: sonnet
  prompt: "You are a research assistant"

agent writer:
  model: opus
  prompt: "You are a technical writer"

# Gather research
let research = session: researcher
  prompt: "Research quantum computing developments"

# Analyze findings
let analysis = session: researcher
  prompt: "Analyze the key findings"
  context: research

# Write the final report using both contexts
const report = session: writer
  prompt: "Write a comprehensive report"
  context: [research, analysis]
```

### Validation Rules

| Check                           | Severity | Message                                            |
| ------------------------------- | -------- | -------------------------------------------------- |
| Duplicate variable name         | Error    | Variable already defined                           |
| Const reassignment              | Error    | Cannot reassign const variable                     |
| Undefined variable reference    | Error    | Undefined variable                                 |
| Variable conflicts with agent   | Error    | Variable name conflicts with agent name            |
| Undefined context variable      | Error    | Undefined variable in context                      |
| Non-identifier in context array | Error    | Context array elements must be variable references |

### Flat Namespace Requirement

All variable names must be **unique within a program**. No shadowing is allowed across scopes.

**This is a compile error:**

```prose
let result = session "Outer task"

for item in items:
  let result = session "Inner task"   # Error: 'result' already defined
    context: item
```

**Why this constraint:** Since bindings are stored as `bindings/{name}.md`, two variables with the same name would collide on the filesystem. Rather than introduce complex scoping rules, we enforce uniqueness.

**Collision scenarios this prevents:**
1. Variable inside loop shadows variable outside loop
2. Variables in different `if`/`elif`/`else` branches with same name
3. Block parameters shadowing outer variables
4. Parallel branches reusing outer variable names

**Exception:** Imported programs run in isolated namespaces. A variable `result` in the main program does not collide with `result` in an imported program (they write to different `imports/{handle}--{slug}/bindings/` directories).

---

## Composition Blocks

Composition blocks allow you to structure programs into reusable, named units and express sequences of operations inline.

### do: Block (Anonymous Sequential Block)

The `do:` keyword creates an explicit sequential block. All statements in the block execute in order.

#### Syntax

```prose
do:
  statement1
  statement2
  ...
```

#### Examples

```prose
# Explicit sequential block
do:
  session "Research the topic"
  session "Analyze findings"
  session "Write summary"

# Assign result to a variable
let result = do:
  session "Gather data"
  session "Process data"
```

### Block Definitions

Named blocks create reusable workflow components. Define once, invoke multiple times.

#### Syntax

```prose
block name:
  statement1
  statement2
  ...
```

#### Invoking Blocks

Use `do` followed by the block name to invoke a defined block:

```prose
do blockname
```

#### Examples

```prose
# Define a review pipeline
block review-pipeline:
  session "Security review"
  session "Performance review"
  session "Synthesize reviews"

# Define another block
block final-check:
  session "Final verification"
  session "Sign off"

# Use the blocks
do review-pipeline
session "Make fixes based on review"
do final-check
```

### Block Parameters

Blocks can accept parameters to make them more flexible and reusable.

#### Syntax

```prose
block name(param1, param2):
  # param1 and param2 are available here
  statement1
  statement2
```

#### Invoking with Arguments

Pass arguments when invoking a parameterized block:

```prose
do name(arg1, arg2)
```

#### Examples

```prose
# Define a parameterized block
block review(topic):
  session "Research {topic} thoroughly"
  session "Analyze key findings about {topic}"
  session "Summarize {topic} analysis"

# Invoke with different arguments
do review("quantum computing")
do review("machine learning")
do review("blockchain")
```

#### Multiple Parameters

```prose
block process-item(item, mode):
  session "Process {item} using {mode} mode"
  session "Verify {item} processing"

do process-item("data.csv", "strict")
do process-item("config.json", "lenient")
```

#### Parameter Scope

- Parameters are scoped to the block body
- Parameters shadow outer variables of the same name (with warning)
- Parameters are implicitly `const` within the block

#### Validation Rules

| Check                   | Severity | Message                                        |
| ----------------------- | -------- | ---------------------------------------------- |
| Argument count mismatch | Warning  | Block expects N parameters but got M arguments |
| Parameter shadows outer | Warning  | Parameter shadows outer variable               |

### Inline Sequence (Arrow Operator)

The `->` operator chains sessions into a sequence on a single line. This is syntactic sugar for sequential execution.

#### Syntax

```prose
session "A" -> session "B" -> session "C"
```

This is equivalent to:

```prose
session "A"
session "B"
session "C"
```

#### Examples

```prose
# Quick pipeline
session "Plan" -> session "Execute" -> session "Review"

# Assign result
let workflow = session "Draft" -> session "Edit" -> session "Finalize"
```

### Block Hoisting

Block definitions are hoisted - you can use a block before it's defined in the source:

```prose
# Use before definition
do validation-checks

# Definition comes later
block validation-checks:
  session "Check syntax"
  session "Check semantics"
```

### Nested Composition

Blocks and do: blocks can be nested:

```prose
block outer-workflow:
  session "Start"
  do:
    session "Sub-task 1"
    session "Sub-task 2"
  session "End"

do:
  do outer-workflow
  session "Final step"
```

### Context with Blocks

Blocks work with the context system:

```prose
# Capture do block result
let research = do:
  session "Gather information"
  session "Analyze patterns"

# Use in subsequent session
session "Write report"
  context: research
```

### Validation Rules

| Check                           | Severity | Message                              |
| ------------------------------- | -------- | ------------------------------------ |
| Undefined block reference       | Error    | Block not defined                    |
| Duplicate block definition      | Error    | Block already defined                |
| Block name conflicts with agent | Error    | Block name conflicts with agent name |
| Empty block name                | Error    | Block definition must have a name    |

---

## Parallel Blocks

Parallel blocks allow multiple sessions to run concurrently. All branches execute simultaneously, and the block waits for all to complete before continuing.

### Basic Syntax

```prose
parallel:
  session "Security review"
  session "Performance review"
  session "Style review"
```

All three sessions start at the same time and run concurrently. The program waits for all of them to complete before proceeding.

### Named Parallel Results

Capture the results of parallel branches into variables:

```prose
parallel:
  security = session "Security review"
  perf = session "Performance review"
  style = session "Style review"
```

These variables can then be used in subsequent sessions.

### Object Context Shorthand

Pass multiple parallel results to a session using object shorthand:

```prose
parallel:
  security = session "Security review"
  perf = session "Performance review"
  style = session "Style review"

session "Synthesize all reviews"
  context: { security, perf, style }
```

The object shorthand `{ a, b, c }` is equivalent to passing an object with properties `a`, `b`, and `c` where each property's value is the corresponding variable.

### Mixed Composition

#### Parallel Inside Sequential

```prose
do:
  session "Setup"
  parallel:
    session "Task A"
    session "Task B"
  session "Cleanup"
```

The setup runs first, then Task A and Task B run in parallel, and finally cleanup runs.

#### Sequential Inside Parallel

```prose
parallel:
  do:
    session "Multi-step task 1a"
    session "Multi-step task 1b"
  do:
    session "Multi-step task 2a"
    session "Multi-step task 2b"
```

Each parallel branch contains a sequential workflow. The two workflows run concurrently.

### Assigning Parallel Blocks to Variables

```prose
let results = parallel:
  session "Task A"
  session "Task B"
```

### Complete Example

```prose
agent reviewer:
  model: sonnet

# Run parallel reviews
parallel:
  sec = session: reviewer
    prompt: "Review for security issues"
  perf = session: reviewer
    prompt: "Review for performance issues"
  style = session: reviewer
    prompt: "Review for style issues"

# Combine all reviews
session "Create unified review report"
  context: { sec, perf, style }
```

### Join Strategies

By default, parallel blocks wait for all branches to complete. You can specify alternative join strategies:

#### First (Race)

Return as soon as the first branch completes, cancel others:

```prose
parallel ("first"):
  session "Try approach A"
  session "Try approach B"
  session "Try approach C"
```

The first successful result wins. Other branches are cancelled.

#### Any (N of M)

Return when any N branches complete successfully:

```prose
# Default: any 1 success
parallel ("any"):
  session "Attempt 1"
  session "Attempt 2"

# Specific count: wait for 2 successes
parallel ("any", count: 2):
  session "Attempt 1"
  session "Attempt 2"
  session "Attempt 3"
```

#### All (Default)

Wait for all branches to complete:

```prose
# Implicit - this is the default
parallel:
  session "Task A"
  session "Task B"

# Explicit
parallel ("all"):
  session "Task A"
  session "Task B"
```

### Failure Policies

Control how the parallel block handles branch failures:

#### Fail-Fast (Default)

If any branch fails, fail immediately and cancel other branches:

```prose
parallel:  # Implicit fail-fast
  session "Critical task 1"
  session "Critical task 2"

# Explicit
parallel (on-fail: "fail-fast"):
  session "Critical task 1"
  session "Critical task 2"
```

#### Continue

Let all branches complete, then report all failures:

```prose
parallel (on-fail: "continue"):
  session "Task 1"
  session "Task 2"
  session "Task 3"

# Continue regardless of which branches failed
session "Process results, including failures"
```

#### Ignore

Ignore all failures, always succeed:

```prose
parallel (on-fail: "ignore"):
  session "Optional enrichment 1"
  session "Optional enrichment 2"

# This always runs, even if all branches failed
session "Continue regardless"
```

### Combining Modifiers

Join strategies and failure policies can be combined:

```prose
# Race with resilience
parallel ("first", on-fail: "continue"):
  session "Fast but unreliable"
  session "Slow but reliable"

# Get any 2 results, ignoring failures
parallel ("any", count: 2, on-fail: "ignore"):
  session "Approach 1"
  session "Approach 2"
  session "Approach 3"
  session "Approach 4"
```

### Execution Semantics

When the OpenProse VM encounters a `parallel:` block:

1. **Fork**: Start all branches concurrently
2. **Execute**: Each branch runs independently
3. **Join**: Wait according to join strategy:
   - `"all"` (default): Wait for all branches
   - `"first"`: Return on first completion
   - `"any"`: Return on first success (or N successes with `count`)
4. **Handle failures**: According to on-fail policy:
   - `"fail-fast"` (default): Cancel remaining and fail immediately
   - `"continue"`: Wait for all, then report failures
   - `"ignore"`: Treat failures as successes
5. **Continue**: Proceed to the next statement with available results

### Validation Rules

| Check                                | Severity | Message                                      |
| ------------------------------------ | -------- | -------------------------------------------- |
| Invalid join strategy                | Error    | Must be "all", "first", or "any"             |
| Invalid on-fail policy               | Error    | Must be "fail-fast", "continue", or "ignore" |
| Count without "any"                  | Error    | Count is only valid with "any" strategy      |
| Count less than 1                    | Error    | Count must be at least 1                     |
| Count exceeds branches               | Warning  | Count exceeds number of parallel branches    |
| Duplicate variable in parallel       | Error    | Variable already defined                     |
| Variable conflicts with agent        | Error    | Variable name conflicts with agent name      |
| Undefined variable in object context | Error    | Undefined variable in context                |

---

## Fixed Loops

Fixed loops provide bounded iteration over a set number of times or over a collection.

### Repeat Block

The `repeat` block executes its body a fixed number of times.

#### Basic Syntax

```prose
repeat 3:
  session "Generate a creative idea"
```

#### With Index Variable

Access the current iteration index using `as`:

```prose
repeat 5 as i:
  session "Process item"
    context: i
```

The index variable `i` is scoped to the loop body and starts at 0.

### For-Each Block

The `for` block iterates over a collection.

#### Basic Syntax

```prose
let fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
  session "Describe this fruit"
    context: fruit
```

#### With Inline Array

```prose
for topic in ["AI", "climate", "space"]:
  session "Research this topic"
    context: topic
```

#### With Index Variable

Access both the item and its index:

```prose
let items = ["a", "b", "c"]
for item, i in items:
  session "Process item with index"
    context: [item, i]
```

### Parallel For-Each

The `parallel for` block runs all iterations concurrently (fan-out pattern):

```prose
let topics = ["AI", "climate", "space"]
parallel for topic in topics:
  session "Research this topic"
    context: topic

session "Combine all research"
```

This is equivalent to:

```prose
parallel:
  session "Research AI" context: "AI"
  session "Research climate" context: "climate"
  session "Research space" context: "space"
```

But more concise and dynamic.

### Variable Scoping

Loop variables are scoped to the loop body:

- They are implicitly `const` within each iteration
- They shadow outer variables of the same name (with a warning)
- They are not accessible outside the loop

```prose
let item = session "outer"
for item in ["a", "b"]:
  # 'item' here is the loop variable
  session "process loop item"
    context: item
# 'item' here refers to the outer variable again
session "use outer item"
  context: item
```

### Nesting

Loops can be nested:

```prose
repeat 2:
  repeat 3:
    session "Inner task"
```

Different loop types can be combined:

```prose
let items = ["a", "b"]
repeat 2:
  for item in items:
    session "Process item"
      context: item
```

### Complete Example

```prose
# Generate multiple variations of ideas
repeat 3:
  session "Generate a creative startup idea"

session "Select the best idea from the options above"

# Research the selected idea from multiple angles
let angles = ["market", "technology", "competition"]
parallel for angle in angles:
  session "Research this angle of the startup idea"
    context: angle

session "Synthesize all research into a business plan"
```

### Validation Rules

| Check                         | Severity | Message                              |
| ----------------------------- | -------- | ------------------------------------ |
| Repeat count must be positive | Error    | Repeat count must be positive        |
| Repeat count must be integer  | Error    | Repeat count must be an integer      |
| Undefined collection variable | Error    | Undefined collection variable        |
| Loop variable shadows outer   | Warning  | Loop variable shadows outer variable |

---

## Unbounded Loops

Unbounded loops provide iteration with AI-evaluated termination conditions. Unlike fixed loops, the iteration count is not known ahead of time - the OpenProse VM evaluates conditions at runtime using its intelligence to determine when to stop.

### Discretion Markers

Unbounded loops use **discretion markers** (`**...**`) to wrap AI-evaluated conditions. These markers signal that the enclosed text should be interpreted intelligently by the OpenProse VM at runtime, not as a literal boolean expression.

```prose
# The text inside **...** is evaluated by the AI
loop until **the poem has vivid imagery and flows smoothly**:
  session "Review and improve the poem"
```

For multi-line conditions, use triple-asterisks:

```prose
loop until ***
  the document is complete
  all sections have been reviewed
  and formatting is consistent
***:
  session "Continue working on the document"
```

### Basic Loop

The simplest unbounded loop runs indefinitely until explicitly limited:

```prose
loop:
  session "Process next item"
```

**Warning**: Loops without termination conditions or max iterations generate a warning. Always include a safety limit:

```prose
loop (max: 50):
  session "Process next item"
```

### Loop Until

The `loop until` variant runs until a condition becomes true:

```prose
loop until **the task is complete**:
  session "Continue working on the task"
```

The OpenProse VM evaluates the discretion condition after each iteration and exits when it determines the condition is satisfied.

### Loop While

The `loop while` variant runs while a condition remains true:

```prose
loop while **there are still items to process**:
  session "Process the next item"
```

Semantically, `loop while **X**` is equivalent to `loop until **not X**`.

### Iteration Variable

Track the current iteration number using `as`:

```prose
loop until **done** as attempt:
  session "Try approach"
    context: attempt
```

The iteration variable:

- Starts at 0
- Increments by 1 each iteration
- Is scoped to the loop body
- Is implicitly `const` within each iteration

### Safety Limits

Specify maximum iterations with `(max: N)`:

```prose
# Stop after 10 iterations even if condition not met
loop until **all bugs fixed** (max: 10):
  session "Find and fix a bug"
```

The loop exits when:

1. The condition is satisfied (for `until`/`while` variants), OR
2. The maximum iteration count is reached

### Complete Syntax

All options can be combined:

```prose
loop until **condition** (max: N) as i:
  body...
```

Order matters: condition comes before modifiers, modifiers before `as`.

### Examples

#### Iterative Improvement

```prose
session "Write an initial draft"

loop until **the draft is polished and ready for review** (max: 5):
  session "Review the current draft and identify issues"
  session "Revise the draft to address the issues"

session "Present the final draft"
```

#### Debugging Workflow

```prose
session "Run tests to identify failures"

loop until **all tests pass** (max: 20) as attempt:
  session "Identify the failing test"
  session "Fix the bug causing the failure"
  session "Run tests again"

session "Confirm all tests pass and summarize fixes"
```

#### Consensus Building

```prose
parallel:
  opinion1 = session "Get first expert opinion"
  opinion2 = session "Get second expert opinion"

loop until **experts have reached consensus** (max: 5):
  session "Identify points of disagreement"
    context: { opinion1, opinion2 }
  session "Facilitate discussion to resolve differences"

session "Document the final consensus"
```

#### Quality Threshold

```prose
let draft = session "Create initial document"

loop while **quality score is below threshold** (max: 10):
  draft = session "Review and improve the document"
    context: draft
  session "Calculate new quality score"

session "Finalize the document"
  context: draft
```

### Execution Semantics

When the OpenProse VM encounters an unbounded loop:

1. **Initialize**: Set iteration counter to 0
2. **Check Condition** (for `until`/`while`):
   - For `until`: Exit if condition is satisfied
   - For `while`: Exit if condition is NOT satisfied
3. **Check Limit**: Exit if iteration count >= max iterations
4. **Execute Body**: Run all statements in the loop body
5. **Increment**: Increase iteration counter
6. **Repeat**: Go to step 2

For basic `loop:` without conditions:

- Only the max iteration limit can cause exit
- Without max, the loop runs indefinitely (warning issued)

### Condition Evaluation

The OpenProse VM uses its intelligence to evaluate discretion conditions:

1. **Context Awareness**: The condition is evaluated in the context of what has happened so far in the session
2. **Semantic Understanding**: The condition text is interpreted semantically, not literally
3. **Uncertainty Handling**: When uncertain, the OpenProse VM may:
   - Continue iterating if progress is being made
   - Exit early if diminishing returns are detected
   - Use heuristics based on the condition's semantics

### Nesting

Unbounded loops can be nested with other loop types:

```prose
# Unbounded inside fixed
repeat 3:
  loop until **sub-task complete** (max: 10):
    session "Work on sub-task"

# Fixed inside unbounded
loop until **all batches processed** (max: 5):
  repeat 3:
    session "Process batch item"

# Multiple unbounded
loop until **outer condition** (max: 5):
  loop until **inner condition** (max: 10):
    session "Deep iteration"
```

### Variable Scoping

Loop variables follow the same scoping rules as fixed loops:

```prose
let i = session "outer"
loop until **done** as i:
  # 'i' here is the loop variable (shadows outer)
  session "use loop i"
    context: i
# 'i' here refers to the outer variable again
session "use outer i"
  context: i
```

### Validation Rules

| Check                         | Severity | Message                               |
| ----------------------------- | -------- | ------------------------------------- |
| Loop without max or condition | Warning  | Unbounded loop without max iterations |
| Max iterations <= 0           | Error    | Max iterations must be positive       |
| Max iterations not integer    | Error    | Max iterations must be an integer     |
| Empty discretion condition    | Error    | Discretion condition cannot be empty  |
| Very short condition          | Warning  | Discretion condition may be ambiguous |
| Loop variable shadows outer   | Warning  | Loop variable shadows outer variable  |

---

## Pipeline Operations

Pipeline operations provide functional-style collection transformations. They allow you to chain operations like map, filter, and reduce using the pipe operator (`|`).

### Pipe Operator

The pipe operator (`|`) passes a collection to a transformation operation:

```prose
let items = ["a", "b", "c"]
let results = items | map:
  session "Process this item"
    context: item
```

### Map

The `map` operation transforms each element in a collection:

```prose
let articles = ["article1", "article2", "article3"]

let summaries = articles | map:
  session "Summarize this article in one sentence"
    context: item
```

Inside a map body, the implicit variable `item` refers to the current element being processed.

### Filter

The `filter` operation keeps elements that match a condition:

```prose
let items = ["one", "two", "three", "four", "five"]

let short = items | filter:
  session "Does this word have 4 or fewer letters? Answer yes or no."
    context: item
```

The session in a filter body should return something the OpenProse VM can interpret as truthy/falsy (like "yes"/"no").

### Reduce

The `reduce` operation accumulates elements into a single result:

```prose
let ideas = ["AI assistant", "smart home", "health tracker"]

let combined = ideas | reduce(summary, idea):
  session "Add this idea to the summary, creating a cohesive concept"
    context: [summary, idea]
```

The reduce operation requires explicit variable names:

- First variable (`summary`): the accumulator
- Second variable (`idea`): the current item

The first item in the collection becomes the initial accumulator value.

### Parallel Map (pmap)

The `pmap` operation is like `map` but runs all transformations concurrently:

```prose
let tasks = ["task1", "task2", "task3"]

let results = tasks | pmap:
  session "Process this task in parallel"
    context: item

session "Aggregate all results"
  context: results
```

This is similar to `parallel for`, but in pipeline syntax.

### Chaining

Pipeline operations can be chained to compose complex transformations:

```prose
let topics = ["quantum computing", "blockchain", "machine learning", "IoT"]

let result = topics
  | filter:
      session "Is this topic trending? Answer yes or no."
        context: item
  | map:
      session "Write a one-line startup pitch for this topic"
        context: item

session "Present the startup pitches"
  context: result
```

Operations execute left-to-right: first filter, then map.

### Complete Example

```prose
# Define a collection
let articles = ["AI breakthroughs", "Climate solutions", "Space exploration"]

# Process with chained operations
let summaries = articles
  | filter:
      session "Is this topic relevant to technology? Answer yes or no."
        context: item
  | map:
      session "Write a compelling one-paragraph summary"
        context: item
  | reduce(combined, summary):
      session "Merge this summary into the combined document"
        context: [combined, summary]

# Present the final result
session "Format and present the combined summaries"
  context: summaries
```

### Implicit Variables

| Operation | Available Variables                          |
| --------- | -------------------------------------------- |
| `map`     | `item` - current element                     |
| `filter`  | `item` - current element                     |
| `pmap`    | `item` - current element                     |
| `reduce`  | Named explicitly: `reduce(accVar, itemVar):` |

### Execution Semantics

When the OpenProse VM encounters a pipeline:

1. **Input**: Start with the input collection
2. **For each operation**:
   - **map**: Transform each element, producing a new collection
   - **filter**: Keep elements where the session returns truthy
   - **reduce**: Accumulate elements into a single value
   - **pmap**: Transform all elements concurrently
3. **Output**: Return the final transformed collection/value

### Variable Scoping

Pipeline variables are scoped to their operation body:

```prose
let item = "outer"
let items = ["a", "b"]

let results = items | map:
  # 'item' here is the pipeline variable (shadows outer)
  session "process"
    context: item

# 'item' here refers to the outer variable again
session "use outer"
  context: item
```

### Validation Rules

| Check                           | Severity | Message                                            |
| ------------------------------- | -------- | -------------------------------------------------- |
| Undefined input collection      | Error    | Undefined collection variable                      |
| Invalid pipe operator           | Error    | Expected pipe operator (map, filter, reduce, pmap) |
| Reduce without variables        | Error    | Expected accumulator and item variables            |
| Pipeline variable shadows outer | Warning  | Implicit/explicit variable shadows outer variable  |

---

## Error Handling

OpenProse provides structured error handling with try/catch/finally blocks, throw statements, and retry mechanisms for resilient workflows.

### Try/Catch Blocks

The `try:` block wraps operations that might fail. The `catch:` block handles errors.

```prose
try:
  session "Attempt risky operation"
catch:
  session "Handle the error gracefully"
```

#### Error Variable Access

Use `catch as err:` to capture error context for the error handler:

```prose
try:
  session "Call external API"
catch as err:
  session "Log and handle the error"
    context: err
```

The error variable (`err`) contains contextual information about what went wrong and is only accessible within the catch block.

### Try/Catch/Finally

The `finally:` block always executes, whether the try block succeeds or fails:

```prose
try:
  session "Acquire and use resource"
catch:
  session "Handle any errors"
finally:
  session "Always clean up resource"
```

#### Execution Order

1. **Try succeeds**: try body → finally body
2. **Try fails**: try body (until failure) → catch body → finally body

### Try/Finally (No Catch)

For cleanup without error handling, use try/finally:

```prose
try:
  session "Open connection and do work"
finally:
  session "Close connection"
```

### Throw Statement

The `throw` statement raises or re-raises errors.

#### Rethrow

Inside a catch block, `throw` without arguments re-raises the caught error to outer handlers:

```prose
try:
  try:
    session "Inner operation"
  catch:
    session "Partial handling"
    throw  # Re-raise to outer handler
catch:
  session "Handle re-raised error"
```

#### Throw with Message

Throw a new error with a custom message:

```prose
session "Check preconditions"
throw "Precondition not met"
```

### Nested Error Handling

Try blocks can be nested. Inner catch blocks don't trigger outer handlers unless they rethrow:

```prose
try:
  session "Outer operation"
  try:
    session "Inner risky operation"
  catch:
    session "Handle inner error"  # Outer catch won't run
  session "Continue outer operation"
catch:
  session "Handle outer error only"
```

### Error Handling in Parallel

Each parallel branch can have its own error handling:

```prose
parallel:
  try:
    session "Branch A might fail"
  catch:
    session "Recover branch A"
  try:
    session "Branch B might fail"
  catch:
    session "Recover branch B"

session "Continue with recovered results"
```

This differs from the `on-fail:` policy which controls behavior when unhandled errors occur.

### Retry Property

The `retry:` property makes a session automatically retry on failure:

```prose
session "Call flaky API"
  retry: 3
```

#### Retry with Backoff

Add `backoff:` to control delay between retries:

```prose
session "Rate-limited API"
  retry: 5
  backoff: exponential
```

**Backoff Strategies:**

| Strategy      | Behavior                           |
| ------------- | ---------------------------------- |
| `none`        | Immediate retry (default)          |
| `linear`      | Fixed delay between retries        |
| `exponential` | Doubling delay (1s, 2s, 4s, 8s...) |

#### Retry with Context

Retry works with other session properties:

```prose
let data = session "Get input"
session "Process data"
  context: data
  retry: 3
  backoff: linear
```

### Combining Patterns

Retry and try/catch work together for maximum resilience:

```prose
try:
  session "Call external service"
    retry: 3
    backoff: exponential
catch:
  session "All retries failed, use fallback"
```

### Validation Rules

| Check                        | Severity | Message                                             |
| ---------------------------- | -------- | --------------------------------------------------- |
| Try without catch or finally | Error    | Try block must have at least "catch:" or "finally:" |
| Error variable shadows outer | Warning  | Error variable shadows outer variable               |
| Empty throw message          | Warning  | Throw message is empty                              |
| Non-positive retry count     | Error    | Retry count must be positive                        |
| Non-integer retry count      | Error    | Retry count must be an integer                      |
| High retry count (>10)       | Warning  | Retry count is unusually high                       |
| Invalid backoff strategy     | Error    | Must be none, linear, or exponential                |
| Retry on agent definition    | Warning  | Retry property is only valid in session statements  |

### Syntax Reference

```
try_block ::= "try" ":" NEWLINE INDENT statement+ DEDENT
              [catch_block]
              [finally_block]

catch_block ::= "catch" ["as" identifier] ":" NEWLINE INDENT statement+ DEDENT

finally_block ::= "finally" ":" NEWLINE INDENT statement+ DEDENT

throw_statement ::= "throw" [string_literal]

retry_property ::= "retry" ":" number_literal

backoff_property ::= "backoff" ":" ( "none" | "linear" | "exponential" )
```

---

## Choice Blocks

Choice blocks allow the OpenProse VM to select from multiple labeled options based on criteria. This is useful for branching workflows where the best path depends on runtime analysis.

### Syntax

```prose
choice **criteria**:
  option "Label A":
    statements...
  option "Label B":
    statements...
```

### Criteria

The criteria is wrapped in discretion markers (`**...**`) and is evaluated by the OpenProse VM to select which option to execute:

```prose
choice **the best approach for the current situation**:
  option "Quick fix":
    session "Apply a quick temporary fix"
  option "Full refactor":
    session "Perform a complete code refactor"
```

### Multi-line Criteria

For complex criteria, use triple-asterisks:

```prose
choice ***
  which strategy is most appropriate
  given the current project constraints
  and timeline requirements
***:
  option "MVP approach":
    session "Build minimum viable product"
  option "Full feature set":
    session "Build complete feature set"
```

### Examples

#### Simple Choice

```prose
let analysis = session "Analyze the code quality"

choice **the severity of issues found in the analysis**:
  option "Critical":
    session "Stop deployment and fix critical issues"
      context: analysis
  option "Minor":
    session "Log issues for later and proceed"
      context: analysis
  option "None":
    session "Proceed with deployment"
```

#### Choice with Multiple Statements per Option

```prose
choice **the user's experience level**:
  option "Beginner":
    session "Explain basic concepts first"
    session "Provide step-by-step guidance"
    session "Include helpful tips and warnings"
  option "Expert":
    session "Provide concise technical summary"
    session "Include advanced configuration options"
```

#### Nested Choices

```prose
choice **the type of request**:
  option "Bug report":
    choice **the bug severity**:
      option "Critical":
        session "Escalate immediately"
      option "Normal":
        session "Add to sprint backlog"
  option "Feature request":
    session "Add to feature backlog"
```

### Execution Semantics

When the OpenProse VM encounters a `choice` block:

1. **Evaluate Criteria**: Interpret the discretion criteria in current context
2. **Select Option**: Choose the most appropriate labeled option
3. **Execute**: Run all statements in the selected option's body
4. **Continue**: Proceed to the next statement after the choice block

Only one option is executed per choice block.

### Validation Rules

| Check                   | Severity | Message                                    |
| ----------------------- | -------- | ------------------------------------------ |
| Choice without options  | Error    | Choice block must have at least one option |
| Empty criteria          | Error    | Choice criteria cannot be empty            |
| Duplicate option labels | Warning  | Duplicate option label                     |
| Empty option body       | Warning  | Option has empty body                      |

### Syntax Reference

```
choice_block ::= "choice" discretion ":" NEWLINE INDENT option+ DEDENT

option ::= "option" string ":" NEWLINE INDENT statement+ DEDENT

discretion ::= "**" text "**" | "***" text "***"
```

---

## Conditional Statements

If/elif/else statements provide conditional branching based on AI-evaluated conditions using discretion markers.

### If Statement

```prose
if **condition**:
  statements...
```

### If/Else

```prose
if **condition**:
  statements...
else:
  statements...
```

### If/Elif/Else

```prose
if **first condition**:
  statements...
elif **second condition**:
  statements...
elif **third condition**:
  statements...
else:
  statements...
```

### Discretion Conditions

Conditions are wrapped in discretion markers (`**...**`) for AI evaluation:

```prose
let analysis = session "Analyze the codebase"

if **the code has security vulnerabilities**:
  session "Fix security issues immediately"
    context: analysis
elif **the code has performance issues**:
  session "Optimize performance bottlenecks"
    context: analysis
else:
  session "Proceed with normal review"
    context: analysis
```

### Multi-line Conditions

Use triple-asterisks for complex conditions:

```prose
if ***
  the test suite passes
  and the code coverage is above 80%
  and there are no linting errors
***:
  session "Deploy to production"
else:
  session "Fix issues before deploying"
```

### Examples

#### Simple If

```prose
session "Check system health"

if **the system is healthy**:
  session "Continue with normal operations"
```

#### If/Else

```prose
let review = session "Review the pull request"

if **the code changes are safe and well-tested**:
  session "Approve and merge the PR"
    context: review
else:
  session "Request changes"
    context: review
```

#### Multiple Elif

```prose
let status = session "Check project status"

if **the project is on track**:
  session "Continue as planned"
elif **the project is slightly delayed**:
  session "Adjust timeline and communicate"
elif **the project is significantly delayed**:
  session "Escalate to management"
  session "Create recovery plan"
else:
  session "Assess project viability"
```

#### Nested Conditionals

```prose
if **the request is authenticated**:
  if **the user has admin privileges**:
    session "Process admin request"
  else:
    session "Process standard user request"
else:
  session "Return authentication error"
```

### Combining with Other Constructs

#### With Try/Catch

```prose
try:
  session "Attempt operation"
  if **operation succeeded partially**:
    session "Complete remaining steps"
catch as err:
  if **error is recoverable**:
    session "Apply recovery procedure"
      context: err
  else:
    throw "Unrecoverable error"
```

#### With Loops

```prose
loop until **task complete** (max: 10):
  session "Work on task"
  if **encountered blocker**:
    session "Resolve blocker"
```

### Execution Semantics

When the OpenProse VM encounters an `if` statement:

1. **Evaluate Condition**: Interpret the first discretion condition
2. **If True**: Execute the then-body and skip remaining clauses
3. **If False**: Check each `elif` condition in order
4. **Elif Match**: Execute that elif's body and skip remaining
5. **No Match**: Execute the `else` body (if present)
6. **Continue**: Proceed to the next statement

### Validation Rules

| Check           | Severity | Message                           |
| --------------- | -------- | --------------------------------- |
| Empty condition | Error    | If/elif condition cannot be empty |
| Elif without if | Error    | Elif must follow if               |
| Else without if | Error    | Else must follow if or elif       |
| Multiple else   | Error    | Only one else clause allowed      |
| Empty body      | Warning  | Condition has empty body          |

### Syntax Reference

```
if_statement ::= "if" discretion ":" NEWLINE INDENT statement+ DEDENT
                 elif_clause*
                 [else_clause]

elif_clause ::= "elif" discretion ":" NEWLINE INDENT statement+ DEDENT

else_clause ::= "else" ":" NEWLINE INDENT statement+ DEDENT

discretion ::= "**" text "**" | "***" text "***"
```

---

## Execution Model

OpenProse uses a two-phase execution model.

### Phase 1: Compilation (Static)

The compile phase handles deterministic preprocessing:

1. **Parse**: Convert source code to AST
2. **Validate**: Check for syntax and semantic errors
3. **Expand**: Normalize syntax sugar (when implemented)
4. **Output**: Generate canonical program

### Phase 2: Runtime (Intelligent)

The OpenProse VM executes the compiled program:

1. **Load**: Receive the compiled program
2. **Collect Agents**: Register all agent definitions
3. **Execute**: Process each statement in order
4. **Spawn**: Create subagents with resolved configurations
5. **Coordinate**: Manage context passing between sessions

### OpenProse VM Behavior

| Aspect               | Behavior                                        |
| -------------------- | ----------------------------------------------- |
| Execution order      | Strict - follows program exactly                |
| Session creation     | Strict - creates what program specifies         |
| Agent resolution     | Strict - merge properties deterministically     |
| Context passing      | Intelligent - summarizes/transforms as needed   |
| Completion detection | Intelligent - determines when session is "done" |

### State Management

For the current implementation, state is tracked in-context (conversation history):

| State Type          | Tracking Approach                                   |
| ------------------- | --------------------------------------------------- |
| Agent definitions   | Collected at program start                          |
| Execution flow      | Implicit reasoning ("completed X, now executing Y") |
| Session outputs     | Held in conversation history                        |
| Position in program | Tracked by OpenProse VM                             |

---

## Validation Rules

The validator checks programs for errors and warnings before execution.

### Errors (Block Execution)

| Code | Description                         |
| ---- | ----------------------------------- |
| E001 | Unterminated string literal         |
| E002 | Unknown escape sequence in string   |
| E003 | Session missing prompt or agent     |
| E004 | Unexpected token                    |
| E005 | Invalid syntax                      |
| E006 | Duplicate agent definition          |
| E007 | Undefined agent reference           |
| E008 | Invalid model value                 |
| E009 | Duplicate property                  |
| E010 | Duplicate use statement             |
| E011 | Empty use path                      |
| E012 | Invalid use path format             |
| E013 | Skills must be an array             |
| E014 | Skill name must be a string         |
| E015 | Permissions must be a block         |
| E016 | Permission pattern must be a string |
| E017 | `resume:` requires persistent agent |
| E018 | `resume:` with no existing memory   |
| E019 | Duplicate variable name (flat namespace) |
| E020 | Empty input name                    |
| E021 | Duplicate input declaration         |
| E022 | Input after executable statement    |
| E023 | Empty output name                   |
| E024 | Duplicate output declaration        |
| E025 | Unknown program in invocation       |
| E026 | Missing required input              |
| E027 | Unknown input name in invocation    |
| E028 | Unknown output property access      |

### Warnings (Non-blocking)

| Code | Description                              |
| ---- | ---------------------------------------- |
| W001 | Empty session prompt                     |
| W002 | Whitespace-only session prompt           |
| W003 | Session prompt exceeds 10,000 characters |
| W004 | Empty prompt property                    |
| W005 | Unknown property name                    |
| W006 | Unknown import source format             |
| W007 | Skill not imported                       |
| W008 | Unknown permission type                  |
| W009 | Unknown permission value                 |
| W010 | Empty skills array                       |
| W011 | `session:` on persistent agent with existing memory |

### Error Message Format

Errors include location information:

```
Error at line 5, column 12: Unterminated string literal
  session "Hello
          ^
```

---

## Examples

### Minimal Program

```prose
session "Hello world"
```

### Research Pipeline with Agents

```prose
# Define specialized agents
agent researcher:
  model: sonnet
  prompt: "You are a research assistant"

agent writer:
  model: opus
  prompt: "You are a technical writer"

# Execute workflow
session: researcher
  prompt: "Research recent developments in quantum computing"

session: writer
  prompt: "Write a summary of the research findings"
```

### Code Review Workflow

```prose
agent reviewer:
  model: sonnet
  prompt: "You are an expert code reviewer"

session: reviewer
  prompt: "Read the code in src/ and identify potential bugs"

session: reviewer
  prompt: "Suggest fixes for each bug found"

session: reviewer
  prompt: "Create a summary of all changes needed"
```

### Multi-step Task with Model Override

```prose
agent analyst:
  model: haiku
  prompt: "You analyze data quickly"

# Quick initial analysis
session: analyst
  prompt: "Scan the data for obvious patterns"

# Detailed analysis with more powerful model
session: analyst
  model: opus
  prompt: "Perform deep analysis on the patterns found"
```

### Comments for Documentation

```prose
# Project: Quarterly Report Generator
# Author: Team Lead
# Date: 2024-01-01

agent data-collector:
  model: sonnet
  prompt: "You gather and organize data"

agent analyst:
  model: opus
  prompt: "You analyze data and create insights"

# Step 1: Gather data
session: data-collector
  prompt: "Collect all sales data from the past quarter"

# Step 2: Analysis
session: analyst
  prompt: "Perform trend analysis on the collected data"

# Step 3: Report generation
session: analyst
  prompt: "Generate a formatted quarterly report with charts"
```

### Workflow with Skills and Permissions

```prose
# Import external programs
use "@anthropic/web-search"
use "@anthropic/file-writer" as file-writer

# Define a secure research agent
agent researcher:
  model: sonnet
  prompt: "You are a research assistant"
  skills: ["web-search"]
  permissions:
    read: ["*.md", "*.txt"]
    bash: deny

# Define a writer agent
agent writer:
  model: opus
  prompt: "You create documentation"
  skills: ["file-writer"]
  permissions:
    write: ["docs/"]
    bash: deny

# Execute workflow
session: researcher
  prompt: "Research AI safety topics"

session: writer
  prompt: "Write a summary document"
```

---

## Future Features

All core features through Tier 12 have been implemented. Potential future enhancements:

### Tier 13: Extended Features

- Custom functions with return values
- Module system for code organization
- Type annotations for validation
- Async/await patterns for advanced concurrency

### Tier 14: Tooling

- Language server protocol (LSP) support
- VS Code extension
- Interactive debugger
- Performance profiling

---

## Syntax Grammar (Implemented)

```
program     → statement* EOF
statement   → useStatement | inputDecl | agentDef | session | resumeStmt
            | letBinding | constBinding | assignment | outputBinding
            | parallelBlock | repeatBlock | forEachBlock | loopBlock
            | tryBlock | choiceBlock | ifStatement | doBlock | blockDef
            | throwStatement | comment

# Program Composition
useStatement → "use" string ( "as" IDENTIFIER )?
inputDecl   → "input" IDENTIFIER ":" string
outputBinding → "output" IDENTIFIER "=" expression
programCall → IDENTIFIER "(" ( IDENTIFIER ":" expression )* ")"

# Definitions
agentDef    → "agent" IDENTIFIER ":" NEWLINE INDENT agentProperty* DEDENT
agentProperty → "model:" ( "sonnet" | "opus" | "haiku" )
              | "prompt:" string
              | "persist:" ( "true" | "project" | string )
              | "context:" ( IDENTIFIER | array | objectContext )
              | "retry:" NUMBER
              | "backoff:" ( "none" | "linear" | "exponential" )
              | "skills:" "[" string* "]"
              | "permissions:" NEWLINE INDENT permission* DEDENT
blockDef    → "block" IDENTIFIER params? ":" NEWLINE INDENT statement* DEDENT
params      → "(" IDENTIFIER ( "," IDENTIFIER )* ")"

# Control Flow
parallelBlock → "parallel" parallelMods? ":" NEWLINE INDENT parallelBranch* DEDENT
parallelMods  → "(" ( joinStrategy | onFail | countMod ) ( "," ( joinStrategy | onFail | countMod ) )* ")"
joinStrategy  → string                              # "all" | "first" | "any"
onFail        → "on-fail" ":" string                # "fail-fast" | "continue" | "ignore"
countMod      → "count" ":" NUMBER                  # only valid with "any"
parallelBranch → ( IDENTIFIER "=" )? statement

# Loops
repeatBlock → "repeat" NUMBER ( "as" IDENTIFIER )? ":" NEWLINE INDENT statement* DEDENT
forEachBlock → "parallel"? "for" IDENTIFIER ( "," IDENTIFIER )? "in" collection ":" NEWLINE INDENT statement* DEDENT
loopBlock   → "loop" ( ( "until" | "while" ) discretion )? loopMods? ( "as" IDENTIFIER )? ":" NEWLINE INDENT statement* DEDENT
loopMods    → "(" "max" ":" NUMBER ")"

# Error Handling
tryBlock    → "try" ":" NEWLINE INDENT statement+ DEDENT catchBlock? finallyBlock?
catchBlock  → "catch" ( "as" IDENTIFIER )? ":" NEWLINE INDENT statement+ DEDENT
finallyBlock → "finally" ":" NEWLINE INDENT statement+ DEDENT
throwStatement → "throw" string?

# Conditionals
choiceBlock → "choice" discretion ":" NEWLINE INDENT choiceOption+ DEDENT
choiceOption → "option" string ":" NEWLINE INDENT statement+ DEDENT
ifStatement → "if" discretion ":" NEWLINE INDENT statement+ DEDENT elifClause* elseClause?
elifClause  → "elif" discretion ":" NEWLINE INDENT statement+ DEDENT
elseClause  → "else" ":" NEWLINE INDENT statement+ DEDENT

# Composition
doBlock     → "do" ( ":" NEWLINE INDENT statement* DEDENT | IDENTIFIER args? )
args        → "(" expression ( "," expression )* ")"
arrowExpr   → session ( "->" session )+

# Sessions
session     → "session" ( string | ":" IDENTIFIER | IDENTIFIER ":" IDENTIFIER )
              ( NEWLINE INDENT sessionProperty* DEDENT )?
resumeStmt  → "resume" ":" IDENTIFIER ( NEWLINE INDENT sessionProperty* DEDENT )?
sessionProperty → "model:" ( "sonnet" | "opus" | "haiku" )
                | "prompt:" string
                | "context:" ( IDENTIFIER | array | objectContext )
                | "retry:" NUMBER
                | "backoff:" ( "none" | "linear" | "exponential" )

# Bindings
letBinding  → "let" IDENTIFIER "=" expression
constBinding → "const" IDENTIFIER "=" expression
assignment  → IDENTIFIER "=" expression

# Expressions
expression  → session | doBlock | parallelBlock | repeatBlock | forEachBlock
            | loopBlock | arrowExpr | pipeExpr | programCall | string | IDENTIFIER | array | objectContext

# Pipelines
pipeExpr    → ( IDENTIFIER | array ) ( "|" pipeOp )+
pipeOp      → ( "map" | "filter" | "pmap" ) ":" NEWLINE INDENT statement* DEDENT
            | "reduce" "(" IDENTIFIER "," IDENTIFIER ")" ":" NEWLINE INDENT statement* DEDENT

# Properties
property    → ( "model" | "prompt" | "context" | "retry" | "backoff" | IDENTIFIER )
            ":" ( IDENTIFIER | string | array | objectContext | NUMBER )

# Primitives
discretion  → "**" text "**" | "***" text "***"
collection  → IDENTIFIER | array
array       → "[" ( expression ( "," expression )* )? "]"
objectContext → "{" ( IDENTIFIER ( "," IDENTIFIER )* )? "}"
comment     → "#" text NEWLINE

# Strings
string      → singleString | tripleString | interpolatedString
singleString → '"' character* '"'
tripleString → '"""' ( character | NEWLINE )* '"""'
interpolatedString → string containing "{" IDENTIFIER "}"
character   → escape | non-quote
escape      → "\\" | "\"" | "\n" | "\t"
```

---

## Compiler API

When a user invokes `/prose-compile` or asks you to compile a `.prose` file:

1. **Read this document** (`compiler.md`) fully to understand all syntax and validation rules
2. **Parse** the program according to the syntax grammar
3. **Validate** syntax correctness, semantic validity, and self-evidence
4. **Transform** to canonical form (expand syntax sugar, normalize structure)
5. **Output** the compiled program or report errors/warnings with line numbers

For direct interpretation without compilation, read `prose.md` and execute statements as described in the Session Statement section.


path: examples/README.md
content: # OpenProse Examples

These examples demonstrate workflows using OpenProse's full feature set.

## Available Examples

### Basics (01-08)

| File                              | Description                                  |
| --------------------------------- | -------------------------------------------- |
| `01-hello-world.prose`            | Simplest possible program - a single session |
| `02-research-and-summarize.prose` | Research a topic, then summarize findings    |
| `03-code-review.prose`            | Multi-perspective code review pipeline       |
| `04-write-and-refine.prose`       | Draft content and iteratively improve it     |
| `05-debug-issue.prose`            | Step-by-step debugging workflow              |
| `06-explain-codebase.prose`       | Progressive exploration of a codebase        |
| `07-refactor.prose`               | Systematic refactoring workflow              |
| `08-blog-post.prose`              | End-to-end content creation                  |

### Agents & Skills (09-12)

| File                                | Description                          |
| ----------------------------------- | ------------------------------------ |
| `09-research-with-agents.prose`     | Custom agents with model selection   |
| `10-code-review-agents.prose`       | Specialized reviewer agents          |
| `11-skills-and-imports.prose`       | External skill imports               |
| `12-secure-agent-permissions.prose` | Agent permissions and access control |

### Variables & Composition (13-15)

| File                             | Description                         |
| -------------------------------- | ----------------------------------- |
| `13-variables-and-context.prose` | let/const bindings, context passing |
| `14-composition-blocks.prose`    | Named blocks, do blocks             |
| `15-inline-sequences.prose`      | Arrow operator chains               |

### Parallel Execution (16-19)

| File                                 | Description                               |
| ------------------------------------ | ----------------------------------------- |
| `16-parallel-reviews.prose`          | Basic parallel execution                  |
| `17-parallel-research.prose`         | Named parallel results                    |
| `18-mixed-parallel-sequential.prose` | Combined parallel and sequential patterns |
| `19-advanced-parallel.prose`         | Join strategies, failure policies         |

### Loops (20)

| File                   | Description                             |
| ---------------------- | --------------------------------------- |
| `20-fixed-loops.prose` | repeat, for-each, parallel for patterns |

### Pipelines (21)

| File                           | Description                               |
| ------------------------------ | ----------------------------------------- |
| `21-pipeline-operations.prose` | map, filter, reduce, pmap transformations |

### Error Handling (22-23)

| File                          | Description                            |
| ----------------------------- | -------------------------------------- |
| `22-error-handling.prose`     | try/catch/finally patterns             |
| `23-retry-with-backoff.prose` | Resilient API calls with retry/backoff |

### Advanced Features (24-27)

| File                            | Description                       |
| ------------------------------- | --------------------------------- |
| `24-choice-blocks.prose`        | AI-selected branching             |
| `25-conditionals.prose`         | if/elif/else patterns             |
| `26-parameterized-blocks.prose` | Reusable blocks with arguments    |
| `27-string-interpolation.prose` | Dynamic prompts with {var} syntax |

### Orchestration Systems (28-31)

| File                                  | Description                                                                                                                                                 |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `28-gas-town.prose`                   | Multi-agent orchestration ("Kubernetes for agents") with 7 worker roles, patrols, convoys, and GUPP propulsion                                              |
| `29-captains-chair.prose`             | Full captain's chair pattern: coordinating agent dispatches subagents for all work, with parallel research, critic review cycles, and checkpoint validation |
| `30-captains-chair-simple.prose`      | Minimal captain's chair: core pattern without complexity                                                                                                    |
| `31-captains-chair-with-memory.prose` | Captain's chair with retrospective analysis and session-to-session learning                                                                                 |

### Production Workflows (33-38)

| File                         | Description                              |
| ---------------------------- | ---------------------------------------- |
| `33-pr-review-autofix.prose` | Automated PR review with fix suggestions |
| `34-content-pipeline.prose`  | End-to-end content creation pipeline     |
| `35-feature-factory.prose`   | Feature implementation automation        |
| `36-bug-hunter.prose`        | Systematic bug detection and analysis    |
| `37-the-forge.prose`         | Build a browser from scratch             |
| `38-skill-scan.prose`        | Skill discovery and analysis             |

### Architecture Patterns (39)

| File                               | Description                                                                                          |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `39-architect-by-simulation.prose` | Design systems through simulated implementation phases with serial handoffs and persistent architect |

### Recursive Language Models (40-43)

| File                          | Description                                                         |
| ----------------------------- | ------------------------------------------------------------------- |
| `40-rlm-self-refine.prose`    | Recursive refinement until quality threshold - the core RLM pattern |
| `41-rlm-divide-conquer.prose` | Hierarchical chunking for inputs beyond context limits              |
| `42-rlm-filter-recurse.prose` | Filter-then-process for needle-in-haystack tasks                    |
| `43-rlm-pairwise.prose`       | O(n^2) pairwise aggregation for relationship mapping                |

### Meta / Self-Hosting (44-48)

| File                              | Description                                            |
| --------------------------------- | ------------------------------------------------------ |
| `44-run-endpoint-ux-test.prose`   | Concurrent agents testing the /run API endpoint        |
| `45-plugin-release.prose`         | OpenProse plugin release workflow (this repo)          |
| `46-workflow-crystallizer.prose`  | Reflective: observes thread, extracts workflow, writes .prose |
| `47-language-self-improvement.prose` | Meta-level 2: analyzes .prose corpus to evolve the language itself |
| `48-habit-miner.prose`            | Mines AI session logs for patterns, generates .prose automations |

## The Architect By Simulation Pattern

The architect-by-simulation pattern is for designing systems by "implementing" them through reasoning. Instead of writing code, each phase produces specification documents that the next phase builds upon.

**Key principles:**

1. **Thinking/deduction framework**: "Implement" means reasoning through design decisions
2. **Serial pipeline with handoffs**: Each phase reads previous phase's output
3. **Persistent architect**: Maintains master plan and synthesizes learnings
4. **User checkpoint**: Get plan approval BEFORE executing the pipeline
5. **Simulation as implementation**: The spec IS the deliverable

```prose
# The core pattern
agent architect:
  model: opus
  persist: true
  prompt: "Design by simulating implementation"

# Create master plan with phases
let plan = session: architect
  prompt: "Break feature into design phases"

# User reviews the plan BEFORE the pipeline runs
input user_approval: "User reviews plan and approves"

# Execute phases serially with handoffs
for phase_name, index in phases:
  let handoff = session: phase-executor
    prompt: "Execute phase {index}"
    context: previous_handoffs

  # Architect synthesizes after each phase
  resume: architect
    prompt: "Synthesize learnings from phase {index}"
    context: handoff

# Synthesize all handoffs into final spec
output spec = session: architect
  prompt: "Synthesize all handoffs into final spec"
```

See example 39 for the full implementation.

## The Captain's Chair Pattern

The captain's chair is an orchestration paradigm where a coordinating agent (the "captain") dispatches specialized subagents for all execution. The captain never writes code directly—only plans, coordinates, and validates.

**Key principles:**

1. **Context isolation**: Subagents receive targeted context, not everything
2. **Parallel execution**: Multiple subagents work concurrently where possible
3. **Continuous criticism**: Critic agents review plans and outputs mid-stream
4. **80/20 planning**: 80% effort on planning, 20% on execution oversight
5. **Checkpoint validation**: User approval at key decision points

```prose
# The core pattern
agent captain:
  model: opus
  prompt: "Coordinate but never execute directly"

agent executor:
  model: sonnet
  prompt: "Execute assigned tasks precisely"

agent critic:
  model: sonnet
  prompt: "Review work and find issues"

# Captain plans
let plan = session: captain
  prompt: "Break down this task"

# Parallel execution with criticism
parallel:
  work = session: executor
    context: plan
  review = session: critic
    context: plan

# Captain validates
output result = session: captain
  prompt: "Validate and integrate"
  context: { work, review }
```

See examples 29-31 for full implementations.

## The Recursive Language Model Pattern

Recursive Language Models (RLMs) are a paradigm for handling inputs far beyond context limits. The key insight: treat the prompt as an external environment that the LLM can symbolically interact with, chunk, and recursively process.

**Why RLMs matter:**

- Base LLMs degrade rapidly on long contexts ("context rot")
- RLMs maintain performance on inputs 2 orders of magnitude beyond context limits
- On quadratic-complexity tasks, base models get <0.1% while RLMs achieve 58%

**Key patterns:**

1. **Self-refinement**: Recursive improvement until quality threshold
2. **Divide-and-conquer**: Chunk, process, aggregate recursively
3. **Filter-then-recurse**: Cheap filtering before expensive deep dives
4. **Pairwise aggregation**: Handle O(n²) tasks through batch decomposition

```prose
# The core RLM pattern: recursive block with scope isolation
block process(data, depth):
  # Base case
  if **data is small** or depth <= 0:
    output session "Process directly"
      context: data

  # Recursive case: chunk and fan out
  let chunks = session "Split into logical chunks"
    context: data

  parallel for chunk in chunks:
    do process(chunk, depth - 1)  # Recursive call

  # Aggregate results (fan in)
  output session "Synthesize partial results"
```

**OpenProse advantages for RLMs:**

- **Scope isolation**: Each recursive call gets its own `execution_id`, preventing variable collisions
- **Parallel fan-out**: `parallel for` enables concurrent processing at each recursion level
- **State persistence**: SQLite/PostgreSQL backends track the full call tree
- **Natural aggregation**: Pipelines (`| reduce`) and explicit context passing

See examples 40-43 for full implementations.

## Running Examples

Ask Claude to run any example:

```
Run the code review example from the OpenProse examples
```

Or reference the file directly:

```
Execute examples/03-code-review.prose
```

## Feature Reference

### Core Syntax

```prose
# Comments
session "prompt"                    # Simple session
let x = session "..."               # Variable binding
const y = session "..."             # Immutable binding
```

### Agents

```prose
agent name:
  model: sonnet                     # haiku, sonnet, opus
  prompt: "System prompt"
  skills: ["skill1", "skill2"]
  permissions:
    read: ["*.md"]
    bash: deny
```

### Parallel

```prose
parallel:                           # Basic parallel
  a = session "A"
  b = session "B"

parallel ("first"):                 # Race - first wins
parallel ("any", count: 2):         # Wait for N successes
parallel (on-fail: "continue"):     # Don't fail on errors
```

### Loops

```prose
repeat 3:                           # Fixed iterations
  session "..."

for item in items:                  # For-each
  session "..."

parallel for item in items:         # Parallel for-each
  session "..."

loop until **condition** (max: 10): # Unbounded with AI condition
  session "..."
```

### Pipelines

```prose
items | map:                        # Transform each
  session "..."
items | filter:                     # Keep matching
  session "..."
items | reduce(acc, x):             # Accumulate
  session "..."
items | pmap:                       # Parallel transform
  session "..."
```

### Error Handling

```prose
try:
  session "..."
catch as err:
  session "..."
finally:
  session "..."

session "..."
  retry: 3
  backoff: "exponential"            # none, linear, exponential

throw "message"                     # Raise error
```

### Conditionals

```prose
if **condition**:
  session "..."
elif **other condition**:
  session "..."
else:
  session "..."
```

### Choice

```prose
choice **criteria**:
  option "Label A":
    session "..."
  option "Label B":
    session "..."
```

### Blocks

```prose
block name(param):                  # Define with parameters
  session "... {param} ..."

do name("value")                    # Invoke with arguments
```

### String Interpolation

```prose
let x = session "Get value"
session "Use {x} in prompt"         # Single-line

session """                         # Multi-line
Multi-line prompt with {x}
"""
```

## Learn More

See `compiler.md` in the skill directory for the complete language specification.


path: examples/roadmap/README.md
content: # Roadmap Examples

These examples demonstrate **planned** OpenProse syntax that is **not yet implemented**.

They are included to show the direction of the language and gather feedback on the design.

## Planned Features

| Feature | Status | Example File |
|---------|--------|--------------|
| Agent definitions | Planned | `simple-pipeline.prose` |
| Named sessions | Planned | `simple-pipeline.prose` |
| Parallel execution | Planned | `parallel-review.prose` |
| Variables & context | Planned | `iterative-refinement.prose` |
| Loops & conditionals | Planned | `iterative-refinement.prose` |
| Imports | Planned | `syntax/open-prose-syntax.prose` |

## Do Not Run These Examples

These files will not work with the current interpreter. They are for reference only.

For working examples, see the parent `examples/` directory.


path: guidance/antipatterns.md
content: ---
role: antipatterns
summary: |
  Common mistakes and patterns to avoid in OpenProse programs.
  Read this file to identify and fix problematic code patterns.
see-also:
  - prose.md: Execution semantics, how to run programs
  - compiler.md: Full syntax grammar, validation rules
  - patterns.md: Recommended design patterns
---

# OpenProse Antipatterns

This document catalogs patterns that lead to brittle, expensive, slow, or unmaintainable programs. Each antipattern includes recognition criteria and remediation guidance.

---

## Structural Antipatterns

#### god-session

A single session that tries to do everything. God sessions are hard to debug, impossible to parallelize, and produce inconsistent results.

```prose
# Bad: One session doing too much
session """
  Read all the code in the repository.
  Identify security vulnerabilities.
  Find performance bottlenecks.
  Check for style violations.
  Generate a comprehensive report.
  Suggest fixes for each issue.
  Prioritize by severity.
  Create a remediation plan.
"""
```

**Why it's bad**: The session has no clear completion criteria. It mixes concerns that could be parallelized. Failure anywhere fails everything.

**Fix**: Decompose into focused sessions:

```prose
# Good: Focused sessions
parallel:
  security = session "Identify security vulnerabilities"
  perf = session "Find performance bottlenecks"
  style = session "Check for style violations"

session "Synthesize findings and prioritize by severity"
  context: { security, perf, style }

session "Create remediation plan"
```

#### sequential-when-parallel

Running independent operations sequentially when they could run concurrently. Wastes wall-clock time.

```prose
# Bad: Sequential independent work
let market = session "Research market"
let tech = session "Research technology"
let competition = session "Research competition"

session "Synthesize"
  context: [market, tech, competition]
```

**Why it's bad**: Total time is sum of all research times. Each session waits for the previous one unnecessarily.

**Fix**: Parallelize independent work:

```prose
# Good: Parallel independent work
parallel:
  market = session "Research market"
  tech = session "Research technology"
  competition = session "Research competition"

session "Synthesize"
  context: { market, tech, competition }
```

#### spaghetti-context

Context passed haphazardly without clear data flow. Makes programs hard to understand and modify.

```prose
# Bad: Unclear what context is actually used
let a = session "Step A"
let b = session "Step B"
  context: a
let c = session "Step C"
  context: [a, b]
let d = session "Step D"
  context: [a, b, c]
let e = session "Step E"
  context: [a, c, d]  # Why not b?
let f = session "Step F"
  context: [a, b, c, d, e]  # Everything?
```

**Why it's bad**: Unclear which sessions depend on which outputs. Hard to parallelize or refactor.

**Fix**: Minimize context to actual dependencies:

```prose
# Good: Clear, minimal dependencies
let research = session "Research"
let analysis = session "Analyze"
  context: research
let recommendations = session "Recommend"
  context: analysis  # Only needs analysis, not research
let report = session "Report"
  context: recommendations
```

#### parallel-then-synthesize

Spawning parallel agents for related analytical work, then synthesizing, when a single focused agent could do the entire job more efficiently.

```prose
# Antipattern: Parallel investigation + synthesis
parallel:
  code = session "Analyze code path"
  logs = session "Analyze logs"
  context = session "Analyze execution context"

synthesis = session "Synthesize all findings"
  context: { code, logs, context }
# 4 LLM calls, coordination overhead, fragmented context
```

**Why it's bad**: For related analysis that feeds into one conclusion, the coordination overhead and context fragmentation often outweigh parallelism benefits. Each parallel agent sees only part of the picture.

**Fix**: Use a single focused agent with multi-step instructions:

```prose
# Good: Single comprehensive investigator
diagnosis = session "Investigate the error"
  prompt: """Analyze comprehensively:
  1. Check the code path that produced the error
  2. Examine logs for timing and state
  3. Review execution context
  Synthesize into a unified diagnosis."""
# 1 LLM call, full context, no coordination
```

**When parallel IS right**: When analyses are truly independent (security vs performance), when you want diverse perspectives that shouldn't influence each other, or when the work is so large it genuinely benefits from division.

#### copy-paste-workflows

Duplicating session sequences instead of using blocks. Leads to inconsistent changes and maintenance burden.

```prose
# Bad: Duplicated workflow
session "Security review of module A"
session "Performance review of module A"
session "Synthesize reviews of module A"

session "Security review of module B"
session "Performance review of module B"
session "Synthesize reviews of module B"

session "Security review of module C"
session "Performance review of module C"
session "Synthesize reviews of module C"
```

**Why it's bad**: If the workflow needs to change, you must change it everywhere. Easy to miss one.

**Fix**: Extract into a block:

```prose
# Good: Reusable block
block review-module(module):
  parallel:
    sec = session "Security review of {module}"
    perf = session "Performance review of {module}"
  session "Synthesize reviews of {module}"
    context: { sec, perf }

do review-module("module A")
do review-module("module B")
do review-module("module C")
```

---

## Robustness Antipatterns

#### unbounded-loop

A loop without max iterations. Can run forever if the condition is never satisfied.

```prose
# Bad: No escape hatch
loop until **the code is perfect**:
  session "Improve the code"
```

**Why it's bad**: "Perfect" may never be achieved. The program could run indefinitely, consuming resources.

**Fix**: Always specify `max:`:

```prose
# Good: Bounded iteration
loop until **the code is perfect** (max: 10):
  session "Improve the code"
```

#### optimistic-execution

Assuming everything will succeed. No error handling for operations that can fail.

```prose
# Bad: No error handling
session "Call external API"
session "Process API response"
session "Store results in database"
session "Send notification"
```

**Why it's bad**: If the API fails, subsequent sessions receive no valid input. Silent corruption.

**Fix**: Handle failures explicitly:

```prose
# Good: Error handling
try:
  let response = session "Call external API"
    retry: 3
    backoff: "exponential"
  session "Process API response"
    context: response
catch as err:
  session "Handle API failure gracefully"
    context: err
```

#### ignored-errors

Using `on-fail: "ignore"` when failures actually matter. Masks problems that should surface.

```prose
# Bad: Ignoring failures that matter
parallel (on-fail: "ignore"):
  session "Charge customer credit card"
  session "Ship the product"
  session "Send confirmation email"

session "Order complete!"  # But was it really?
```

**Why it's bad**: The order might be marked complete even if payment failed.

**Fix**: Use appropriate failure policy:

```prose
# Good: Fail-fast for critical operations
parallel:  # Default: fail-fast
  payment = session "Charge customer credit card"
  inventory = session "Reserve inventory"

# Only ship if both succeeded
session "Ship the product"
  context: { payment, inventory }

# Email can fail without blocking
try:
  session "Send confirmation email"
catch:
  session "Queue email for retry"
```

#### vague-discretion

Discretion conditions that are ambiguous or unmeasurable.

```prose
# Bad: What does "good enough" mean?
loop until **the output is good enough**:
  session "Improve output"

# Bad: Highly subjective
if **the user will be happy**:
  session "Ship it"
```

**Why it's bad**: The VM has no clear criteria for evaluation. Results are unpredictable.

**Fix**: Provide concrete, evaluatable criteria:

```prose
# Good: Specific criteria
loop until **all tests pass and code coverage exceeds 80%** (max: 10):
  session "Improve test coverage"

# Good: Observable conditions
if **the response contains valid JSON with all required fields**:
  session "Process the response"
```

#### catch-and-swallow

Catching errors without meaningful handling. Hides problems without solving them.

```prose
# Bad: Silent swallow
try:
  session "Critical operation"
catch:
  # Nothing here - error disappears
```

**Why it's bad**: Errors vanish. No recovery, no logging, no visibility.

**Fix**: Handle errors meaningfully:

```prose
# Good: Meaningful handling
try:
  session "Critical operation"
catch as err:
  session "Log error for investigation"
    context: err
  session "Execute fallback procedure"
  # Or rethrow if unrecoverable:
  throw
```

---

## Cost Antipatterns

#### opus-for-everything

Using the most powerful (expensive) model for all tasks, including trivial ones.

```prose
# Bad: Opus for simple classification
agent classifier:
  model: opus
  prompt: "Categorize items as: spam, not-spam"

# Expensive for a binary classification
for email in emails:
  session: classifier
    prompt: "Classify: {email}"
```

**Why it's bad**: Opus costs significantly more than haiku. Simple tasks don't benefit from advanced reasoning.

**Fix**: Match model to task complexity:

```prose
# Good: Haiku for simple tasks
agent classifier:
  model: haiku
  prompt: "Categorize items as: spam, not-spam"
```

#### context-bloat

Passing excessive context that the session doesn't need.

```prose
# Bad: Passing everything
let full_codebase = session "Read entire codebase"
let all_docs = session "Read all documentation"
let history = session "Get full git history"

session "Fix the typo in the README"
  context: [full_codebase, all_docs, history]  # Massive overkill
```

**Why it's bad**: Large contexts slow processing, increase costs, and can confuse the model with irrelevant information.

**Fix**: Pass minimal relevant context:

```prose
# Good: Minimal context
let readme = session "Read the README file"

session "Fix the typo in the README"
  context: readme
```

#### unnecessary-iteration

Looping when a single session would suffice.

```prose
# Bad: Loop for what could be one call
let items = ["apple", "banana", "cherry"]
for item in items:
  session "Describe {item}"
```

**Why it's bad**: Three sessions when one could handle all items. Session overhead multiplied.

**Fix**: Batch when possible:

```prose
# Good: Batch processing
let items = ["apple", "banana", "cherry"]
session "Describe each of these items: {items}"
```

#### redundant-computation

Computing the same thing multiple times.

```prose
# Bad: Redundant research
session "Research AI safety for security review"
session "Research AI safety for ethics review"
session "Research AI safety for compliance review"
```

**Why it's bad**: Same research done three times with slightly different framing.

**Fix**: Compute once, use many times:

```prose
# Good: Compute once
let research = session "Comprehensive research on AI safety"

parallel:
  session "Security review"
    context: research
  session "Ethics review"
    context: research
  session "Compliance review"
    context: research
```

---

## Performance Antipatterns

#### eager-over-computation

Computing everything upfront when only some results might be needed.

```prose
# Bad: Compute all branches even if only one is needed
parallel:
  simple_analysis = session "Simple analysis"
    model: haiku
  detailed_analysis = session "Detailed analysis"
    model: sonnet
  deep_analysis = session "Deep analysis"
    model: opus

# Then only use one based on some criterion
choice **appropriate depth**:
  option "Simple":
    session "Use simple"
      context: simple_analysis
  option "Detailed":
    session "Use detailed"
      context: detailed_analysis
  option "Deep":
    session "Use deep"
      context: deep_analysis
```

**Why it's bad**: All three analyses run even though only one is used.

**Fix**: Compute lazily:

```prose
# Good: Only compute what's needed
let initial = session "Initial assessment"
  model: haiku

choice **appropriate depth based on initial assessment**:
  option "Simple":
    session "Simple analysis"
      model: haiku
  option "Detailed":
    session "Detailed analysis"
      model: sonnet
  option "Deep":
    session "Deep analysis"
      model: opus
```

#### over-parallelization

Parallelizing so aggressively that overhead dominates or resources are exhausted.

```prose
# Bad: 100 parallel sessions
parallel for item in large_collection:  # 100 items
  session "Process {item}"
```

**Why it's bad**: May overwhelm the system. Coordination overhead can exceed parallelism benefits.

**Fix**: Batch or limit concurrency:

```prose
# Good: Process in batches
for batch in batches(large_collection, 10):
  parallel for item in batch:
    session "Process {item}"
```

#### premature-parallelization

Parallelizing tiny tasks where sequential would be simpler and fast enough.

```prose
# Bad: Parallel overkill for simple tasks
parallel:
  a = session "Add 2 + 2"
  b = session "Add 3 + 3"
  c = session "Add 4 + 4"
```

**Why it's bad**: Coordination overhead exceeds task time. Sequential would be simpler and possibly faster.

**Fix**: Keep it simple:

```prose
# Good: Sequential for trivial tasks
session "Add 2+2, 3+3, and 4+4"
```

#### synchronous-fire-and-forget

Waiting for operations whose results you don't need.

```prose
# Bad: Waiting for logging
session "Do important work"
session "Log the result"  # Don't need to wait for this
session "Continue with next important work"
```

**Why it's bad**: Main workflow blocked by non-critical operation.

**Fix**: Use appropriate patterns for fire-and-forget operations, or batch logging:

```prose
# Better: Batch non-critical work
session "Do important work"
session "Continue with next important work"
# ... more important work ...

# Log everything at the end or async
session "Log all operations"
```

---

## Maintainability Antipatterns

#### magic-strings

Hardcoded prompts repeated throughout the program.

```prose
# Bad: Same prompt in multiple places
session "You are a helpful assistant. Analyze this code for bugs."
# ... later ...
session "You are a helpful assistant. Analyze this code for bugs."
# ... even later ...
session "You are a helpful assistent. Analyze this code for bugs."  # Typo!
```

**Why it's bad**: Inconsistency when updating. Typos go unnoticed.

**Fix**: Use agents:

```prose
# Good: Single source of truth
agent code-analyst:
  model: sonnet
  prompt: "You are a helpful assistant. Analyze code for bugs."

session: code-analyst
  prompt: "Analyze the auth module"
session: code-analyst
  prompt: "Analyze the payment module"
```

#### opaque-workflow

No structure or comments indicating what's happening.

```prose
# Bad: What is this doing?
let x = session "A"
let y = session "B"
  context: x
parallel:
  z = session "C"
    context: y
  w = session "D"
session "E"
  context: [z, w]
```

**Why it's bad**: Impossible to understand, debug, or modify.

**Fix**: Use meaningful names and structure:

```prose
# Good: Clear intent
# Phase 1: Research
let research = session "Gather background information"

# Phase 2: Analysis
let analysis = session "Analyze research findings"
  context: research

# Phase 3: Parallel evaluation
parallel:
  technical_eval = session "Technical feasibility assessment"
    context: analysis
  business_eval = session "Business viability assessment"
    context: analysis

# Phase 4: Synthesis
session "Create final recommendation"
  context: { technical_eval, business_eval }
```

#### implicit-dependencies

Relying on conversation history rather than explicit context.

```prose
# Bad: Implicit state
session "Set the project name to Acme"
session "Set the deadline to Friday"
session "Now create a project plan"  # Hopes previous info is remembered
```

**Why it's bad**: Relies on VM implementation details. Fragile across refactoring.

**Fix**: Explicit context:

```prose
# Good: Explicit state
let config = session "Define project: name=Acme, deadline=Friday"

session "Create a project plan"
  context: config
```

#### mixed-concerns-agent

Agents with prompts that cover too many responsibilities.

```prose
# Bad: Jack of all trades
agent super-agent:
  model: opus
  prompt: """
    You are an expert in:
    - Security analysis
    - Performance optimization
    - Code review
    - Documentation
    - Testing
    - DevOps
    - Project management
    - Customer communication
    When asked, perform any of these tasks.
  """
```

**Why it's bad**: No focus means mediocre results across the board. Can't optimize model choice.

**Fix**: Specialized agents:

```prose
# Good: Focused expertise
agent security-expert:
  model: sonnet
  prompt: "You are a security analyst. Focus only on security concerns."

agent performance-expert:
  model: sonnet
  prompt: "You are a performance engineer. Focus only on optimization."

agent technical-writer:
  model: haiku
  prompt: "You write clear technical documentation."
```

---

## Logic Antipatterns

#### infinite-refinement

Loops that can never satisfy their exit condition.

```prose
# Bad: Perfection is impossible
loop until **the code has zero bugs**:
  session "Find and fix bugs"
```

**Why it's bad**: Zero bugs is unachievable. Loop runs until max (if specified) or forever.

**Fix**: Use achievable conditions:

```prose
# Good: Achievable condition
loop until **all known bugs are fixed** (max: 20):
  session "Find and fix the next bug"

# Or: Diminishing returns
loop until **no significant bugs found in last iteration** (max: 10):
  session "Search for bugs"
```

#### assertion-as-action

Using conditions as actions—checking something without acting on the result.

```prose
# Bad: Check but don't use result
session "Check if the system is healthy"
session "Deploy to production"  # Deploys regardless!
```

**Why it's bad**: The health check result isn't used. Deploy happens unconditionally.

**Fix**: Use conditional execution:

```prose
# Good: Act on the check
let health = session "Check if the system is healthy"

if **system is healthy**:
  session "Deploy to production"
else:
  session "Alert on-call and skip deployment"
    context: health
```

#### false-parallelism

Putting sequential-dependent operations in a parallel block.

```prose
# Bad: These aren't independent!
parallel:
  data = session "Fetch data"
  processed = session "Process the data"  # Needs data!
    context: data
  stored = session "Store processed data"  # Needs processed!
    context: processed
```

**Why it's bad**: Despite being in parallel, these must run sequentially due to dependencies.

**Fix**: Be honest about dependencies:

```prose
# Good: Sequential where needed
let data = session "Fetch data"
let processed = session "Process the data"
  context: data
session "Store processed data"
  context: processed
```

#### exception-as-flow-control

Using try/catch for expected conditions rather than exceptional errors.

```prose
# Bad: Exceptions for normal flow
try:
  session "Find the optional config file"
catch:
  session "Use default configuration"
```

**Why it's bad**: Missing config is expected, not exceptional. Obscures actual errors.

**Fix**: Use conditionals for expected cases:

```prose
# Good: Conditional for expected case
let config_exists = session "Check if config file exists"

if **config file exists**:
  session "Load configuration from file"
else:
  session "Use default configuration"
```

#### excessive-user-checkpoints

Prompting the user for decisions that have obvious or predictable answers.

```prose
# Antipattern: Asking the obvious
input "Blocking error detected. Investigate?"  # Always yes
input "Diagnosis complete. Proceed to triage?"  # Always yes
input "Tests pass. Deploy?"  # Almost always yes
```

**Why it's bad**: Each checkpoint is a round-trip waiting for user input. If the answer is predictable 90% of the time, you're adding latency for no value.

**Fix**: Auto-proceed for obvious cases, only prompt when genuinely ambiguous:

```prose
# Good: Auto-proceed with escape hatches for edge cases
if observation.blocking_error:
  # Auto-investigate (don't ask - of course we investigate errors)
  let diagnosis = do investigate(...)

  # Only ask if genuinely ambiguous
  if diagnosis.confidence == "low":
    input "Low confidence diagnosis. Proceed anyway?"

  # Auto-deploy if tests pass (but log for audit)
  if fix.tests_pass:
    do deploy(...)
```

**When checkpoints ARE right**: Irreversible actions (production deployments to critical systems), expensive operations (long-running jobs), or genuine decision points where the user's preference isn't predictable.

#### fixed-observation-window

Waiting for a predetermined duration when the signal arrived early.

```prose
# Antipattern: Fixed window regardless of findings
loop 30 times (wait: 2s each):  # Always 60 seconds
  resume: observer
    prompt: "Keep watching the stream"
# Runs all 30 iterations even if blocking error detected on iteration 1
```

**Why it's bad**: Wastes time when the answer is already known. If the observer detected a fatal error at +5 seconds, why wait another 55 seconds?

**Fix**: Use signal-driven exit conditions:

```prose
# Good: Exit on significant signal
loop until **blocking error OR completion** (max: 30):
  resume: observer
    prompt: "Watch the stream. Signal IMMEDIATELY on blocking errors."
# Exits as soon as something significant happens
```

Or use `early_exit` if your runtime supports it:

```prose
# Good: Explicit early exit
let observation = session: observer
  prompt: "Monitor for errors. Signal immediately if found."
  timeout: 120s
  early_exit: **blocking_error detected**
```

---

## Security Antipatterns

#### unvalidated-input

Passing external input directly to sessions without validation.

```prose
# Bad: Direct injection
let user_input = external_source

session "Execute this command: {user_input}"
```

**Why it's bad**: User could inject malicious prompts or commands.

**Fix**: Validate and sanitize:

```prose
# Good: Validate first
let user_input = external_source
let validated = session "Validate this input is a safe search query"
  context: user_input

if **input is valid and safe**:
  session "Search for: {validated}"
else:
  throw "Invalid input rejected"
```

#### overprivileged-agents

Agents with more permissions than they need.

```prose
# Bad: Full access for simple task
agent file-reader:
  permissions:
    read: ["**/*"]
    write: ["**/*"]
    bash: allow
    network: allow

session: file-reader
  prompt: "Read the README.md file"
```

**Why it's bad**: Task only needs to read one file but has full system access.

**Fix**: Least privilege:

```prose
# Good: Minimal permissions
agent file-reader:
  permissions:
    read: ["README.md"]
    write: []
    bash: deny
    network: deny
```

---

## Summary

Antipatterns emerge from:

1. **Laziness**: Copy-paste instead of abstraction, implicit instead of explicit
2. **Over-engineering**: Parallelizing everything, using opus for all tasks
3. **Under-engineering**: No error handling, unbounded loops, vague conditions
4. **Unclear thinking**: God sessions, mixed concerns, spaghetti context

When reviewing OpenProse programs, ask:

- Can independent work be parallelized?
- Are loops bounded?
- Are errors handled?
- Is context minimal and explicit?
- Are models matched to task complexity?
- Are agents focused and reusable?
- Would a stranger understand this code?

Fix antipatterns early. They compound over time into unmaintainable systems.


path: guidance/patterns.md
content: ---
role: best-practices
summary: |
  Design patterns for robust, efficient, and maintainable OpenProse programs.
  Read this file when authoring new programs or reviewing existing ones.
see-also:
  - prose.md: Execution semantics, how to run programs
  - compiler.md: Full syntax grammar, validation rules
  - antipatterns.md: Patterns to avoid
---

# OpenProse Design Patterns

This document catalogs proven patterns for orchestrating AI agents effectively. Each pattern addresses specific concerns: robustness, cost efficiency, speed, maintainability, or self-improvement capability.

---

## Structural Patterns

#### parallel-independent-work

When tasks have no data dependencies, execute them concurrently. This maximizes throughput and minimizes wall-clock time.

```prose
# Good: Independent research runs in parallel
parallel:
  market = session "Research market trends"
  tech = session "Research technology landscape"
  competition = session "Analyze competitor products"

session "Synthesize findings"
  context: { market, tech, competition }
```

The synthesis session waits for all branches, but total time equals the longest branch rather than the sum of all branches.

#### fan-out-fan-in

For processing collections, fan out to parallel workers then collect results. Use `parallel for` instead of manual parallel branches.

```prose
let topics = ["AI safety", "interpretability", "alignment", "robustness"]

parallel for topic in topics:
  session "Deep dive research on {topic}"

session "Create unified report from all research"
```

This scales naturally with collection size and keeps code DRY.

#### pipeline-composition

Chain transformations using pipe operators for readable data flow. Each stage has a single responsibility.

```prose
let candidates = session "Generate 10 startup ideas"

let result = candidates
  | filter:
      session "Is this idea technically feasible? yes/no"
        context: item
  | map:
      session "Expand this idea into a one-page pitch"
        context: item
  | reduce(best, current):
      session "Compare these two pitches, return the stronger one"
        context: [best, current]
```

#### agent-specialization

Define agents with focused expertise. Specialized agents produce better results than generalist prompts.

```prose
agent security-reviewer:
  model: sonnet
  prompt: """
    You are a security expert. Focus exclusively on:
    - Authentication and authorization flaws
    - Injection vulnerabilities
    - Data exposure risks
    Ignore style, performance, and other concerns.
  """

agent performance-reviewer:
  model: sonnet
  prompt: """
    You are a performance engineer. Focus exclusively on:
    - Algorithmic complexity
    - Memory usage patterns
    - I/O bottlenecks
    Ignore security, style, and other concerns.
  """
```

#### reusable-blocks

Extract repeated workflows into parameterized blocks. Blocks are the functions of OpenProse.

```prose
block review-and-revise(artifact, criteria):
  let feedback = session "Review {artifact} against {criteria}"
  session "Revise {artifact} based on feedback"
    context: feedback

# Reuse the pattern
do review-and-revise("the architecture doc", "clarity and completeness")
do review-and-revise("the API design", "consistency and usability")
do review-and-revise("the test plan", "coverage and edge cases")
```

---

## Robustness Patterns

#### bounded-iteration

Always constrain loops with `max:` to prevent runaway execution. Even well-crafted conditions can fail to terminate.

```prose
# Good: Explicit upper bound
loop until **all tests pass** (max: 20):
  session "Identify and fix the next failing test"

# The program will terminate even if tests never fully pass
```

#### graceful-degradation

Use `on-fail: "continue"` when partial results are acceptable. Collect what you can rather than failing entirely.

```prose
parallel (on-fail: "continue"):
  primary = session "Query primary data source"
  backup = session "Query backup data source"
  cache = session "Check local cache"

# Continue with whatever succeeded
session "Merge available data"
  context: { primary, backup, cache }
```

#### retry-with-backoff

External services fail transiently. Retry with exponential backoff to handle rate limits and temporary outages.

```prose
session "Call external API"
  retry: 5
  backoff: "exponential"
```

For critical paths, combine retry with fallback:

```prose
try:
  session "Call primary API"
    retry: 3
    backoff: "exponential"
catch:
  session "Use fallback data source"
```

#### error-context-capture

Capture error context for intelligent recovery. The error variable provides information for diagnostic or remediation sessions.

```prose
try:
  session "Deploy to production"
catch as err:
  session "Analyze deployment failure and suggest fixes"
    context: err
  session "Attempt automatic remediation"
    context: err
```

#### defensive-context

Validate assumptions before expensive operations. Cheap checks prevent wasted computation.

```prose
let prereqs = session "Check all prerequisites: API keys, permissions, dependencies"

if **prerequisites are not met**:
  session "Report missing prerequisites and exit"
    context: prereqs
  throw "Prerequisites not satisfied"

# Expensive operations only run if prereqs pass
session "Execute main workflow"
```

---

## Cost Efficiency Patterns

#### model-tiering

Match model capability to task complexity:

| Model | Best For | Examples |
|-------|----------|----------|
| **Sonnet 4.5** | Orchestration, control flow, coordination | VM execution, captain's chair, workflow routing |
| **Opus 4.5** | Hard/difficult work requiring deep reasoning | Complex analysis, strategic decisions, novel problem-solving |
| **Haiku** | Simple, self-evident tasks (use sparingly) | Classification, summarization, formatting |

**Key insight:** Sonnet 4.5 excels at *orchestrating* agents and managing control flow—it's the ideal model for the OpenProse VM itself and for "captain" agents that coordinate work. Opus 4.5 should be reserved for agents doing genuinely difficult intellectual work. Haiku can handle simple tasks but should generally be avoided where quality matters.

**Detailed task-to-model mapping:**

| Task Type | Model | Rationale |
|-----------|-------|-----------|
| Orchestration, routing, coordination | Sonnet | Fast, good at following structure |
| Investigation, debugging, diagnosis | Sonnet | Structured analysis, checklist-style work |
| Triage, classification, categorization | Sonnet | Clear criteria, deterministic decisions |
| Code review, verification (checklist) | Sonnet | Following defined review criteria |
| Simple implementation, fixes | Sonnet | Applying known patterns |
| Complex multi-file synthesis | Opus | Needs to hold many things in context |
| Novel architecture, strategic planning | Opus | Requires creative problem-solving |
| Ambiguous problems, unclear requirements | Opus | Needs to reason through uncertainty |

**Rule of thumb:** If you can write a checklist for the task, Sonnet can do it. If the task requires genuine creativity or navigating ambiguity, use Opus.

```prose
agent captain:
  model: sonnet  # Orchestration and coordination
  persist: true  # Execution-scoped (dies with run)
  prompt: "You coordinate the team and review work"

agent researcher:
  model: opus  # Hard analytical work
  prompt: "You perform deep research and analysis"

agent formatter:
  model: haiku  # Simple transformation (use sparingly)
  prompt: "You format text into consistent structure"

agent preferences:
  model: sonnet
  persist: user  # User-scoped (survives across projects)
  prompt: "You remember user preferences and patterns"

# Captain orchestrates, specialists do the hard work
session: captain
  prompt: "Plan the research approach"

let findings = session: researcher
  prompt: "Investigate the technical architecture"

resume: captain
  prompt: "Review findings and determine next steps"
  context: findings
```

#### context-minimization

Pass only relevant context. Large contexts slow processing and increase costs.

```prose
# Bad: Passing everything
session "Write executive summary"
  context: [raw_data, analysis, methodology, appendices, references]

# Good: Pass only what's needed
let key_findings = session "Extract key findings from analysis"
  context: analysis

session "Write executive summary"
  context: key_findings
```

#### early-termination

Exit loops as soon as the goal is achieved. Don't iterate unnecessarily.

```prose
# The condition is checked each iteration
loop until **solution found and verified** (max: 10):
  session "Generate potential solution"
  session "Verify solution correctness"
# Exits immediately when condition is met, not after max iterations
```

#### early-signal-exit

When observing or monitoring, exit as soon as you have a definitive answer—don't wait for the full observation window.

```prose
# Good: Exit on signal
let observation = session: observer
  prompt: "Watch the stream. Signal immediately if you detect a blocking error."
  timeout: 120s
  early_exit: **blocking_error detected**

# Bad: Fixed observation window
loop 30 times:
  resume: observer
    prompt: "Keep watching..."  # Even if error was obvious at iteration 2
```

This respects signals when they arrive rather than waiting for arbitrary timeouts.

#### defaults-over-prompts

For standard configuration, use constants or environment variables. Only prompt when genuinely variable.

```prose
# Good: Sensible defaults
const API_URL = "https://api.example.com"
const TEST_PROGRAM = "# Simple test\nsession 'Hello'"

# Slower: Prompting for known values
let api_url = input "Enter API URL"  # Usually the same value
let program = input "Enter test program"  # Usually the same value
```

If 90% of runs use the same value, hardcode it. Let users override via CLI args if needed.

#### race-for-speed

When any valid result suffices, race multiple approaches and take the first success.

```prose
parallel ("first"):
  session "Try algorithm A"
  session "Try algorithm B"
  session "Try algorithm C"

# Continues as soon as any approach completes
session "Use winning result"
```

#### batch-similar-work

Group similar operations to amortize overhead. One session with structured output beats many small sessions.

```prose
# Inefficient: Many small sessions
for file in files:
  session "Analyze {file}"

# Efficient: Batch analysis
session "Analyze all files and return structured findings for each"
  context: files
```

---

## Self-Improvement Patterns

#### self-verification-in-prompt

For tasks that would otherwise require a separate verifier, include verification as the final step in the prompt. This saves a round-trip while maintaining rigor.

```prose
# Good: Combined work + self-verification
agent investigator:
  model: sonnet
  prompt: """Diagnose the error.
  1. Examine code paths
  2. Check logs and state
  3. Form hypothesis
  4. BEFORE OUTPUTTING: Verify your evidence supports your conclusion.

  Output only if confident. If uncertain, state what's missing."""

# Slower: Separate verifier agent
let diagnosis = session: researcher
  prompt: "Investigate the error"
let verification = session: verifier
  prompt: "Verify this diagnosis"  # Extra round-trip
  context: diagnosis
```

Use a separate verifier when you need genuine adversarial review (different perspective), but for self-consistency checks, bake verification into the prompt.

#### iterative-refinement

Use feedback loops to progressively improve outputs. Each iteration builds on the previous.

```prose
let draft = session "Create initial draft"

loop until **draft meets quality bar** (max: 5):
  let critique = session "Critically evaluate this draft"
    context: draft
  draft = session "Improve draft based on critique"
    context: [draft, critique]

session "Finalize and publish"
  context: draft
```

#### multi-perspective-review

Gather diverse viewpoints before synthesis. Different lenses catch different issues.

```prose
parallel:
  user_perspective = session "Evaluate from end-user viewpoint"
  tech_perspective = session "Evaluate from engineering viewpoint"
  business_perspective = session "Evaluate from business viewpoint"

session "Synthesize feedback and prioritize improvements"
  context: { user_perspective, tech_perspective, business_perspective }
```

#### adversarial-validation

Use one agent to challenge another's work. Adversarial pressure improves robustness.

```prose
let proposal = session "Generate proposal"

let critique = session "Find flaws and weaknesses in this proposal"
  context: proposal

let defense = session "Address each critique with evidence or revisions"
  context: [proposal, critique]

session "Produce final proposal incorporating valid critiques"
  context: [proposal, critique, defense]
```

#### consensus-building

For critical decisions, require agreement between independent evaluators.

```prose
parallel:
  eval1 = session "Independently evaluate the solution"
  eval2 = session "Independently evaluate the solution"
  eval3 = session "Independently evaluate the solution"

loop until **evaluators agree** (max: 3):
  session "Identify points of disagreement"
    context: { eval1, eval2, eval3 }
  parallel:
    eval1 = session "Reconsider position given other perspectives"
      context: { eval1, eval2, eval3 }
    eval2 = session "Reconsider position given other perspectives"
      context: { eval1, eval2, eval3 }
    eval3 = session "Reconsider position given other perspectives"
      context: { eval1, eval2, eval3 }

session "Document consensus decision"
  context: { eval1, eval2, eval3 }
```

---

## Maintainability Patterns

#### descriptive-agent-names

Name agents for their role, not their implementation. Names should convey purpose.

```prose
# Good: Role-based naming
agent code-reviewer:
agent technical-writer:
agent data-analyst:

# Bad: Implementation-based naming
agent opus-agent:
agent session-1-handler:
agent helper:
```

#### prompt-as-contract

Write prompts that specify expected inputs and outputs. Clear contracts prevent misunderstandings.

```prose
agent json-extractor:
  model: haiku
  prompt: """
    Extract structured data from text.

    Input: Unstructured text containing entity information
    Output: JSON object with fields: name, date, amount, status

    If a field cannot be determined, use null.
    Never invent information not present in the input.
  """
```

#### separation-of-concerns

Each session should do one thing well. Combine simple sessions rather than creating complex ones.

```prose
# Good: Single responsibility per session
let data = session "Fetch and validate input data"
let analysis = session "Analyze data for patterns"
  context: data
let recommendations = session "Generate recommendations from analysis"
  context: analysis
session "Format recommendations as report"
  context: recommendations

# Bad: God session
session "Fetch data, analyze it, generate recommendations, and format a report"
```

#### explicit-context-flow

Make data flow visible through explicit context passing. Avoid relying on implicit conversation history.

```prose
# Good: Explicit flow
let step1 = session "First step"
let step2 = session "Second step"
  context: step1
let step3 = session "Third step"
  context: [step1, step2]

# Bad: Implicit flow (relies on conversation state)
session "First step"
session "Second step using previous results"
session "Third step using all previous"
```

---

## Performance Patterns

#### lazy-evaluation

Defer expensive operations until their results are needed. Don't compute what might not be used.

```prose
session "Assess situation"

if **detailed analysis needed**:
  # Expensive operations only when necessary
  parallel:
    deep_analysis = session "Perform deep analysis"
      model: opus
    historical = session "Gather historical comparisons"
  session "Comprehensive report"
    context: { deep_analysis, historical }
else:
  session "Quick summary"
    model: haiku
```

#### progressive-disclosure

Start with fast, cheap operations. Escalate to expensive ones only when needed.

```prose
# Tier 1: Fast screening (haiku)
let initial = session "Quick assessment"
  model: haiku

if **needs deeper review**:
  # Tier 2: Moderate analysis (sonnet)
  let detailed = session "Detailed analysis"
    model: sonnet
    context: initial

  if **needs expert review**:
    # Tier 3: Deep reasoning (opus)
    session "Expert-level analysis"
      model: opus
      context: [initial, detailed]
```

#### work-stealing

Use `parallel ("any", count: N)` to get results as fast as possible from a pool of workers.

```prose
# Get 3 good ideas as fast as possible from 5 parallel attempts
parallel ("any", count: 3, on-fail: "ignore"):
  session "Generate creative solution approach 1"
  session "Generate creative solution approach 2"
  session "Generate creative solution approach 3"
  session "Generate creative solution approach 4"
  session "Generate creative solution approach 5"

session "Select best from the first 3 completed"
```

---

## Composition Patterns

#### workflow-template

Create blocks that encode entire workflow patterns. Instantiate with different parameters.

```prose
block research-report(topic, depth):
  let research = session "Research {topic} at {depth} level"
  let analysis = session "Analyze findings about {topic}"
    context: research
  let report = session "Write {depth}-level report on {topic}"
    context: [research, analysis]

# Instantiate for different needs
do research-report("market trends", "executive")
do research-report("technical architecture", "detailed")
do research-report("competitive landscape", "comprehensive")
```

#### middleware-pattern

Wrap sessions with cross-cutting concerns like logging, timing, or validation.

```prose
block with-validation(task, validator):
  let result = session "{task}"
  let valid = session "{validator}"
    context: result
  if **validation failed**:
    throw "Validation failed for: {task}"

do with-validation("Generate SQL query", "Check SQL for injection vulnerabilities")
do with-validation("Generate config file", "Validate config syntax")
```

#### circuit-breaker

After repeated failures, stop trying and fail fast. Prevents cascading failures.

```prose
let failures = 0
let max_failures = 3

loop while **service needed and failures < max_failures** (max: 10):
  try:
    session "Call external service"
    # Reset on success
    failures = 0
  catch:
    failures = failures + 1
    if **failures >= max_failures**:
      session "Circuit open - using fallback"
      throw "Service unavailable"
```

---

## Observability Patterns

#### checkpoint-narration

For long workflows, emit progress markers. Helps with debugging and monitoring.

```prose
session "Phase 1: Data Collection"
# ... collection work ...

session "Phase 2: Analysis"
# ... analysis work ...

session "Phase 3: Report Generation"
# ... report work ...

session "Phase 4: Quality Assurance"
# ... QA work ...
```

#### structured-output-contracts

Request structured outputs that can be reliably parsed and validated.

```prose
agent structured-reviewer:
  model: sonnet
  prompt: """
    Always respond with this exact JSON structure:
    {
      "verdict": "pass" | "fail" | "needs_review",
      "issues": [{"severity": "high"|"medium"|"low", "description": "..."}],
      "suggestions": ["..."]
    }
  """

let review = session: structured-reviewer
  prompt: "Review this code for security issues"
```

---

## Summary

The most effective OpenProse programs combine these patterns:

1. **Structure**: Parallelize independent work, use blocks for reuse
2. **Robustness**: Bound loops, handle errors, retry transient failures
3. **Efficiency**: Tier models, minimize context, terminate early
4. **Quality**: Iterate, get multiple perspectives, validate adversarially
5. **Maintainability**: Name clearly, separate concerns, make flow explicit

Choose patterns based on your specific constraints. A quick prototype prioritizes speed over robustness. A production workflow prioritizes reliability over cost. A research exploration prioritizes thoroughness over efficiency.


path: guidance/system-prompt.md
content: ---
role: system-prompt-enforcement
summary: |
  Strict system prompt addition for OpenProse VM instances. This enforces
  that the agent ONLY executes .prose programs and embodies the VM correctly.
  Append this to system prompts for dedicated OpenProse execution instances.
---

# OpenProse VM System Prompt Enforcement

**⚠️ CRITICAL: THIS INSTANCE IS DEDICATED TO OPENPROSE EXECUTION ONLY ⚠️**

This agent instance is configured exclusively for executing OpenProse (`.prose`) programs. You MUST NOT execute, interpret, or respond to any non-Prose tasks. If a user requests anything other than a `prose` command or `.prose` program execution, you MUST refuse and redirect them to use a general-purpose agent.

## Your Role: You ARE the OpenProse VM

You are not simulating a virtual machine—you **ARE** the OpenProse VM. When executing a `.prose` program:

- **Your conversation history** = The VM's working memory
- **Your Task tool calls** = The VM's instruction execution
- **Your state tracking** = The VM's execution trace
- **Your judgment on `**...**`** = The VM's intelligent evaluation

### Core Execution Principles

1. **Strict Structure**: Follow the program structure exactly as written
2. **Intelligent Evaluation**: Use judgment only for discretion conditions (`**...**`)
3. **Real Execution**: Each `session` spawns a real subagent via Task tool
4. **State Persistence**: Track state in `.prose/runs/{id}/` or via narration protocol

## Execution Model

### Sessions = Function Calls

Every `session` statement triggers a Task tool call:

```prose
session "Research quantum computing"
```

Execute as:

```
Task({
  description: "OpenProse session",
  prompt: "Research quantum computing",
  subagent_type: "general-purpose"
})
```

### Context Passing (By Reference)

The VM passes context **by reference**, never by value:

```
Context (by reference):
- research: .prose/runs/{id}/bindings/research.md

Read this file to access the content. The VM never holds full binding values.
```

### Parallel Execution

`parallel:` blocks spawn multiple sessions concurrently—call all Task tools in a single response:

```prose
parallel:
  a = session "Task A"
  b = session "Task B"
```

Execute by calling both Task tools simultaneously, then wait for all to complete.

### Persistent Agents

- `session: agent` = Fresh start (ignores memory)
- `resume: agent` = Load memory, continue with context

For `resume:`, include the agent's memory file path and instruct the subagent to read/update it.

### Control Flow

- **Loops**: Evaluate condition, execute body, repeat until condition met or max reached
- **Try/Catch**: Execute try, catch on error, always execute finally
- **Choice/If**: Evaluate conditions, execute first matching branch only
- **Blocks**: Push frame, bind arguments, execute body, pop frame

## State Management

Default: File-system state in `.prose/runs/{id}/`

- `state.md` = VM execution state (written by VM only)
- `bindings/{name}.md` = Variable values (written by subagents)
- `agents/{name}/memory.md` = Persistent agent memory

Subagents write their outputs directly to binding files and return confirmation messages (not full content) to the VM.

## File Location Index

**Do NOT search for OpenProse documentation files.** All skill files are installed in the skills directory. Use the following paths (with placeholder `{OPENPROSE_SKILL_DIR}` that will be replaced with the actual skills directory path):

| File                    | Location                                      | Purpose                                        |
| ----------------------- | --------------------------------------------- | ---------------------------------------------- |
| `prose.md`              | `{OPENPROSE_SKILL_DIR}/prose.md`              | VM semantics (load to run programs)            |
| `state/filesystem.md`   | `{OPENPROSE_SKILL_DIR}/state/filesystem.md`   | File-based state (default, load with VM)       |
| `state/in-context.md`   | `{OPENPROSE_SKILL_DIR}/state/in-context.md`   | In-context state (on request)                  |
| `state/sqlite.md`       | `{OPENPROSE_SKILL_DIR}/state/sqlite.md`       | SQLite state (experimental, on request)        |
| `state/postgres.md`     | `{OPENPROSE_SKILL_DIR}/state/postgres.md`     | PostgreSQL state (experimental, on request)    |
| `primitives/session.md` | `{OPENPROSE_SKILL_DIR}/primitives/session.md` | Session context and compaction guidelines      |
| `compiler.md`           | `{OPENPROSE_SKILL_DIR}/compiler.md`           | Compiler/validator (load only on request)      |
| `help.md`               | `{OPENPROSE_SKILL_DIR}/help.md`               | Help, FAQs, onboarding (load for `prose help`) |

**When to load these files:**

- **Always load `prose.md`** when executing a `.prose` program
- **Load `state/filesystem.md`** with `prose.md` (default state mode)
- **Load `state/in-context.md`** only if user requests `--in-context` or says "use in-context state"
- **Load `state/sqlite.md`** only if user requests `--state=sqlite` (requires sqlite3 CLI)
- **Load `state/postgres.md`** only if user requests `--state=postgres` (requires psql + PostgreSQL)
- **Load `primitives/session.md`** when working with persistent agents (`resume:`)
- **Load `compiler.md`** only when user explicitly requests compilation or validation
- **Load `help.md`** only for `prose help` command

Never search the user's workspace for these files—they are installed in the skills directory.

## Critical Rules

### ⛔ DO NOT:

- Execute any non-Prose code or scripts
- Respond to general programming questions
- Perform tasks outside `.prose` program execution
- Skip program structure or modify execution flow
- Hold full binding values in VM context (use references only)

### ✅ DO:

- Execute `.prose` programs strictly according to structure
- Spawn sessions via Task tool for every `session` statement
- Track state in `.prose/runs/{id}/` directory
- Pass context by reference (file paths, not content)
- Evaluate discretion conditions (`**...**`) intelligently
- Refuse non-Prose requests and redirect to general-purpose agent

## When User Requests Non-Prose Tasks

**Standard Response:**

```
⚠️ This agent instance is dedicated exclusively to executing OpenProse programs.

I can only execute:
- `prose run <file.prose>`
- `prose compile <file>`
- `prose help`
- `prose examples`
- Other `prose` commands

For general programming tasks, please use a general-purpose agent instance.
```

## Execution Algorithm (Simplified)

1. Parse program structure (use statements, inputs, agents, blocks)
2. Bind inputs from caller or prompt user if missing
3. For each statement in order:
   - `session` → Task tool call, await result
   - `resume` → Load memory, Task tool call, await result
   - `let/const` → Execute RHS, bind result
   - `parallel` → Spawn all branches concurrently, await per strategy
   - `loop` → Evaluate condition, execute body, repeat
   - `try/catch` → Execute try, catch on error, always finally
   - `choice/if` → Evaluate conditions, execute matching branch
   - `do block` → Push frame, bind args, execute body, pop frame
4. Collect output bindings
5. Return outputs to caller

## Remember

**You are the VM. The program is the instruction set. Execute it precisely, intelligently, and exclusively.**


path: help.md
content: # OpenProse Help

Load this file when a user invokes `prose help` or asks about OpenProse.

---

## Welcome

OpenProse is a programming language for AI sessions. You write structured programs that orchestrate AI agents, and the VM (this session) executes them by spawning real subagents.

**A long-running AI session is a Turing-complete computer. OpenProse is a programming language for it.**

---

## What Do You Want to Automate?

When a user invokes `prose help`, guide them toward defining what they want to build. Use the AskUserQuestion tool:

```
Question: "What would you like to automate with OpenProse?"
Header: "Goal"
Options:
  1. "Run a workflow" - "I have a .prose file to execute"
  2. "Build something new" - "Help me create a program for a specific task"
  3. "Learn the syntax" - "Show me examples and explain how it works"
  4. "Explore possibilities" - "What can OpenProse do?"
```

**After the user responds:**

- **Run a workflow**: Ask for the file path, then load `prose.md` and execute
- **Build something new**: Ask them to describe their task, then help write a .prose program (load `guidance/patterns.md`)
- **Learn the syntax**: Show examples from `examples/`, explain the VM model
- **Explore possibilities**: Walk through key examples like `37-the-forge.prose` or `28-gas-town.prose`



---

## Available Commands

| Command | What it does |
|---------|--------------|
| `prose help` | This help - guides you to what you need |
| `prose run <file>` | Execute a .prose program |
| `prose compile <file>` | Validate syntax without running |
| `prose update` | Migrate legacy workspace files |
| `prose examples` | Browse and run example programs |

---

## Quick Start

**Run an example:**
```
prose run examples/01-hello-world.prose
```

**Create your first program:**
```
prose help
→ Select "Build something new"
→ Describe what you want to automate
```

---

## FAQs

### What AI assistants are supported?

Claude Code, OpenCode, and Amp. Any harness that runs a sufficiently intelligent model and supports primitives like subagents are considered "Prose Complete".

### How is this a VM?

LLMs are simulators—when given a detailed system description, they don't just describe it, they simulate it. The `prose.md` spec describes a VM with enough fidelity that reading it induces simulation. But simulation with sufficient fidelity is implementation: each session spawns a real subagent, outputs are real artifacts, state persists in conversation history or files. The simulation is the execution.

### What's "intelligent IoC"?

Traditional IoC containers (Spring, Guice) wire up dependencies from configuration files. OpenProse's container is an AI session that wires up agents using understanding. It doesn't just match names—it understands context, intent, and can make intelligent decisions about execution.

### This looks like Python.

The syntax is intentionally familiar—Python's indentation-based structure is readable and self-evident. But the semantics are entirely different. OpenProse has no functions, no classes, no general-purpose computation. It has agents, sessions, and control flow. The design principle: structured but self-evident, unambiguous interpretation with minimal documentation.

### Why not English?

English is already an agent framework—we're not replacing it, we're structuring it. Plain English doesn't distinguish sequential from parallel, doesn't specify retry counts, doesn't scope variables. OpenProse uses English exactly where ambiguity is a feature (inside `**...**`), and structure everywhere else. The fourth wall syntax lets you lean on AI judgment precisely when you want to.

### Why not YAML?

We started with YAML. The problem: loops, conditionals, and variable declarations aren't self-evident in YAML—and when you try to make them self-evident, it gets verbose and ugly. More fundamentally, YAML optimizes for machine parseability. OpenProse optimizes for intelligent machine legibility. It doesn't need to be parsed—it needs to be understood. That's a different design target entirely.

### Why not LangChain/CrewAI/AutoGen?

Those are orchestration libraries—they coordinate agents from outside. OpenProse runs inside the agent session—the session itself is the IoC container. This means zero external dependencies and portability across any AI assistant. Switch from Claude Code to Codex? Your .prose files still work.

---

## Syntax at a Glance

```prose
session "prompt"              # Spawn subagent
agent name:                   # Define agent template
let x = session "..."         # Capture result
parallel:                     # Concurrent execution
repeat N:                     # Fixed loop
for x in items:               # Iteration
loop until **condition**:     # AI-evaluated loop
try: ... catch: ...           # Error handling
if **condition**: ...         # Conditional
choice **criteria**: option   # AI-selected branch
block name(params):           # Reusable block
do blockname(args)            # Invoke block
items | map: ...              # Pipeline
```

For complete syntax and validation rules, see `compiler.md`.

---

## Examples

The `examples/` directory contains 37 example programs:

| Range | Category |
|-------|----------|
| 01-08 | Basics (hello world, research, code review, debugging) |
| 09-12 | Agents and skills |
| 13-15 | Variables and composition |
| 16-19 | Parallel execution |
| 20-21 | Loops and pipelines |
| 22-23 | Error handling |
| 24-27 | Advanced (choice, conditionals, blocks, interpolation) |
| 28 | Gas Town (multi-agent orchestration) |
| 29-31 | Captain's chair pattern (persistent orchestrator) |
| 33-36 | Production workflows (PR auto-fix, content pipeline, feature factory, bug hunter) |
| 37 | The Forge (build a browser from scratch) |

**Recommended starting points:**
- `01-hello-world.prose` - Simplest possible program
- `16-parallel-reviews.prose` - See parallel execution
- `37-the-forge.prose` - Watch AI build a web browser


path: lib/README.md
content: # OpenProse Standard Library

Core programs that ship with OpenProse. Production-quality, well-tested programs for common tasks.

## Programs

### Evaluation & Improvement

| Program | Description |
|---------|-------------|
| `inspector.prose` | Post-run analysis for runtime fidelity and task effectiveness |
| `vm-improver.prose` | Analyzes inspections and proposes PRs to improve the VM |
| `program-improver.prose` | Analyzes inspections and proposes PRs to improve .prose source |
| `cost-analyzer.prose` | Token usage and cost pattern analysis |
| `calibrator.prose` | Validates light evaluations against deep evaluations |
| `error-forensics.prose` | Root cause analysis for failed runs |

### Memory

| Program | Description |
|---------|-------------|
| `user-memory.prose` | Cross-project persistent personal memory |
| `project-memory.prose` | Project-scoped institutional memory |

## The Improvement Loop

The evaluation programs form a recursive improvement cycle:

```
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   Run Program  ──►  Inspector  ──►  VM Improver ──► PR     │
│        ▲                │                                   │
│        │                ▼                                   │
│        │         Program Improver ──► PR                    │
│        │                │                                   │
│        └────────────────┘                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

Supporting analysis:
- **cost-analyzer** — Where does the money go? Optimization opportunities.
- **calibrator** — Are cheap evaluations reliable proxies for expensive ones?
- **error-forensics** — Why did a run fail? Root cause analysis.

## Usage

```bash
# Inspect a completed run
prose run lib/inspector.prose
# Inputs: run_path, depth (light|deep), target (vm|task|all)

# Propose VM improvements
prose run lib/vm-improver.prose
# Inputs: inspection_path, prose_repo

# Propose program improvements
prose run lib/program-improver.prose
# Inputs: inspection_path, run_path

# Analyze costs
prose run lib/cost-analyzer.prose
# Inputs: run_path, scope (single|compare|trend)

# Validate light vs deep evaluation
prose run lib/calibrator.prose
# Inputs: run_paths, sample_size

# Investigate failures
prose run lib/error-forensics.prose
# Inputs: run_path, focus (vm|program|context|external)

# Memory programs (recommend sqlite+ backend)
prose run lib/user-memory.prose --backend sqlite+
# Inputs: mode (teach|query|reflect), content

prose run lib/project-memory.prose --backend sqlite+
# Inputs: mode (ingest|query|update|summarize), content
```

## Memory Programs

The memory programs use persistent agents to accumulate knowledge:

**user-memory** (`persist: user`)
- Learns your preferences, decisions, patterns across all projects
- Remembers mistakes and lessons learned
- Answers questions from accumulated knowledge

**project-memory** (`persist: project`)
- Understands this project's architecture and decisions
- Tracks why things are the way they are
- Answers questions with project-specific context

Both recommend `--backend sqlite+` for durable persistence.

## Design Principles

1. **Production-ready** — Tested, documented, handles edge cases
2. **Composable** — Can be imported via `use` in other programs
3. **User-scoped state** — Cross-project utilities use `persist: user`
4. **Minimal dependencies** — No external services required
5. **Clear contracts** — Well-defined inputs and outputs
6. **Incremental value** — Useful in simple mode, more powerful with depth


path: primitives/session.md
content: ---
role: session-context-management
summary: |
  Guidelines for subagents on context handling, state management, and memory compaction.
  This file is loaded into all subagent sessions at start time to ensure consistent
  behavior around state persistence and context flow.
see-also:
  - ../prose.md: VM execution semantics
  - ../compiler.md: Full language specification
  - ../state/filesystem.md: File-system state management (default)
  - ../state/in-context.md: In-context state management (on request)
  - ../state/sqlite.md: SQLite state management (experimental)
  - ../state/postgres.md: PostgreSQL state management (experimental)
---

# Session Context Management

You are a subagent operating within an OpenProse program. This document explains how to work with the context you receive and how to preserve state for future sessions.

---

## 1. Understanding Your Context Layers

When you start, you receive context from multiple sources. Understand what each represents:

### 1.1 Outer Agent State

The **outer agent state** is context from the orchestrating VM or parent agent. It tells you:

- What program is running
- Where you are in the execution flow
- What has happened in prior steps

Look for markers like:

```
## Execution Context
Program: feature-implementation.prose
Current phase: Implementation
Prior steps completed: [plan, design]
```

**How to use it:** This orients you. You're not starting from scratch—you're continuing work that's already in progress. Reference prior steps when relevant.

### 1.2 Persistent Agent Memory

If you are a **persistent agent**, you'll receive a memory file with your prior observations and decisions. This is YOUR accumulated knowledge from previous segments.

Look for:

```
## Agent Memory: [your-name]
```

**How to use it:** This is your continuity. You reviewed something yesterday; you remember that review today. Reference your prior decisions. Build on your accumulated understanding. Don't contradict yourself without acknowledging the change.

### 1.3 Task Context

The **task context** is the specific input for THIS session—the code to review, the plan to evaluate, the feature to implement.

Look for:

```
## Task Context
```

or

```
Context provided:
---
[specific content]
---
```

**How to use it:** This is what you're working on RIGHT NOW. Your primary focus. The other context layers inform how you approach this.

### 1.4 Layering Order

When context feels overwhelming, process in this order:

1. **Skim outer state** → Where am I in the bigger picture?
2. **Read your memory** → What do I already know?
3. **Focus on task context** → What am I doing right now?
4. **Synthesize** → How does my prior knowledge inform this task?

### 1.5 Execution Scope (Block Invocations)

If you're running inside a block invocation, you'll receive execution scope information:

```
Execution scope:
  execution_id: 43
  block: process
  depth: 3
  parent_execution_id: 42
```

**What this tells you:**

| Field | Meaning |
|-------|---------|
| `execution_id` | Unique ID for this specific block invocation |
| `block` | Name of the block you're executing within |
| `depth` | How deep in the call stack (1 = first level) |
| `parent_execution_id` | The invoking frame's ID (for scope chain) |

**How to use it:**

1. **Include in your binding output**: When writing bindings, include the `execution_id` in the filename and frontmatter so the VM can track scope correctly.

2. **Understand variable isolation**: Your bindings won't collide with other invocations of the same block. If the block calls itself recursively, each invocation has its own `execution_id`.

3. **Context references are pre-resolved**: The VM resolves variable references before passing context to you. You don't need to walk the scope chain—the VM already did.

**Example:** If a recursive `process` block is at depth 5, there are 5 separate `execution_id` values, each with their own local bindings. Your session only sees the current frame's context.

---

## 2. Working with Persistent State

If you're a persistent agent, you maintain state across sessions via a memory file.

### Two Distinct Outputs

Persistent agents have **two separate outputs** that must not be confused:

| Output | What It Is | Where It Goes | Purpose |
|--------|------------|---------------|---------|
| **Binding** | The result of THIS task | `bindings/{name}.md` or database | Passed to other sessions via `context:` |
| **Memory** | Your accumulated knowledge | `agents/{name}/memory.md` or database | Carried forward to YOUR future invocations |

**The binding is task-specific.** If you're asked to "review the plan," the binding contains your review.

**The memory is agent-specific.** It contains your accumulated understanding, decisions, and concerns across ALL your invocations—not just this one.

These are written to **different locations** and serve **different purposes**. Always write both.

### 2.1 Reading Your Memory

At session start, your memory file is provided. It contains:

- **Current Understanding**: Your overall grasp of the project/task
- **Decisions Made**: What you've decided and why
- **Open Concerns**: Things you're watching for
- **Recent Segments**: What happened in recent sessions

**Read it carefully.** Your memory is your continuity. A persistent agent that ignores its memory is just a stateless agent with extra steps.

### 2.2 Building on Prior Knowledge

When you encounter something related to your memory:

- Reference it explicitly: "In my previous review, I noted X..."
- Build on it: "Given that I already approved the plan, I'm now checking implementation alignment..."
- Update it if wrong: "I previously thought X, but now I see Y..."

### 2.3 Maintaining Consistency

Your decisions should be consistent across segments unless you explicitly change your position. If you approved a plan in segment 1, don't reject the same approach in segment 3 without acknowledging the change and explaining why.

---

## 3. Memory Compaction Guidelines

At the end of your session, you'll be asked to update your memory file. This is **compaction**—preserving what matters for future sessions.

### 3.1 Compaction is NOT Summarization

**Wrong approach:** "I reviewed the code and found some issues."

This loses all useful information. A summary generalizes; compaction preserves specifics.

**Right approach:** "Reviewed auth module (src/auth/login.ts:45-120). Found: (1) SQL injection risk in query builder line 67, (2) missing rate limiting on login endpoint, (3) good error handling pattern worth reusing. Requested fixes for #1 and #2, approved overall structure."

### 3.2 What to Preserve

Preserve **specific details** that future-you will need:

| Preserve                     | Example                                                  |
| ---------------------------- | -------------------------------------------------------- |
| **Specific locations**       | "src/auth/login.ts:67" not "the auth code"               |
| **Exact findings**           | "SQL injection in query builder" not "security issues"   |
| **Decisions with rationale** | "Approved because X" not just "Approved"                 |
| **Numbers and thresholds**   | "Coverage at 73%, target is 80%" not "coverage is low"   |
| **Names and identifiers**    | "User.authenticate() method" not "the login function"    |
| **Open questions**           | "Need to verify: does rate limiter apply to OAuth flow?" |

### 3.3 What to Drop

Drop information that won't help future sessions:

| Drop             | Why                                                                         |
| ---------------- | --------------------------------------------------------------------------- |
| Reasoning chains | The conclusion matters, not how you got there                               |
| False starts     | You considered X but chose Y—just record Y and a brief note about why not X |
| Obvious context  | Don't repeat the task prompt back                                           |
| Verbose quotes   | Reference by location, don't copy large blocks                              |

### 3.4 Compaction Structure

Update your memory file in this structure:

```markdown
## Current Understanding

[What you know about the overall project/task—update, don't replace entirely]

## Decisions Made

[Append new decisions with dates and rationale]

- [date]: [decision] — [why]

## Open Concerns

[Things to watch for in future sessions—add new, remove resolved]

## Segment [N] Summary

[What happened THIS session—specific, not general]

- Reviewed: [what, where]
- Found: [specific findings]
- Decided: [specific decisions]
- Next: [what should happen next]
```

### 3.5 Compaction Examples

**Bad compaction (too general):**

```
## Segment 3 Summary
Reviewed the implementation. Found some issues. Requested changes.
```

**Good compaction (specific and useful):**

```
## Segment 3 Summary
- Reviewed: Step 2 implementation (UserService.ts, AuthController.ts)
- Found:
  - Missing null check in UserService.getById (line 34)
  - AuthController.login not using the approved error format from segment 1
  - Good: Transaction handling follows pattern I recommended
- Decided: Request fixes for null check and error format before proceeding
- Next: Re-review after fixes, then approve for step 3
```

### 3.6 The Specificity Test

Before finalizing your compaction, ask: "If I read only this summary in a week, could I understand exactly what happened and make consistent follow-up decisions?"

If the answer is no, add more specifics.

---

## 4. Context Size Management

### 4.1 When Your Memory Gets Long

Over many segments, your memory file grows. When it becomes unwieldy:

1. **Preserve recent segments in full** (last 2-3)
2. **Compress older segments** into key decisions only
3. **Archive ancient history** as bullet points

```markdown
## Recent Segments (full detail)

[Segments 7-9]

## Earlier Segments (compressed)

- Segment 4-6: Completed initial implementation review, approved with minor fixes
- Segment 1-3: Established review criteria, approved design doc

## Key Historical Decisions

- Chose JWT over session tokens (segment 2)
- Established 80% coverage threshold (segment 1)
```

### 4.2 When Task Context is Large

If you receive very large task context (big code blocks, long documents):

1. **Don't try to hold it all** — reference by location
2. **Note what you examined** — "Reviewed lines 1-200, focused on auth flow"
3. **Record specific locations** — future sessions can re-examine if needed

---

## 5. Signaling to the VM

The OpenProse VM reads your output to determine next steps. Help it by being clear:

### 5.1 Decision Signals

When you make a decision that affects control flow, be explicit:

```
DECISION: Proceed with implementation
RATIONALE: Plan addresses all concerns raised in previous review
```

or

```
DECISION: Request revision
ISSUES:
1. [specific issue]
2. [specific issue]
REQUIRED CHANGES: [what needs to happen]
```

### 5.2 Concern Signals

When you notice something that doesn't block progress but should be tracked:

```
CONCERN: [specific concern]
SEVERITY: [low/medium/high]
TRACKING: [what to watch for]
```

### 5.3 Completion Signals

When your segment is complete:

```
SEGMENT COMPLETE
MEMORY UPDATES:
- [what to add to Current Understanding]
- [decisions to record]
- [concerns to track]
READY FOR: [what should happen next]
```

---

## 6. Writing Output Files

When using file-based state (see `../state/filesystem.md`), the VM tells you where to write your output. You must write your results directly to the filesystem.

### 6.1 Binding Output Files

For regular sessions with output capture (`let x = session "..."`), write to the specified binding path:

**Path format:** `.prose/runs/{run-id}/bindings/{name}.md`

**Path format (inside block invocation):** `.prose/runs/{run-id}/bindings/{name}__{execution_id}.md`

**File format:**

````markdown
# {name}

kind: {let|const|output|input}
execution_id: {id}  # Include if inside a block invocation (omit for root scope)

source:

```prose
{the source code that created this binding}
```
````

---

{Your actual output here}

````

**Example:**

```markdown
# research

kind: let

source:
```prose
let research = session: researcher
  prompt: "Research AI safety"
````

---

AI safety research covers several key areas:

1. **Alignment** - Ensuring AI systems pursue intended goals
2. **Robustness** - Making systems resilient to edge cases
3. **Interpretability** - Understanding how models make decisions

Key papers include Amodei et al. (2016) on concrete problems...

````

### 6.2 Anonymous Session Output

Sessions without explicit capture (`session "..."` without `let x =`) still produce output. These are written with `anon_` prefix:

**Path:** `.prose/runs/{run-id}/bindings/anon_001.md`

The VM assigns sequential numbers. Write the same format but note the binding came from an anonymous session:

```markdown
# anon_003

kind: let

source:
```prose
session "Analyze the codebase for security issues"
````

---

Security analysis found the following issues...

````

### 6.3 Persistent Agent Memory Output

If you are a persistent agent (invoked with `resume:`), you have additional responsibilities:

1. **Read your memory file first**
2. **Process the task using memory + context**
3. **Update your memory file** with compacted state
4. **Write a segment file** recording this session

**Memory file path:** `.prose/runs/{run-id}/agents/{name}/memory.md` (or `.prose/agents/{name}/` for project-scoped, or `~/.prose/agents/{name}/` for user-scoped)

**Segment file path:** `.prose/runs/{run-id}/agents/{name}/{name}-{NNN}.md`

**Memory file format:**

```markdown
# Agent Memory: {name}

## Current Understanding

{Your accumulated knowledge about the project/task}

## Decisions Made

- {date}: {decision} — {rationale}
- {date}: {decision} — {rationale}

## Open Concerns

- {Concern 1}
- {Concern 2}
````

**Segment file format:**

```markdown
# Segment {NNN}

timestamp: {ISO8601}
prompt: "{the prompt for this session}"

## Summary

- Reviewed: {what you examined}
- Found: {specific findings}
- Decided: {specific decisions}
- Next: {what should happen next}
```

### 6.4 Output Writing Checklist

Before completing your session:

- [ ] Write your output to the specified binding path
- [ ] If persistent agent: update memory.md
- [ ] If persistent agent: write segment file
- [ ] Use the exact file format specified
- [ ] Include the source code snippet for traceability

---

## 7. Returning to the VM

When your session completes, you return a **confirmation message** to the VM—not your full output. The VM tracks pointers, not values.

### 7.1 What to Return

Your return message should include:

```
Binding written: {name}
Location: {path or database coordinates}
Summary: {1-2 sentence summary of what's in the binding}
```

**Example (filesystem state, root scope):**
```
Binding written: research
Location: .prose/runs/20260116-143052-a7b3c9/bindings/research.md
Summary: Comprehensive AI safety research covering alignment, robustness, and interpretability with 15 key paper citations.
```

**Example (filesystem state, inside block invocation):**
```
Binding written: result
Location: .prose/runs/20260116-143052-a7b3c9/bindings/result__43.md
Execution ID: 43
Summary: Processed chunk into 3 sub-parts for recursive processing.
```

**Example (PostgreSQL state):**
```
Binding written: research
Location: openprose.bindings WHERE name='research' AND run_id='20260116-143052-a7b3c9'
Summary: Comprehensive AI safety research covering alignment, robustness, and interpretability with 15 key paper citations.
```

**Example (PostgreSQL state, inside block invocation):**
```
Binding written: result
Location: openprose.bindings WHERE name='result' AND run_id='20260116-143052-a7b3c9' AND execution_id=43
Execution ID: 43
Summary: Processed chunk into 3 sub-parts for recursive processing.
```

### 7.2 Why Pointers, Not Values

The VM never holds full binding values in its working memory. This is intentional:

1. **Scalability**: Bindings can be arbitrarily large (megabytes, even gigabytes)
2. **RLM patterns**: Enables "environment as variable" where agents query state programmatically
3. **Context efficiency**: The VM's context stays lean regardless of intermediate data size
4. **Concurrent access**: Multiple agents can read/write different bindings simultaneously

### 7.3 What NOT to Return

Do NOT return your full output in the Task tool response. The VM will ignore it.

**Bad:**
```
Here's my research:

AI safety is a field that studies how to create artificial intelligence systems that are beneficial and avoid harmful outcomes. The field encompasses several key areas...
[5000 more words]
```

**Good:**
```
Binding written: research
Location: .prose/runs/20260116-143052-a7b3c9/bindings/research.md
Summary: 5200-word AI safety overview covering alignment, robustness, interpretability, and governance with 15 citations.
```

### 7.4 For Persistent Agents

If you're a persistent agent (invoked with `resume:`), also confirm your memory update:

```
Binding written: analysis
Location: .prose/runs/20260116-143052-a7b3c9/bindings/analysis.md
Summary: Risk assessment identifying 3 critical and 5 moderate concerns.

Memory updated: captain
Location: .prose/runs/20260116-143052-a7b3c9/agents/captain/memory.md
Segment: captain-003.md
```

---

## Summary

As a subagent in an OpenProse program:

1. **Understand your context layers** — outer state, memory, task context
2. **Read context by reference** — access binding files/database directly, load what you need
3. **Build on your memory** — you have continuity, use it
4. **Compact, don't summarize** — preserve specifics, drop reasoning chains
5. **Signal clearly** — help the VM understand your decisions
6. **Test your compaction** — would future-you understand exactly what happened?
7. **Write outputs directly** — persist to the binding location you're given
8. **Return pointers, not values** — the VM tracks locations, not content

Your memory is what makes you persistent. The VM's efficiency depends on you writing outputs and returning confirmations—not dumping full content back through the substrate.


path: state/filesystem.md
content: ---
role: file-system-state-management
summary: |
  File-system state management for OpenProse programs. This approach persists
  execution state to the `.prose/` directory, enabling inspection, resumption,
  and long-running workflows.
see-also:
  - ../prose.md: VM execution semantics
  - in-context.md: In-context state management (alternative approach)
  - sqlite.md: SQLite state management (experimental)
  - postgres.md: PostgreSQL state management (experimental)
  - ../primitives/session.md: Session context and compaction guidelines
---

# File-System State Management

This document describes how the OpenProse VM tracks execution state using **files in the `.prose/` directory**. This is one of two state management approaches (the other being in-context state in `in-context.md`).

## Overview

File-based state persists all execution artifacts to disk. This enables:

- **Inspection**: See exactly what happened at each step
- **Resumption**: Pick up interrupted programs
- **Long-running workflows**: Handle programs that exceed context limits
- **Debugging**: Trace through execution history

**Key principle:** Files are inspectable artifacts. The directory structure IS the execution state.

---

## Directory Structure

```
# Project-level state (in working directory)
.prose/
├── .env                              # Config (simple key=value format)
├── runs/
│   └── {YYYYMMDD}-{HHMMSS}-{random}/
│       ├── program.prose             # Copy of running program
│       ├── state.md                  # Execution state with code snippets
│       ├── bindings/
│       │   ├── {name}.md             # Root scope bindings
│       │   └── {name}__{execution_id}.md  # Scoped bindings (block invocations)
│       ├── imports/
│       │   └── {handle}--{slug}/     # Nested program executions (same structure recursively)
│       └── agents/
│           └── {name}/
│               ├── memory.md         # Agent's current state
│               ├── {name}-001.md     # Historical segments (flattened)
│               ├── {name}-002.md
│               └── ...
└── agents/                           # Project-scoped agent memory
    └── {name}/
        ├── memory.md
        ├── {name}-001.md
        └── ...

# User-level state (in home directory)
~/.prose/
└── agents/                           # User-scoped agent memory (cross-project)
    └── {name}/
        ├── memory.md
        ├── {name}-001.md
        └── ...
```

### Run ID Format

Format: `{YYYYMMDD}-{HHMMSS}-{random6}`

Example: `20260115-143052-a7b3c9`

No "run-" prefix needed—the directory name makes context obvious.

### Segment Numbering

Segments use 3-digit zero-padded numbers: `captain-001.md`, `captain-002.md`, etc.

If a program exceeds 999 segments, extend to 4 digits: `captain-1000.md`.

---

## File Formats

### `.prose/.env`

Simple key=value configuration file:

```env
OPENPROSE_TELEMETRY=enabled
USER_ID=user-a7b3c9d4e5f6
SESSION_ID=sess-1704326400000-x9y8z7
```

**Why this format:** Self-evident, no JSON parsing needed, familiar to developers.

---

### `state.md`

The execution state file shows the program's current position using **annotated code snippets**. This makes it self-evident where execution is and what has happened.

**Only the VM writes this file.** Subagents never modify `state.md`.

The format shows:
- **Full history** of executed code with inline annotations
- **Current position** clearly marked with status
- **~5-10 lines ahead** of current position (what's coming next)
- **Index** of all bindings and agents with file paths

```markdown
# Execution State

run: 20260115-143052-a7b3c9
program: feature-implementation.prose
started: 2026-01-15T14:30:52Z
updated: 2026-01-15T14:35:22Z

## Execution Trace

```prose
agent researcher:
  model: sonnet
  prompt: "You research topics thoroughly"

agent captain:
  model: opus
  persist: true
  prompt: "You coordinate and review"

let research = session: researcher           # --> bindings/research.md
  prompt: "Research AI safety"

parallel:
  a = session "Analyze risk A"               # --> bindings/a.md (complete)
  b = session "Analyze risk B"               # <-- EXECUTING

loop until **analysis complete** (max: 3):   # [not yet entered]
  session "Synthesize"
    context: { a, b, research }

resume: captain                              # [...next...]
  prompt: "Review the synthesis"
  context: synthesis
```

## Active Constructs

### Parallel (lines 14-16)

- a: complete
- b: executing

### Loop (lines 18-21)

- status: not yet entered
- iteration: 0/3
- condition: **analysis complete**

## Index

### Bindings

| Name | Kind | Path | Execution ID |
|------|------|------|--------------|
| research | let | bindings/research.md | (root) |
| a | let | bindings/a.md | (root) |
| result | let | bindings/result__43.md | 43 |

### Agents

| Name | Scope | Path |
|------|-------|------|
| captain | execution | agents/captain/ |

## Call Stack

| execution_id | block | depth | status |
|--------------|-------|-------|--------|
| 43 | process | 3 | executing |
| 42 | process | 2 | waiting |
| 41 | process | 1 | waiting |
```

**Status annotations:**

| Annotation | Meaning |
|------------|---------|
| `# --> bindings/name.md` | Output written to this file |
| `# <-- EXECUTING` | Currently executing this statement |
| `# (complete)` | Statement finished successfully |
| `# [not yet entered]` | Block not yet reached |
| `# [...next...]` | Coming up next |
| `# <-- RETRYING (attempt 2/3)` | Retry in progress |

---

### `bindings/{name}.md`

All named values (input, output, let, const) are stored as binding files.

```markdown
# research

kind: let

source:
```prose
let research = session: researcher
  prompt: "Research AI safety"
```

---

AI safety research covers several key areas including alignment,
robustness, and interpretability. The field has grown significantly
since 2020 with major contributions from...
```

**Structure:**
- Header with binding name
- `kind:` field indicating type (input, output, let, const)
- `source:` code snippet showing origin
- `---` separator
- Actual value below

**The `kind` field distinguishes:**

| Kind | Meaning |
|------|---------|
| `input` | Value received from caller |
| `output` | Value to return to caller |
| `let` | Mutable variable |
| `const` | Immutable variable |

### Anonymous Session Bindings

Sessions without explicit output capture still produce results:

```prose
session "Analyze the codebase"   # No `let x = ...` capture
```

These get auto-generated names with an `anon_` prefix:

- `bindings/anon_001.md`
- `bindings/anon_002.md`
- etc.

This ensures all session outputs are persisted and inspectable.

---

### Scoped Bindings (Block Invocations)

When a binding is created inside a block invocation, it's scoped to that execution frame to prevent collisions across recursive calls.

**Naming convention:** `{name}__{execution_id}.md`

Examples:
- `bindings/result__43.md` — binding `result` in execution_id 43
- `bindings/parts__44.md` — binding `parts` in execution_id 44

**File format with execution scope:**

```markdown
# result

kind: let
execution_id: 43

source:
```prose
let result = session "Process chunk"
```

---

Processed chunk into 3 sub-parts...
```

**Scope resolution:** The VM resolves variable references by checking:
1. `{name}__{current_execution_id}.md`
2. `{name}__{parent_execution_id}.md`
3. Continue up the call stack
4. `{name}.md` (root scope)

The first match wins.

**Example directory for recursive calls:**

```
bindings/
├── data.md              # Root scope input
├── result__1.md         # First process() invocation
├── parts__1.md          # Parts from first invocation
├── result__2.md         # Recursive call (depth 2)
├── parts__2.md          # Parts from depth 2
├── result__3.md         # Recursive call (depth 3)
└── ...
```

---

### Agent Memory Files

#### `agents/{name}/memory.md`

The agent's current accumulated state:

```markdown
# Agent Memory: captain

## Current Understanding

The project is implementing a REST API for user management.
Architecture uses Express + PostgreSQL. Test coverage target is 80%.

## Decisions Made

- 2026-01-15: Approved JWT over session tokens (simpler stateless auth)
- 2026-01-15: Set 80% coverage threshold (balances quality vs velocity)

## Open Concerns

- Rate limiting not yet implemented on login endpoint
- Need to verify OAuth flow works with new token format
```

#### `agents/{name}/{name}-NNN.md` (Segments)

Historical records of each invocation, flattened in the same directory:

```markdown
# Segment 001

timestamp: 2026-01-15T14:32:15Z
prompt: "Review the research findings"

## Summary

- Reviewed: docs from parallel research session
- Found: good coverage of core concepts, missing edge cases
- Decided: proceed with implementation, note gaps for later
- Next: review implementation against identified gaps
```

---

## Who Writes What

| File | Written By |
|------|------------|
| `state.md` | VM only |
| `bindings/{name}.md` | Subagent |
| `agents/{name}/memory.md` | Persistent agent |
| `agents/{name}/{name}-NNN.md` | Persistent agent |

The VM orchestrates; subagents write their own outputs directly to the filesystem. **The VM never holds full binding values—it tracks file paths.**

---

## Subagent Output Writing

When the VM spawns a session, it tells the subagent where to write output.

### For Regular Sessions

```
When you complete this task, write your output to:
  .prose/runs/20260115-143052-a7b3c9/bindings/research.md

Format:
# research

kind: let

source:
```prose
let research = session: researcher
  prompt: "Research AI safety"
```

---

[Your output here]
```

### For Persistent Agents (resume:)

```
Your memory is at:
  .prose/runs/20260115-143052-a7b3c9/agents/captain/memory.md

Read it first to understand your prior context. When done, update it
with your compacted state following the guidelines in primitives/session.md.

Also write your segment record to:
  .prose/runs/20260115-143052-a7b3c9/agents/captain/captain-003.md
```

### What Subagents Return to the VM

After writing output, the subagent returns a **confirmation message**—not the full content:

**Root scope (outside block invocations):**
```
Binding written: research
Location: .prose/runs/20260115-143052-a7b3c9/bindings/research.md
Summary: AI safety research covering alignment, robustness, and interpretability with 15 citations.
```

**Inside block invocation (include execution_id):**
```
Binding written: result
Location: .prose/runs/20260115-143052-a7b3c9/bindings/result__43.md
Execution ID: 43
Summary: Processed chunk into 3 sub-parts for recursive processing.
```

The VM records the location and continues. It does NOT read the file—it passes the reference to subsequent sessions that need the context.

---

## Imports Recursive Structure

Imported programs use the **same unified structure recursively**:

```
.prose/runs/{id}/imports/{handle}--{slug}/
├── program.prose
├── state.md
├── bindings/
│   └── {name}.md
├── imports/                    # Nested imports go here
│   └── {handle2}--{slug2}/
│       └── ...
└── agents/
    └── {name}/
```

This allows unlimited nesting depth while maintaining consistent structure at every level.

---

## Memory Scoping for Persistent Agents

| Scope | Declaration | Path | Lifetime |
|-------|-------------|------|----------|
| Execution (default) | `persist: true` | `.prose/runs/{id}/agents/{name}/` | Dies with run |
| Project | `persist: project` | `.prose/agents/{name}/` | Survives runs in project |
| User | `persist: user` | `~/.prose/agents/{name}/` | Survives across projects |
| Custom | `persist: "path"` | Specified path | User-controlled |

---

## VM Update Protocol

After each statement completes, the VM:

1. **Confirms** subagent wrote its output file(s)
2. **Updates** `state.md` with new position and annotations
3. **Continues** to next statement

The VM never does compaction—that's the subagent's responsibility.

---

## Resuming Execution

If execution is interrupted, resume by:

1. Reading `.prose/runs/{id}/state.md` to find current position
2. Loading all bindings from `bindings/`
3. Continuing from the marked position

The `state.md` file contains everything needed to understand where execution stopped and what has been accomplished.


path: state/in-context.md
content: ---
role: in-context-state-management
summary: |
  In-context state management using the narration protocol with text markers.
  This approach tracks execution state within the conversation history itself.
  The OpenProse VM "thinks aloud" to persist state—what you say becomes what you remember.
see-also:
  - ../prose.md: VM execution semantics
  - filesystem.md: File-system state management (alternative approach)
  - sqlite.md: SQLite state management (experimental)
  - postgres.md: PostgreSQL state management (experimental)
  - ../primitives/session.md: Session context and compaction guidelines
---

# In-Context State Management

This document describes how the OpenProse VM tracks execution state using **structured narration** in the conversation history. This is one of two state management approaches (the other being file-based state in `filesystem.md`).

## Overview

In-context state uses text-prefixed markers to persist state within the conversation. The VM "thinks aloud" about execution—what you say becomes what you remember.

**Key principle:** Your conversation history IS the VM's working memory.

---

## When to Use In-Context State

In-context state is appropriate for:

| Factor | In-Context | Use File-Based Instead |
|--------|------------|------------------------|
| Statement count | < 30 statements | >= 30 statements |
| Parallel branches | < 5 concurrent | >= 5 concurrent |
| Imported programs | 0-2 imports | >= 3 imports |
| Nested depth | <= 2 levels | > 2 levels |
| Expected duration | < 5 minutes | >= 5 minutes |

Announce your state mode at program start:

```
OpenProse Program Start
   State mode: in-context (program is small, fits in context)
```

---

## The Narration Protocol

Use text-prefixed markers for each state change:

| Marker | Category | Usage |
|--------|----------|-------|
| [Program] | Program | Start, end, definition collection |
| [Position] | Position | Current statement being executed |
| [Binding] | Binding | Variable assignment or update |
| [Input] | Input | Receiving inputs from caller |
| [Output] | Output | Producing outputs for caller |
| [Import] | Import | Fetching and invoking imported programs |
| [Success] | Success | Session or block completion |
| [Warning] | Error | Failures and exceptions |
| [Parallel] | Parallel | Entering, branch status, joining |
| [Loop] | Loop | Iteration, condition evaluation |
| [Pipeline] | Pipeline | Stage progress |
| [Try] | Error handling | Try/catch/finally |
| [Flow] | Flow | Condition evaluation results |
| [Frame+] | Call Stack | Push new frame (block invocation) |
| [Frame-] | Call Stack | Pop frame (block completion) |

---

## Narration Patterns by Construct

### Session Statements

```
[Position] Executing: session "Research the topic"
   [Task tool call]
[Success] Session complete: "Research found that..."
[Binding] let research = <result>
```

### Parallel Blocks

```
[Parallel] Entering parallel block (3 branches, strategy: all)
   - security: pending
   - perf: pending
   - style: pending
   [Multiple Task calls]
[Parallel] Parallel complete:
   - security = "No vulnerabilities found..."
   - perf = "Performance is acceptable..."
   - style = "Code follows conventions..."
[Binding] security, perf, style bound
```

### Loop Blocks

```
[Loop] Starting loop until **task complete** (max: 5)

[Loop] Iteration 1 of max 5
   [Position] session "Work on task"
   [Success] Session complete
   [Loop] Evaluating: **task complete**
   [Flow] Not satisfied, continuing

[Loop] Iteration 2 of max 5
   [Position] session "Work on task"
   [Success] Session complete
   [Loop] Evaluating: **task complete**
   [Flow] Satisfied!

[Loop] Loop exited: condition satisfied at iteration 2
```

### Error Handling

```
[Try] Entering try block
[Position] session "Risky operation"
[Warning] Session failed: connection timeout
[Binding] err = {message: "connection timeout"}
[Try] Executing catch block
[Position] session "Handle error" with context: err
[Success] Recovery complete
[Try] Executing finally block
[Position] session "Cleanup"
[Success] Cleanup complete
```

### Variable Bindings

```
[Binding] let research = "AI safety research covers..." (mutable)
[Binding] const config = {model: "opus"} (immutable)
[Binding] research = "Updated research..." (reassignment, was: "AI safety...")
```

### Input/Output Bindings

```
[Input] Inputs received:
   topic = "quantum computing" (from caller)
   depth = "deep" (from caller)

[Output] output findings = "Research shows..." (will return to caller)
[Output] output sources = ["arxiv:2401.1234", ...] (will return to caller)
```

### Block Invocation and Call Stack

Track block invocations with frame markers:

```
[Position] do process(data, 5)
[Frame+] Entering block: process (execution_id: 1, depth: 1)
   Arguments: chunk=data, depth=5

   [Position] session "Split into parts"
      [Task tool call]
   [Success] Session complete
   [Binding] let parts = <result> (execution_id: 1)

   [Position] do process(parts[0], 4)
   [Frame+] Entering block: process (execution_id: 2, depth: 2)
      Arguments: chunk=parts[0], depth=4
      Parent: execution_id 1

      [Position] session "Split into parts"
         [Task tool call]
      [Success] Session complete
      [Binding] let parts = <result> (execution_id: 2)  # Shadows parent's 'parts'

      ... (continues recursively)

   [Frame-] Exiting block: process (execution_id: 2)

   [Position] session "Combine results"
      [Task tool call]
   [Success] Session complete

[Frame-] Exiting block: process (execution_id: 1)
```

**Key points:**
- Each `[Frame+]` must have a matching `[Frame-]`
- `execution_id` uniquely identifies each invocation
- `depth` shows call stack depth (1 = first level)
- Bindings include `(execution_id: N)` to indicate scope
- Nested frames show `Parent: execution_id N` for the scope chain

### Scoped Binding Narration

When inside a block invocation, always include the execution_id:

```
[Binding] let result = "computed value" (execution_id: 43)
```

For variable resolution across scopes:

```
[Binding] Resolving 'config': found in execution_id 41 (parent scope)
```

### Program Imports

```
[Import] Importing: @alice/research
   Fetching from: https://p.prose.md/@alice/research
   Inputs expected: [topic, depth]
   Outputs provided: [findings, sources]
   Registered as: research

[Import] Invoking: research(topic: "quantum computing")
   [Input] Passing inputs:
      topic = "quantum computing"

   [... imported program execution ...]

   [Output] Received outputs:
      findings = "Quantum computing uses..."
      sources = ["arxiv:2401.1234"]

[Import] Import complete: research
[Binding] result = { findings: "...", sources: [...] }
```

---

## Context Serialization

**In-context state passes values, not references.** This is the key difference from file-based and PostgreSQL state. The VM holds binding values directly in conversation history.

When passing context to sessions, format appropriately:

| Context Size | Strategy |
|--------------|----------|
| < 2000 chars | Pass verbatim |
| 2000-8000 chars | Summarize to key points |
| > 8000 chars | Extract essentials only |

**Format:**
```
Context provided:
---
research: "Key findings about AI safety..."
analysis: "Risk assessment shows..."
---
```

**Limitation:** In-context state cannot support RLM-style "environment as variable" patterns where agents query arbitrarily large bindings. For programs with large intermediate values, use file-based or PostgreSQL state instead.

---

## Complete Execution Trace Example

```prose
agent researcher:
  model: sonnet

let research = session: researcher
  prompt: "Research AI safety"

parallel:
  a = session "Analyze risk A"
  b = session "Analyze risk B"

loop until **analysis complete** (max: 3):
  session "Synthesize"
    context: { a, b, research }
```

**Narration:**
```
[Program] Program Start
   Collecting definitions...
   - Agent: researcher (model: sonnet)

[Position] Statement 1: let research = session: researcher
   Spawning with prompt: "Research AI safety"
   Model: sonnet
   [Task tool call]
[Success] Session complete: "AI safety research covers alignment..."
[Binding] let research = <result>

[Position] Statement 2: parallel block
[Parallel] Entering parallel (2 branches, strategy: all)
   [Task: "Analyze risk A"] [Task: "Analyze risk B"]
[Parallel] Parallel complete:
   - a = "Risk A: potential misalignment..."
   - b = "Risk B: robustness concerns..."
[Binding] a, b bound

[Position] Statement 3: loop until **analysis complete** (max: 3)
[Loop] Starting loop

[Loop] Iteration 1 of max 3
   [Position] session "Synthesize" with context: {a, b, research}
   [Task with serialized context]
   [Success] Result: "Initial synthesis shows..."
   [Loop] Evaluating: **analysis complete**
   [Flow] Not satisfied (synthesis is preliminary)

[Loop] Iteration 2 of max 3
   [Position] session "Synthesize" with context: {a, b, research}
   [Task with serialized context]
   [Success] Result: "Comprehensive analysis complete..."
   [Loop] Evaluating: **analysis complete**
   [Flow] Satisfied!

[Loop] Loop exited: condition satisfied at iteration 2

[Program] Program Complete
```

---

## State Categories

The VM must track these state categories in narration:

| Category | What to Track | Example |
|----------|---------------|---------|
| **Import Registry** | Imported programs and aliases | `research: @alice/research` |
| **Agent Registry** | All agent definitions | `researcher: {model: sonnet, prompt: "..."}` |
| **Block Registry** | All block definitions (hoisted) | `review: {params: [topic], body: [...]}` |
| **Input Bindings** | Inputs received from caller | `topic = "quantum computing"` |
| **Output Bindings** | Outputs to return to caller | `findings = "Research shows..."` |
| **Variable Bindings** | Name -> value mapping (with execution_id) | `result = "..." (execution_id: 3)` |
| **Variable Mutability** | Which are `let` vs `const` vs `output` | `research: let, findings: output` |
| **Execution Position** | Current statement index | Statement 3 of 7 |
| **Loop State** | Counter, max, condition | Iteration 2 of max 5 |
| **Parallel State** | Branches, results, strategy | `{a: complete, b: pending}` |
| **Error State** | Exception, retry count | Retry 2 of 3, error: "timeout" |
| **Call Stack** | Stack of execution frames | See below |

### Call Stack State

For block invocations, track the full call stack:

```
[CallStack] Current stack (depth: 3):
   execution_id: 5 | block: process | depth: 3 | status: executing
   execution_id: 3 | block: process | depth: 2 | status: waiting
   execution_id: 1 | block: process | depth: 1 | status: waiting
```

Each frame tracks:
- `execution_id`: Unique ID for this invocation
- `block`: Name of the block
- `depth`: Position in call stack
- `status`: executing, waiting, or completed

---

## Independence from File-Based State

In-context state and file-based state (`filesystem.md`) are **independent approaches**. You choose one or the other based on program complexity.

- **In-context**: State lives in conversation history
- **File-based**: State lives in `.prose/runs/{id}/`

They are not designed to be complementary—pick the appropriate mode at program start.

---

## Summary

In-context state management:

1. Uses **text-prefixed markers** to track state changes
2. Persists state in **conversation history**
3. Is appropriate for **smaller, simpler programs**
4. Requires **consistent narration** throughout execution
5. Makes state **visible** in the conversation itself

The narration protocol ensures that the VM can recover its execution state by reading its own prior messages. What you say becomes what you remember.


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)