Version: 0.2 (pod-aware)
Last validated against code: 2026-04-11
Source of truth: packages/daemon/src/domain/rigspec-schema.ts, packages/daemon/src/domain/types.ts
This is the canonical reference for the pod-aware RigSpec YAML format. Every field, validation rule, and default documented here was traced from the actual parser and validator code, not from prior documentation.
version: "0.2"
name: my-rig
pods:
- id: dev
label: Development
members:
- id: impl
agent_ref: "local:agents/impl"
profile: default
runtime: claude-code
cwd: "."
edges: []
edges: []version: "0.2"
name: my-product-team
summary: A full product squad with orchestration, development, and review pods.
culture_file: culture/CULTURE.md
docs:
- path: SETUP.md
- path: README.md
startup:
files:
- path: guidance/team-norms.md
delivery_hint: guidance_merge
required: true
actions: []
services:
kind: compose
compose_file: docker-compose.yaml
project_name: my-product
profiles: [core]
down_policy: down
wait_for:
- url: http://127.0.0.1:5432/health
- service: redis
condition: healthy
surfaces:
urls:
- name: App
url: http://127.0.0.1:3000
commands:
- name: psql
command: "psql postgresql://app:dev@127.0.0.1:5432/app"
checkpoints:
- id: postgres
export: "docker compose exec -T postgres pg_dump -U app > {{artifacts_dir}}/postgres.sql"
import: "cat {{artifacts_dir}}/postgres.sql | docker compose exec -T postgres psql -U app"
pods:
- id: orch
label: Orchestration
members:
- id: lead
agent_ref: "local:agents/orchestrator"
profile: default
runtime: claude-code
cwd: "."
- id: peer
agent_ref: "local:agents/orchestrator"
profile: default
runtime: codex
cwd: "."
edges: []
- id: dev
label: Development
summary: Implementation and quality assurance pair.
continuity_policy:
enabled: true
sync_triggers: [pre_compaction, pre_shutdown]
artifacts:
session_log: true
restore_brief: true
restore_protocol:
peer_driven: true
verify_via_quiz: false
startup:
files:
- path: guidance/dev-sop.md
delivery_hint: guidance_merge
required: true
actions: []
members:
- id: impl
agent_ref: "local:agents/impl"
profile: default
runtime: claude-code
cwd: "."
label: "Implementation Lead"
model: claude-opus-4-6
restore_policy: resume_if_possible
startup:
files:
- path: guidance/impl-specific.md
delivery_hint: send_text
required: false
applies_on: [fresh_start]
actions:
- type: send_text
value: "Load the implementation-pair skill and begin."
phase: after_ready
idempotent: true
- id: qa
agent_ref: "local:agents/qa"
profile: default
runtime: codex
cwd: "."
edges:
- kind: delegates_to
from: impl
to: qa
- id: rev
label: Review
members:
- id: r1
agent_ref: "local:agents/reviewer"
profile: default
runtime: claude-code
cwd: "."
- id: r2
agent_ref: "local:agents/reviewer"
profile: default
runtime: codex
cwd: "."
edges: []
edges:
- kind: delegates_to
from: orch.lead
to: dev.impl
- kind: delegates_to
from: orch.peer
to: dev.qa
- kind: can_observe
from: rev.r1
to: dev.impl
- kind: can_observe
from: rev.r2
to: dev.qa| Field | Type | Required | Default | Description |
|---|---|---|---|---|
version |
string | yes | — | Must be "0.2" for pod-aware specs. |
name |
string | yes | — | Rig name. Used in session naming ({pod}-{member}@{name}), snapshot identification, and spec library lookup. |
summary |
string | no | — | Human-readable description. Shown in spec library, review surfaces, and rig specs show. |
culture_file |
string | no | — | Relative path to a rig-wide culture/constitution file. Must be a safe relative path (no .., no absolute). |
permission_policy |
string | no | — | Permission policy attached to the rig. Either a built-in (builtin:locked, builtin:standard, builtin:open, builtin:yolo) or a safe relative path to a custom policy file (resolved from this spec's directory; no .., no absolute). Absent leaves the default floor. A member may set its own permission_policy, which takes precedence over the rig-level one. See "Attaching a permission policy" below. |
managed_blocks |
map | no | CLAUDE.md |
File that receives OpenRig's managed instruction blocks for Claude Code members. Only the claude-code key is accepted, with CLAUDE.md or CLAUDE.local.md. Codex members always use AGENTS.md. See "Choosing the Claude instruction file" below. |
docs |
Doc[] | no | — | Documentation files that should travel with the rig. Included in rig bundles. Each entry has a path field (safe relative path). The engine does not consume these — they are for humans and agents setting up the environment before launch. |
startup |
StartupBlock | no | — | Rig-level startup files and actions. Applied to all members via the startup layering model. |
services |
ServicesBlock | no | — | Optional managed services (Docker Compose). When present, services boot before any agent launches. |
pods |
Pod[] | yes | — | At least one pod required. Each pod is a bounded context containing members and pod-local edges. |
edges |
CrossPodEdge[] | no | [] |
Cross-pod edges connecting members in different pods. Must use fully-qualified pod.member IDs. |
Attach a policy to a rig with permission_policy, either at the rig level or on a member:
# a built-in, by name:
permission_policy: builtin:standard
# or a custom policy file, by relative path (resolved from this spec's directory):
permission_policy: policies/my-cautious-dev.policy.mdBuilt-in policies (locked / standard / open / yolo) are read-only and are
referenced as builtin:<name>. A custom policy lives in your own project and is
referenced by a safe relative path (no .., no absolute). A shipped example of the
custom shape is packages/daemon/policies/examples/my-cautious-dev.policy.md — copy it
into your project and edit it to taste.
This records a selection, not a live permission change. Flag-surface policies
select launch flags; config-surface policies still need native configuration
application and inspection. In particular, builtin:yolo selects Codex's
danger-full-access sandbox and never approval policy, and replaces
any codex_config_profile argument. See practical permission choices.
An explicit rig seat set-permissions choice overrides member/rig policy for
future managed launches of that stable seat; it does not rewrite this spec or
its inherited policy provenance. inherit removes that override. See
per-seat permission mode.
OpenRig writes its instructions for Claude Code members into managed blocks in
the member's working directory. By default the file is CLAUDE.md. If your
repository tracks CLAUDE.md, write the blocks to CLAUDE.local.md instead:
managed_blocks:
claude-code: CLAUDE.local.mdClaude Code loads CLAUDE.local.md from the working directory as well. By
convention the file is kept out of git, for example with a .gitignore entry.
- Accepted values are
CLAUDE.mdandCLAUDE.local.md. Any other value or runtime key is rejected before a member launches. - The setting applies to launch, restore, relaunch, handover, adding members,
and export.
rig downremoves OpenRig's blocks from the selected file only. - OpenRig never edits, moves or deletes blocks in the other file.
A rig that already wrote blocks into CLAUDE.md keeps them there after you
switch. Until you remove them, CLAUDE.md stays modified and Claude Code loads
both copies. Delete each <!-- BEGIN OpenRig MANAGED BLOCK: … --> …
<!-- END OpenRig MANAGED BLOCK: … --> section by hand and keep the rest of the
file. If CLAUDE.md has no other uncommitted edits you need to keep, you can
instead run git restore CLAUDE.md; that command discards every unstaged change
to the file, not only OpenRig's blocks. Running rig down on a rig that still uses
the default is not a substitute: it strips every OpenRig block from that
directory's CLAUDE.md, including blocks written by other rigs.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | yes | — | Pod identifier. Must not contain dots. Must be unique within the rig. Used as the first segment of session names and logical IDs. |
label |
string | yes | — | Human-readable pod name. Shown in UI explorer, graph groupings, and detail surfaces. |
summary |
string | no | — | Pod description. |
continuity_policy |
ContinuityPolicy | no | — | Pod-level continuity/restore policy. Controls compaction recovery, artifact management, and peer-driven restoration. |
startup |
StartupBlock | no | — | Pod-level startup files and actions. Applied to all members in this pod via the startup layering model. |
members |
Member[] | yes | — | At least one member required (enforced by pods needing content). |
edges |
PodLocalEdge[] | no | [] |
Edges between members within this pod. Must use unqualified member IDs (not pod.member). |
- Must not contain dots (
.) - Must be unique across all pods in the rig
- Becomes the first segment of the qualified logical ID:
{podId}.{memberId} - Becomes the first segment of the canonical session name:
{podId}-{memberId}@{rigName}
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | yes | — | Member identifier. Must not contain dots. Must be unique within the pod. |
agent_ref |
string | yes | — | Reference to an AgentSpec. Must start with local: (relative) or path: (absolute). Exception: builtin:terminal for infrastructure nodes. |
profile |
string | yes | — | Profile name from the referenced AgentSpec. Use default for the default profile. Exception: none for terminal nodes. |
codex_config_profile |
string | no | — | Codex-only native profile passed as -p <name>; letters, numbers, _, ., -. Separate from the AgentSpec profile. With the normal launch mode, this replaces OpenRig's explicit workspace-write sandbox flag. A full-bypass policy instead emits danger-full-access and omits this profile argument. |
runtime |
string | yes | — | Agent runtime. Current supported values: claude-code, codex, terminal. |
cwd |
string | yes | — | Working directory for the agent. Resolved relative to the rig root (the directory containing the rig spec). Use "." for the rig root itself. Can be overridden at launch time with rig up --cwd. |
label |
string | no | — | Human-readable member name. Shown in UI when present. |
model |
string | no | — | Model override. Runtime-specific (e.g., claude-opus-4-6 for Claude Code). |
restore_policy |
string | no | resume_if_possible |
Restore behavior. One of: resume_if_possible, relaunch_fresh, checkpoint_only. |
startup |
StartupBlock | no | — | Member-level startup files and actions. Applied only to this member. |
Terminal nodes are infrastructure processes (servers, log tails, build watchers) that are not agent runtimes. They require an exact triple:
runtime: terminal
agent_ref: "builtin:terminal"
profile: noneAll three must be present together. Any partial combination is a validation error.
- Must start with
local:orpath: local:paths are relative to the rig spec file's directory (the rig root)path:paths are absolute filesystem paths- The referenced path must contain an
agent.yamlfile - Exception:
builtin:terminalfor terminal nodes
The canonical session name is derived from the pod ID, member ID, and rig name:
{podId}-{memberId}@{rigName}
Example: pod dev, member impl, rig my-team → session dev-impl@my-team
This is human-authored (you choose the pod/member IDs) and system-validated (the system enforces the format).
| Kind | Meaning | Use When |
|---|---|---|
delegates_to |
Source delegates work to target. Constrains launch order. | Orchestrator → implementer, lead → worker |
spawned_by |
Target was spawned by source. Constrains launch order. | Parent → child in hierarchical topologies |
can_observe |
Source can observe target's output. Does NOT constrain launch order. | Reviewer → implementer, monitor → worker |
collaborates_with |
Peer collaboration relationship. Does NOT constrain launch order. | Co-equal peers working together |
escalates_to |
Source escalates to target for decisions. Does NOT constrain launch order. | Worker → lead for escalation |
Edges within a pod use unqualified member IDs (just the member id, not pod.member):
pods:
- id: dev
members:
- id: impl
# ...
- id: qa
# ...
edges:
- kind: delegates_to
from: impl # NOT dev.impl
to: qa # NOT dev.qaBoth from and to must reference members that exist in the same pod.
Edges between pods use fully-qualified pod.member IDs:
edges:
- kind: delegates_to
from: orch.lead # pod.member format
to: dev.impl # pod.member formatCross-pod edges must reference different pods. An edge where both from and to are in the same pod is a validation error — use pod-local edges instead.
Startup blocks can appear at three levels: rig, pod, and member. They are merged additively via the startup layering model (see docs/reference/startup-layering.md).
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | yes | — | Relative path to the file. Must be a safe relative path. |
delivery_hint |
string | no | auto |
How the file is delivered. One of: auto, guidance_merge, skill_install, send_text. |
required |
boolean | no | true |
Whether startup fails if this file cannot be delivered. |
applies_on |
string[] | no | [fresh_start, restore] |
When this file is delivered. Subset of: fresh_start, restore. |
| Hint | Behavior |
|---|---|
auto |
System chooses based on file type and context. |
guidance_merge |
Merged into the runtime's guidance file (CLAUDE.md or AGENTS.md) as a managed block. Delivered before harness boot. |
skill_install |
Installed as a skill in the runtime's skill directory. Delivered before harness boot. |
send_text |
Sent as text to the agent's terminal after the harness is ready. Requires the agent TUI to be active. |
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type |
string | yes | — | Action type. One of: slash_command, send_text, startup_proof. Note: shell is explicitly NOT supported in v1. |
value |
string | yes | — | Command/text to send, or authenticated / none for startup_proof. |
phase |
string | no | after_files |
When to execute text/commands. One of: after_files (after startup files are delivered), after_ready (after harness readiness check passes). Proof selection is resolved before projection regardless of phase. |
idempotent |
boolean | yes | — | Whether this action is safe to replay on restore. Required field. Non-idempotent actions must NOT include restore in applies_on. |
applies_on |
string[] | no | [fresh_start, restore] |
When this action runs. Subset of: fresh_start, restore. |
Startup adds no orientation exercise by default. To select the authenticated startup challenge, declare an action in an agent, profile, rig, pod, member, or operator startup block:
startup:
actions:
- type: startup_proof
value: authenticated
idempotent: trueUse value: none in a later layer to select lean startup explicitly. The last
applicable declaration wins in agent → profile → rig → pod → member → operator
order. Culture contributes files, not a proof selection. With no applicable
declaration, the result is none; the number of startup files never selects
proof. Invalid values and non-idempotent proof declarations fail validation,
including declarations overridden later. These actions declare policy and are
never typed into a terminal.
An authenticated selection challenges only a fresh or fresh-fallback managed
agent launch. Resumed, forked, rebuilt, and adopted sessions receive no new
challenge; terminal nodes never receive one. applies_on follows the requested
startup context, so a fresh fallback during restore uses restore selections.
Keep the default [fresh_start, restore] to cover both fresh launch paths.
Identity delivery, projection, readiness, and ordinary startup actions still
run. startup_status: ready means startup completed, while oriented: missing
means a selected proof awaits authenticated submission. Omission/none yields
oriented: n-a on a new fresh launch and retires an older challenge without
deleting its audit history. Retirement follows successful harness launch,
before readiness checks, so attention, timeout, or a readiness exception cannot
retain the preceding proof. A replacement that fails to launch does not retire
the current proof; resume/adoption also preserves existing proof history.
The effective selection is recorded on node.startup_pending; actions are
persisted in startup context for restore and fresh relaunch.
The services block is optional. When present, services boot before any agent node launches. If service health checks fail, agent launch is blocked.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
kind |
string | yes | — | Service backend. Only compose is supported in v1. |
compose_file |
string | yes | — | Relative path to the Docker Compose file. Must be a safe relative path. Resolved relative to rig root. |
project_name |
string | no | derived from rig name | Docker Compose project name. Must match [a-z0-9][a-z0-9_-]*. If omitted, derived by sanitizing the rig name. |
profiles |
string[] | no | — | Compose profiles to activate. |
down_policy |
string | no | down |
What happens on rig down. One of: leave_running, down, down_and_volumes. |
wait_for |
WaitTarget[] | no | — | Health targets that must pass before agent launch. |
surfaces |
Surfaces | no | — | Metadata about accessible URLs and commands. Not executed — informational only. |
checkpoints |
CheckpointHook[] | no | — | Shell commands for checkpoint export/import during snapshot/restore. |
Each target must define exactly one of service, url, or tcp:
wait_for:
# HTTP probe — hits the URL, expects 2xx
- url: http://127.0.0.1:8200/v1/sys/health
# TCP probe — connects to host:port
- tcp: "127.0.0.1:5432"
# Compose health check — requires Docker health to report "healthy"
- service: postgres
condition: healthy| Field | Type | Required | Description |
|---|---|---|---|
url |
string | one of three | HTTP URL to probe. |
tcp |
string | one of three | host:port for TCP probe. |
service |
string | one of three | Compose service name. Requires condition: healthy. |
condition |
string | only with service |
Must be healthy. Only valid with service targets. |
surfaces:
urls:
- name: Vault UI
url: http://127.0.0.1:8200/ui
commands:
- name: Vault status
command: "vault status -address=http://127.0.0.1:8200"Surfaces are metadata only. They are displayed in the UI and in rig env status output but are NOT executed by OpenRig.
checkpoints:
- id: postgres
export: "docker compose exec -T postgres pg_dump -U app > {{artifacts_dir}}/postgres.sql"
import: "cat {{artifacts_dir}}/postgres.sql | docker compose exec -T postgres psql -U app"| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Unique identifier for this checkpoint. |
export |
string | yes | Shell command to export state. {{artifacts_dir}} is replaced with a daemon-managed path. |
import |
string | no | Shell command to import state on restore. |
Checkpoint hooks are shell commands run by the daemon. They are best-effort — a failed export does not block snapshot, but continuity is classified as receipt_only instead of checkpointed.
Optional pod-level configuration for compaction recovery behavior.
continuity_policy:
enabled: true
sync_triggers: [pre_compaction, pre_shutdown, manual, milestone]
artifacts:
session_log: true
restore_brief: true
quiz: false
restore_protocol:
peer_driven: true
verify_via_quiz: false| Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled |
boolean | yes | — | Whether continuity is active for this pod. |
sync_triggers |
string[] | no | — | When to sync. Values: pre_compaction, pre_shutdown, manual, milestone. |
artifacts.session_log |
boolean | no | — | Whether to maintain a session log. |
artifacts.restore_brief |
boolean | no | — | Whether to maintain a restore brief. |
artifacts.quiz |
boolean | no | — | Whether to use quiz-based verification. |
restore_protocol.peer_driven |
boolean | no | — | Whether peers drive the restore process. |
restore_protocol.verify_via_quiz |
boolean | no | — | Whether to verify restoration via quiz. |
These rules are enforced by the validator. A spec that violates any of these will be rejected by rig spec validate and rig up.
versionandnameare required non-empty strings.podsmust be a non-empty array.- Pod IDs must not contain dots and must be unique.
- Pod labels are required.
- Member IDs must not contain dots and must be unique within their pod.
agent_ref,profile,runtime, andcwdare required for every member.- Terminal nodes require the exact triple:
runtime: terminal,agent_ref: builtin:terminal,profile: none. agent_refmust start withlocal:(relative) orpath:(absolute), exceptbuiltin:terminal.local:refs must be relative paths.path:refs must be absolute paths.restore_policymust be one of:resume_if_possible,relaunch_fresh,checkpoint_only.- Pod-local edges use unqualified member IDs. Cross-pod edges use
pod.memberformat. - Cross-pod edges must reference different pods.
- Edge kinds must be one of:
delegates_to,spawned_by,can_observe,collaborates_with,escalates_to. - All file paths (
culture_file, startup file paths,compose_file) must be safe relative paths. services.kindmust becompose.services.compose_fileis required when services is present.services.project_namemust match[a-z0-9][a-z0-9_-]*.services.down_policymust be one of:leave_running,down,down_and_volumes.- Each wait target must define exactly one of:
service,url,tcp. conditionis only valid onservicetargets and must behealthy.- Startup file
delivery_hintmust be one of:auto,guidance_merge,skill_install,send_text. - Startup action
typemust be one of:slash_command,send_text,startup_proof. (shellis explicitly rejected.) Proof selection requiresvalue: authenticatedornoneandidempotent: true. - Startup action
phasemust be one of:after_files,after_ready. - Startup action
idempotentis a required boolean. - Non-idempotent actions must not include
restoreinapplies_on. applies_onvalues must be from:fresh_start,restore.
These are the built-in specs shipped with OpenRig. Read them as worked examples.
| Spec | Location | Pods | Members | Services |
|---|---|---|---|---|
product-team |
packages/daemon/specs/rigs/preview/product-team/rig.yaml |
orch1, dev1, rev1 | 7 (lead, peer, impl, qa, design, r1, r2) | no |
implementation-pair |
packages/daemon/specs/rigs/launch/implementation-pair/rig.yaml |
dev | 2 (impl, qa) | no |
adversarial-review |
packages/daemon/specs/rigs/focused/adversarial-review/rig.yaml |
orch, review | 3 (lead, r1, r2) | no |
research-team |
packages/daemon/specs/rigs/focused/research-team/rig.yaml |
orch, research | 3 (lead, analyst, synthesizer) | no |
secrets-manager |
packages/daemon/specs/rigs/launch/secrets-manager/rig.yaml |
vault | 1 (specialist) | yes (Vault) |