Overstory Documentation

repository·main·Indexed 23 days ago

https://github.com/jayminwest/overstory

A multi-agent orchestration framework for AI coding agents (@os-eco/overstory-cli v0.11.0). Overstory enables developers to coordinate swarms of agents working in isolated git worktrees via tmux, using a custom SQLite mail system for communication and tiered conflict resolution for merging. It features pluggable runtime adapters for Claude Code, Pi, and others, and a hierarchical prompt inheritance system called Canopy.

Tokens
50.6K
Snippets
71
Records
275
Agent score
79%

What's inside Overstory

  1. Understand the Canopy Prompt Inheritance Tree

    main

    Overstory uses a hierarchical inheritance model for agent prompts. Prompts are organized into trees where child agents inherit sections from their parents, allowing for specialized behavior while maintaining universal principles.

    Main Agent Tree

    • base-agent: The root containing universal principles.
    • leaf-worker: Single-worker agents (e.g., builder, merger, scout, reviewer).
    • coordinator-base: Leadership and orchestration agents (e.g., lead, orchestrator, coordinator-agent).
    • monitor: Tier 2 fleet patrol.

    Profile / Delivery Prompts

    A separate chain used to define the session style:

    • ov-delivery: Base guidance.
    • Specialized profiles: ov-architecture, ov-co-creation, ov-discovery, ov-research, ov-red-hat (adversarial/risk analysis).

    Standalone Utility Prompts

    Prompts that do not participate in the inheritance chain:

    • prioritize, release, pr-reviews, issue-reviews.
    base-agent                          (root — universal principles)
    │
    ├── leaf-worker                     (single-worker constraints)
    │   ├── builder                     (implementation specialist)
    │   ├── merger                      (branch merge specialist)
    │   └── read-only-worker            (read-only restriction layer)
    │       ├── scout                   (exploration, no writes)
    │       └── reviewer                (validation, no writes)
    │
    ├── coordinator-base                (leadership/orchestration)
    │   ├── lead                        (team lead, spawns sub-workers)
    │   ├── orchestrator                (multi-repo coordinator)
    │   └── coordinator-agent           (top-level coordinator)
    │
    └── monitor                         (Tier 2 fleet patrol)
  2. Understand the difference between TUI and Headless runtimes

    main

    Overstory categorizes agent runtimes into two main types based on how they interact with the orchestrator:

    TUI Runtimes (e.g., Claude Code, Pi, Copilot)

    These runtimes maintain a persistent interactive process inside a tmux pane. The orchestrator manages their lifecycle by:

    • Creating a tmux session.
    • Using detectReady() to poll the pane content (looking for "loading", "dialog", or "ready") to ensure the TUI has rendered.
    • Sending prompts and beacons via tmux send-keys.
    • Verifying beacons to ensure the TUI didn't swallow the input (common in Claude Code/Copilot).
    • Using mail hooks (like ov mail check --inject for Claude Code) for mid-session communication.
    • Persisting across multiple exchanges until killSession() is called.

    Headless Runtimes (e.g., Codex)

    These runtimes spawn a process, execute a single task, and exit. They are non-persistent:

    • detectReady() returns ready immediately.
    • Prompts are passed as execution arguments rather than via tmux keys.
    • No mid-execution mail delivery is possible; the process runs to completion.
    • Events and token usage are captured via NDJSON on stdout (using the --json flag).
  3. Understand the Multi-Swarm and Container Isolation Architecture

    main

    Overstory is transitioning from a single-swarm model to a multi-swarm architecture. This allows an operator to manage multiple concurrent, isolated swarms from a single, always-running UI surface.

    Key Architectural Shifts

    • Run-id as the Primary Primitive: Instead of a single current-run.txt file, the system uses a run-id to namespace all activities. This allows multiple active runs to coexist.
    • Run-Namespaced Storage: To prevent collisions between different swarms, storage is moved from global paths to run-specific directories:
      • Host Mode: .overstory/runs/<run-id>/
      • Container Mode: /workspace/.overstory/ (exposed via bind mount)
    • Namespacing: Worktrees, mail.db, sessions.db, events.db, and logs are all scoped under the specific run-id.

    Operator Workflow

    1. Setup: Run ov setup to start a persistent daemon (ov serve) and a stable local UI URL.
    2. Manage Swarms: Use the UI sidebar (Run picker) to view all past and active runs.
    3. Spawn Swarms: Use the "New run" affordance in the UI to spawn a new coordinator under a unique run-id without using the terminal.
    4. Interact: Click into any running coordinator to engage in a chat session, similar to tmux attach.
  4. How Overstory works: Multi-agent orchestration

    main

    Overstory transforms a single coding session into a multi-agent team. It works by:

    • Spawning workers: Creating individual worker agents in isolated git worktrees.
    • Coordination: Using a custom SQLite mail system to allow agents to communicate.
    • Merging: Bringing work back into the main codebase using tiered conflict resolution.
    • Runtimes: Utilizing a pluggable AgentRuntime interface to support various CLI-based agents like Claude Code, Aider, or Goose.

    Warning: Multi-agent orchestration introduces risks such as compounding error rates, cost amplification, and merge conflicts. Use with caution in production.

  5. Understand the runtime resolution order

    main

    Overstory determines which runtime to use for an agent based on the following priority (from highest to lowest):

    1. CLI Flag: ov sling --runtime <name>
    2. Project Config: config.runtime.default in .overstory/config.yaml
    3. Hardcoded Fallback: Defaults to "claude" if no other configuration is found.
  6. How headless agents handle mail injection

    main

    In headless mode (using --output-format stream-json --input-format stream-json), agents do not use shell hooks to receive updates. Instead, the orchestrator (e.g., ov serve) injects new messages by writing NDJSON lines to the agent's stdin.

    To send a new user message to a running headless agent, write the following format to its stdin:

    {"type":"user","message":{"role":"user","content":[{"type":"text","text":"..."}]}}

    When ov serve is running, it runs a mail injection loop that polls mail.db for unread messages. When new mail is found, it is formatted as a contextual user turn and written to stdin. If multiple messages are pending, they are batched into a single user turn to prevent the agent from being overwhelmed.

  7. How the Agent Runtime Abstraction works

    main

    Overstory uses a runtime abstraction layer to decouple the orchestration engine from specific coding agent runtimes (like Claude Code, Codex, or Pi). This allows a single swarm to contain agents using different runtimes simultaneously.

    The abstraction is implemented via the AgentRuntime interface, which handles four primary surfaces:

    1. Spawn: Managing binary names, CLI flags, and environment variables.
    2. Readiness: Detecting when an agent is ready via TUI detection strings or handling trust dialogs.
    3. Hooks: Managing event names, configuration file paths, and payload schemas.
    4. Overlay + Transcripts: Handling instruction file paths (e.g., .claude/CLAUDE.md) and parsing transcript JSONL formats for metrics.

    Runtimes are primarily config-driven, where most differences are defined by flag names and file paths rather than complex logic.

  8. Understand Guard Rules in Headless Mode

    main

    In Overstory, when running Claude Code in headless mode (using flags like --permission-mode bypassPermissions), security guards behave differently than in TUI mode.

    Key distinction:

    • In TUI mode: Overstory uses .claude/settings.local.json PreToolUse hooks to mechanically intercept and block tool calls that violate path boundaries, capability rules, or bash danger patterns.
    • In Headless mode: While PreToolUse hooks are still deployed and dispatched, they are supplemented by a headless-specific subset. Non-PreToolUse hooks (like SessionStart or UserPromptSubmit) are replaced by the orchestrator's internal stream-json parser and mail injection loop.

    Security Model: Because headless mode often bypasses standard permission prompts, the primary enforcement mechanism is the CLAUDE.md overlay. Agents are instructed via this overlay to operate only within their designated worktree. While the mechanical PreToolUse guards provide defense-in-depth, the system relies on agent alignment with these instructions.

  9. Understand Headless Hook Behavior and Deployment

    main

    When running in headless mode, Overstory modifies how hooks are deployed and executed compared to standard tmux-based agents.

    Key Deployment Rules

    • PreToolUse guards: These are still deployed but use a specific headlessOnly mode (identified by overstory-e24b).
    • PostToolUse (ov log): Skipped; the stream parser handles this instead.
    • PostToolUse (mail check): Subsumed by the server-side injection loop.
    • Stop (ov log session-end): Skipped; handled by the result event from the parser.
    • Stop (ml learn): Omitted; agents are instead instructed via the CLAUDE.md overlay to call ml record before completion.

    Hook Mapping Summary

    Original HookHeadless Equivalent / Treatment
    SessionStartov primeInitial stdin prompt
    SessionStartmail checkInitial stdin prompt
    UserPromptSubmitmail checkServer-side injection loop (ov serve)
    PreToolUse guards (all)Deployed via headlessOnly mode
    PostToolUseov logSkip (handled by stream parser)
    PostToolUsemail checkSubsumed by injection loop
    Stopov log session-endSkip (handled by result event)
    Stopml learnOmit (use ml record via CLAUDE.md)
    PreCompactov primeDeferred (detect compact event, then re-send)
  10. Understand the Canopy Prompt Runtime Flow

    main

    Canopy prompts are assembled through a three-stage resolution process when an agent is spawned (e.g., via ov sling). The final instruction set is written to CLAUDE.md at the agent's {{INSTRUCTION_PATH}}. The resulting prompt combines three distinct layers of guidance:

    1. Base Definition (HOW): Resolved via cn render builder --json. This defines the core agent capabilities (e.g., leaf-worker -> builder).
    2. Profile Guidance (STYLE): Resolved via cn render <profile-name> --json. This applies specific behavioral or architectural profiles (e.g., ov-architecture).
    3. Overlay Specifics (WHAT): Built from templates/overlay.md.tmpl. This contains task-specific context (e.g., TASK_ID, BRANCH_NAME) provided at spawn time.

    The system joins these sections, substitutes variables (like QUALITY_GATE_* and TRACKER_CLI), and delivers a single cohesive instruction set to the agent.

  11. How Runtime Adapters work in Overstory

    main

    Overstory uses an abstraction layer called AgentRuntime to interact with various agent CLIs (like Claude Code, Codex, or Copilot). The orchestration engine never calls a runtime's CLI directly; instead, it interacts exclusively with AgentRuntime methods. This decoupling allows the orchestrator to manage different agent types using a unified interface.

    To use a specific runtime, the orchestrator resolves the appropriate adapter via the getRuntime() method from the runtime registry. The adapter then handles the specific CLI commands, configuration deployment, readiness detection, and transcript parsing for that particular tool.

    Orchestrator / Lead Agent
            |
            | calls AgentRuntime methods only
            v
    +---------------------------+
    |     AgentRuntime          |
    |  (src/runtimes/types.ts)  |
    +---------------------------+
            |
            +--- ClaudeRuntime  (src/runtimes/claude.ts)
            |     claude --model ... --permission-mode ...
            |
            +--- CodexRuntime   (src/runtimes/codex.ts)
            |     codex exec --full-auto --json ...
            |
            +--- PiRuntime      (src/runtimes/pi.ts)
            |     pi --model <provider>/<model> ...
            |
            +--- CopilotRuntime (src/runtimes/copilot.ts)
            |     copilot --model ... --allow-all-tools
            |
            +--- CursorRuntime  (src/runtimes/cursor.ts)
                  agent --model ... --yolo
  12. Understand the Agent Client Protocol (ACP)

    main

    The Agent Client Protocol (ACP) is an emerging standard for controlling coding agents via bidirectional JSON-RPC over stdin/stdout. Overstory can use a generic ACP adapter to support any compliant runtime (like OpenCode or Cline) without needing per-runtime implementations.

    ACP provides:

    • Session lifecycle: start, prompt, abort, and shutdown methods.
    • Event streaming: Notifications for tool_call, file edits, messages, and errors.
    • State queries: Methods to check if the agent is idle or to get its current state.