feat(skills): ship public routing and default projection

This commit is contained in:
v-openrig-build committed 2026-08-02 21:56:53 +00:00
1 parent 25bdf742b0
commit 4c6d88834c
116 files changed
+5161 -5078

No files matched your search

+1 -1
View File
@@ -169,7 +169,7 @@ deprecations, and behavioral changes. Breaking changes are called out explicitly
- **New verbs (capped at exactly three)**: `rig host add` (registry writes validated by the loader's own rules — no more hand-edited YAML for the standard path), `rig host list` (config pointers, never secret values), `rig host doctor <id>` (stepwise distinct errors: transport → remote rig binary → daemon health → identity) with `--posture product-factory-vps` — the ONE built-in security baseline, three-valued per item (UNKNOWN is never pass).
- **Transport posture DECIDED + documented** (no behavior change): ssh carries pane ops (`send`/`capture`), http-bearer carries daemon REST (`up`/`down`/`launch`), `ps`/`whoami` follow the host's declared transport, fan-out is http-only; NO cross-transport fallback; NO http parity for send/capture in 0.4.4. Per-command table in cli-reference §Cross-host execution.
- **Product-factory bootstrap**: `scripts/bootstrap-product-factory-vps.sh` + `docs/reference/product-factory-vps-runbook.md` (fresh Ubuntu VPS → factory-ready; smoke-tested VPS posture as encoded defaults; safe UI tunnel + restricted fail-closed reverse-path recipes).
- **Product-factory bootstrap**: `scripts/bootstrap-product-factory-vps.sh` (fresh Ubuntu VPS → factory-ready; smoke-tested VPS posture as encoded defaults).
### BREAKING: `rig ps` consolidated all-rigs default + explicit disclosure ladder (OPR.0.4.4.21)
+2 -2
View File
@@ -946,8 +946,8 @@ Semantics + safety wall (source: `packages/cli/src/lib/file-transfer.ts`):
Usage: `rig host <add|list|doctor>` — the multi-host registry verbs (OPR.0.4.4.13; capped at
exactly these three — no edit/remove/tunnel/bootstrap verbs; hand-editing `hosts.yaml` remains
the path for exotica, and the factory bootstrap ships as script + runbook at
`docs/reference/product-factory-vps-runbook.md`).
the path for exotica, and the factory bootstrap ships as
`scripts/bootstrap-product-factory-vps.sh`).
- `add --id <id> --transport <ssh|http> [--target <t> --user <u> | --url <u> [--bearer-env <n>|--bearer-file <p>]] [--notes <text>] [--json]` — writes the entry validated by the registry loader's OWN rules (add-time errors are load-time errors, verbatim; duplicate ids refused; the http bearer pointer is optional — omit both for a tokenless daemon, never both). Rewrites `hosts.yaml` canonically (hand-authored comments are not preserved).
- `list [--json]` — id/transport/target plus AUTH as a config POINTER (`env:NAME` / `file:PATH` / `ssh-key`); never a resolved secret value.
@@ -1,132 +0,0 @@
# Product-Factory VPS Runbook (product-factory-vps)
OPR.0.4.4.13 — the productized form of the 2026-06-23 OVH smoke test: a fresh
Ubuntu VPS becomes an OpenRig product factory managed from a home base, with
the proven security posture as the encoded default. The bootstrap is a
SCRIPT + THIS RUNBOOK by design — host verbs are capped at `add`/`list`/
`doctor`, and the acceptance anchor is the observable end state: home-base
`rig host doctor <id>` all green.
## 1. Prerequisites
- A fresh Ubuntu 22.04/24.04 VPS (any provider; the lived reference was OVH).
- A Tailscale tailnet you administer; the home base already on it.
- A home-base SSH keypair for the factory (`ssh-keygen -t ed25519 -f ~/.ssh/openrig-factory`).
- The published OpenRig artifact (`@openrig/cli@<version>`) or the packaged
tarball a release branch builds (`npm pack` output) for pre-release proof.
- Dedicated Claude/Codex accounts for THIS factory. Never copy home-base
credentials (`~/.claude`, `~/.codex`, `~/.openrig`) onto a VPS.
## 2. Tailscale tag + ACL (one-time per tailnet)
In the Tailscale admin console (the UI's words, mapped):
- **tag name**: `openrig-vps` (enter as `tag:openrig-vps` in ACL JSON).
- **tag owner**: your tailnet admin group/user (`"tagOwners": {"tag:openrig-vps": ["autogroup:admin"]}`).
- ACL: home base may reach `tag:openrig-vps` on 22/7433 over the tailnet;
`tag:openrig-vps` gets NO grants toward the home base (the reverse path is
the explicit recipe in §6, never standing policy).
- Auth keys for `tailscale up` must be EPHEMERAL or revoked after use.
## 3. Bootstrap (fresh VPS → factory-ready)
On the VPS, as root:
```bash
curl -fsSLO <your-copy-of>/scripts/bootstrap-product-factory-vps.sh
chmod +x bootstrap-product-factory-vps.sh
./bootstrap-product-factory-vps.sh \
--artifact @openrig/cli@<version> \
--authorized-key "$(cat ~/.ssh/openrig-factory.pub)" \
--ts-authkey tskey-... # ephemeral
```
The script is stepwise and loud: non-root `openrig` user (key-only) → sshd
hardening drop-in (`PermitRootLogin no`, `PasswordAuthentication no`,
`KbdInteractiveAuthentication no`, `X11Forwarding no`) → UFW default-deny +
tailnet ingress (public SSH stays open as a BOOTSTRAP ESCAPE HATCH only) →
Tailscale with `tag:openrig-vps`, no routes/exit-node/Tailscale SSH → Node 22 →
`npm install -g` of the artifact (must succeed with NO manual package
patching) → daemon + kernel.
On the home base:
```bash
rig host add --id ovh-01 --transport ssh --target <tailnet-alias> --user openrig
rig host doctor ovh-01 # expect 4/4 green
rig host doctor ovh-01 --posture product-factory-vps --public-addr <public-ip>
```
Then close the escape hatch on the VPS: `sudo ufw delete allow OpenSSH` and
make sure Tailscale SSH is off: `tailscale set --ssh=false`. Re-run the
posture check. UNKNOWN posture items are NOT passes — each carries the command
that verifies it from the right vantage.
## 4. Transport posture (the decided partition)
See the per-command transport table in `docs/as-built/cli-reference.md`
(§Cross-host execution). The partition IS the intended posture: ssh carries
interactive pane ops (`send`/`capture`); http carries daemon REST ops
(`up`/`down`/`launch`); `ps`/`whoami` follow the host's DECLARED transport;
fan-out (`--all-hosts`) is http-only. There is NO cross-transport fallback and
NO http parity for send/capture in 0.4.4 (parity = new attack surface with no
scope-locked need).
## 5. Safe UI access (recipe, not a verb)
The daemon binds loopback/tailnet — never public. View the factory UI through
a local tunnel (the smoke test's exact form):
```bash
ssh -N -L 127.0.0.1:17433:127.0.0.1:7433 <tailnet-alias>
# then open http://127.0.0.1:17433
```
Tear the tunnel down when done. Do not add public allow rules for :7433.
## 6. Restricted reverse path (supported recipe — NOT always-on)
Boundary first: home-base-initiated ONLY; no broad VPS→home SSH; the tunnel is
torn down after use. The factory cannot freely reach into the home base.
1. On the home base, create a dedicated key the FACTORY will use through the
reverse tunnel, and gate it with a forced command in
`~/.ssh/authorized_keys`:
```text
command="$HOME/.openrig/bin/openrig-reverse-gate",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-ed25519 AAAA...factory-reverse-key
```
2. The gate script (generatable template — allowlists EXACTLY the four verbs
the smoke test proved; everything else is refused, fail-closed):
```bash
#!/usr/bin/env bash
# openrig-reverse-gate — forced-command allowlist for the reverse path.
set -euo pipefail
case "${SSH_ORIGINAL_COMMAND:-}" in
"rig send "*|"rig capture "*|"rig ps"*|"rig whoami"*)
exec $SSH_ORIGINAL_COMMAND ;;
*)
echo "refused: only rig send/capture/ps/whoami are allowed on this key" >&2
exit 77 ;;
esac
```
3. Open the reverse tunnel FROM the home base when you want the channel:
```bash
ssh -N -R 127.0.0.1:2222:127.0.0.1:22 <tailnet-alias> # home-base initiated
```
4. On the factory, agents reach home through it:
`ssh -p 2222 -i <factory-reverse-key> [email protected] rig send <session> "..."`.
5. Kill the tunnel after use. The REFUSAL of any out-of-allowlist verb is the
proof artifact that the gate works — test it on purpose.
## 7. Credential + teardown discipline
- Runtime credentials (Claude/Codex) live ON the VPS, provisioned for it —
never copied from the home host.
- Snapshot/backup expectations and clean teardown follow the provider's
tooling; `rig down --snapshot` before destroying a factory.
- Revoke the Tailscale node + one-time keys when a factory is retired.
+6
View File
@@ -462,6 +462,12 @@ describe("rig scope mission create (HG-14 + HG-15)", () => {
expect(content).toMatch(/## §1\. Top-of-mind context/);
expect(content).toMatch(/## §10\. What NOT to reconstruct/);
expect(content).toMatch(/## §A\. <first-seat>@<rig> notes/);
// Recovery must use durable full-body artifacts first. Compact queue rows
// and transcript output are insufficient evidence after compaction.
expect(content).toContain("rig queue list --mine --full --json");
expect(content).toContain("rig queue show <id> --full --json");
expect(content).toMatch(/little or\s+no output does not prove the session was quiet/);
expect(content).not.toContain("rig queue list --destination <your-session>");
});
it("FR-3: --no-mission-notes opts out — README created, MISSION_NOTES.md is NOT", async () => {
@@ -5,6 +5,11 @@ You are running inside an OpenRig-managed topology.
This file is the thin bootstrap overlay, not the full OpenRig manual.
Use it to recover identity, communicate, and regain context after launch or compaction.
When you are unsure which packaged skill applies, start with the global `openrig-skills` index. It routes to every shipped skill in one hop:
- Claude Code: `~/.claude/skills/openrig-skills/SKILL.md`
- Codex: `~/.agents/skills/openrig-skills/SKILL.md`
For the full OpenRig command surface, load the packaged `openrig-user` skill now.
If your runtime supports skills, use that mechanism.
If it does not auto-load skills reliably, read the packaged copy directly from your current project or workspace:
@@ -4,7 +4,7 @@ Canonical OpenRig skills and hooks for cross-runtime agent topology coordination
## What this plugin ships
**Skills (11):** the canonical OpenRig operating knowledge — how to use the `rig` CLI, how to design rig topologies, how to recover from compaction, how to hand work off durably between agents, and how to maintain seat continuity across handovers and restarts.
**Skills (10):** the canonical OpenRig operating knowledge — how to use the `rig` CLI, how to design rig topologies, how to recover from compaction, how to hand work off durably between agents, and how to maintain seat continuity across handovers and restarts.
**Hooks:** activity-tracking hooks (Claude Code: 4 events; Codex: 3 events) that POST agent state to the OpenRig daemon for real-time UI seat-status updates.
@@ -4,15 +4,17 @@ description: Use when a Claude Code session has just compacted, is about to comp
metadata:
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Load-bearing for any OpenRig seat that may compact. PreCompact hook
is wired into Claude Code's settings (e.g. ~/.claude/settings.json)
so the restore packet is generated automatically before compaction.
sibling_skills:
- mental-model-ha
- scope-recovery
- session-compaction-and-restore
- agent-startup-and-context-ingestion
- agent-starters
- composable-priming-packs
- session-source-fork
- seat-continuity-and-handover
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# Claude Compaction Restore
@@ -105,6 +107,7 @@ After the first restore pass, audit yourself before continuing.
## Guardrails
- Compaction is survival, not housekeeping — never compact to free space, "lean" a seat, or capture/prepare an agent starter (the `rig agent-image` library). It is lossy (a compacted Claude is confident-but-hollow); compact only when a seat is genuinely near its context limit, with a before/after plan. A starter's value is being *functional*, not small — see the `agent-starters` skill.
- Do not silently launch fresh after compaction.
- Do not continue from memory when restore evidence exists.
- Do not defer required restore reading until a later user task. The restore is
@@ -41,10 +41,6 @@ function readInstructionFile(filePath) {
return fs.readFileSync(expanded, "utf8");
}
function sanitizeKey(value) {
return value.replace(/[^a-zA-Z0-9_.@-]/g, "_");
}
function sessionKey(input) {
const raw = [
process.env.OPENRIG_SESSION_NAME,
@@ -55,65 +51,13 @@ function sessionKey(input) {
input.sessionName,
input.transcript_path ? path.basename(input.transcript_path, ".jsonl") : "",
].find((value) => typeof value === "string" && value.trim().length > 0) || "unknown-session";
return sanitizeKey(raw);
}
// OPR.0.4.1.09 (rev1-r2 hook-path leak fix): MUST match claude-compaction-enforcer.ts
// declaredSeatOf EXACTLY — a seat is authoritative ONLY inside a WELL-FORMED leading
// frontmatter fence (opened AND closed `---`); the body is NEVER scanned; malformed/absent
// frontmatter -> null (generic). Duplicated (not imported) because this hook is a standalone
// portable plugin asset that cannot import the compiled daemon TS; semantics are kept
// identical so the enforcer and hook paths refuse wrong-seat extras the same way.
function declaredSeatOf(content) {
const fm = /^\s*---\s*\n([\s\S]*?)\n---/.exec(content);
if (!fm) return null;
const m = /^[ \t]*(?:target[_-]?seat|seat|session(?:[_-]?name)?)[ \t]*:[ \t]*["']?([^"'\n#]+?)["']?[ \t]*$/im.exec(fm[1]);
return m ? m[1].trim() : null;
}
// OPR.0.4.1.09 (rev1-r2): resolve the seat-safe EXTRA-FILE CONTENT for
// postCompactInstruction, mirroring the enforcer resolvePostCompactExtra: (1) prefer the
// PER-SEAT extra post-compact-extra/<seat>.md; (2) else the GLOBAL messageFilePath. In
// EITHER case a file whose WELL-FORMED frontmatter declares a DIFFERENT seat is REFUSED
// (returns "") so a foreign-seat extra never leaks into the marker via the hook path
// (the enforcer path already refused it). Generic/this-seat/malformed -> inject.
function readSeatSafeExtraFile(input, globalFilePath) {
const seatKey = sessionKey(input);
const refusedIfForeign = (content) => {
const declared = declaredSeatOf(content);
return declared && sanitizeKey(declared) !== seatKey ? "" : content;
};
// 1. Per-seat extra preferred (seat-keyed path; still defensively seat-checked to match
// the enforcer, which refuses a per-seat file declaring a different seat).
const perSeatPath = path.join(getOpenRigHome(), "compaction", "post-compact-extra", `${seatKey}.md`);
if (fs.existsSync(perSeatPath)) {
return refusedIfForeign(fs.readFileSync(perSeatPath, "utf8"));
}
// 2. Global messageFilePath fallback, seat-checked.
if (!globalFilePath) return "";
const content = readInstructionFile(globalFilePath);
if (!content) return "";
return refusedIfForeign(content);
return raw.replace(/[^a-zA-Z0-9_.@-]/g, "_");
}
function pendingMarkerPath(input) {
return path.join(getOpenRigHome(), "compaction", "restore-pending", `${sessionKey(input)}.json`);
}
// OPR.0.4.1.09: pointer to this seat's per-seat post-compaction extra
// (compaction/post-compact-extra/<seat>.md), surfaced by the bridge reader.
// Returned ONLY when it EXISTS, so the marker never points at an unresolvable
// restoreMapPath; null otherwise.
function perSeatRestoreMapPath(input) {
const p = path.join(getOpenRigHome(), "compaction", "post-compact-extra", `${sessionKey(input)}.md`);
try {
fs.accessSync(p);
return p;
} catch {
return null;
}
}
function writePendingRestoreMarker(input, parsed, restoreInstruction, customMessage) {
const markerPath = pendingMarkerPath(input);
fs.mkdirSync(path.dirname(markerPath), { recursive: true });
@@ -130,8 +74,6 @@ function writePendingRestoreMarker(input, parsed, restoreInstruction, customMess
expectedAck: "restored from packet at <path>; resumed at step <X>",
deliveredAt: null,
deliveryCount: 0,
// OPR.0.4.1.09: per-seat restore-map pointer (post-compact-extra/<seat>.md) or null.
restoreMapPath: perSeatRestoreMapPath(input),
};
fs.writeFileSync(markerPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
return markerPath;
@@ -144,7 +86,7 @@ function writePendingRestoreMarker(input, parsed, restoreInstruction, customMess
// enabled but restore text has not been written yet, use OpenRig's default
// instruction to load the canonical restore skill. Inline instructions and
// file-path content are both included when both are configured.
function readClaudeCompactionMessage(input) {
function readClaudeCompactionMessage() {
const configPath = path.join(getOpenRigHome(), "config.json");
let inline = "";
let filePath = "";
@@ -173,20 +115,17 @@ function readClaudeCompactionMessage(input) {
const parts = [];
if (inline && inline.length > 0) {
// Inline has no file/seat to declare; keep as-is.
parts.push(`Inline restore instruction:\n${inline}`);
}
// OPR.0.4.1.09 (rev1-r2): the FILE portion is SEAT-SAFE — per-seat extra preferred, a
// foreign-seat global refused (mirrors the enforcer). Checked even when messageFilePath
// is unset, because the per-seat extra is an independent mechanism (the enforcer also
// checks the per-seat path regardless of the global config).
try {
const fileText = readSeatSafeExtraFile(input, filePath);
if (fileText) {
parts.push(`Additional restore instruction file:\n${fileText}`);
if (filePath && filePath.length > 0) {
try {
const fileText = readInstructionFile(filePath);
if (fileText) {
parts.push(`Additional restore instruction file (${filePath}):\n${fileText}`);
}
} catch {
// Keep any inline instruction; unreadable extra files degrade quietly.
}
} catch {
// Keep any inline instruction; unreadable extra files degrade quietly.
}
if (parts.length > 0) return parts.join("\n\n");
if (policyEnabled && !inlineConfigured && !filePathConfigured) {
@@ -208,7 +147,7 @@ try {
args.push(input.transcript_path);
}
const customMessage = readClaudeCompactionMessage(input);
const customMessage = readClaudeCompactionMessage();
const result = spawnSync("node", args, { encoding: "utf8" });
if (result.status !== 0) {
@@ -1,22 +1,27 @@
---
name: forming-an-openrig-mental-model
description: |
Use when an agent is newly oriented to OpenRig and needs to form an accurate mental model of the system fast — what rigs are, how skills load, what the topology shapes mean, what the product loop is. For agents booting into a new seat or returning to OpenRig work after time away. NOT for HA-pair compaction recovery (that's the pair-of-seats coordination pattern; orientation is a solo task) or for specific operational procedures.
Use when an agent is newly oriented to OpenRig and needs to form an accurate mental model of the system fast — what rigs are, how skills load, what the topology shapes mean, what the product loop is. For agents booting into a new seat or returning to OpenRig work after time away. NOT for compaction recovery (use claude-compaction-restore for that) or for specific operational procedures.
metadata:
cli_surfaces_referenced:
- ask
- capture
- down
- ps
- send
- transcript
- up
- whoami
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Authored 2026-05-02 in response to founder-observed pattern: agents
Distinct from HA-pair mental-model preservation (which is a
pair-of-seats coordination pattern). This skill serves the legitimate
need to form an initial mental model of OpenRig as a system.
sibling_skills:
- openrig-user
- openrig-operator
- openrig-builder
- openrig-architect
transfer_test: pending
- openrig-upgrade
- ai-dev-workflows
- software-for-agents
---
# Forming an OpenRig Mental Model
@@ -165,13 +170,14 @@ cost when you reach for one.
| Home | Purpose |
|---|---|
| `<rig-cwd>/.claude/skills/`, `<rig-cwd>/.agents/skills/` | Where the harness actually loads from. Populated by `rig up`. |
| `~/.claude/skills/`, `~/.agents/skills/` | Your personal/global skills + the OpenRig bootstrap set (openrig-user, openrig-operator, openrig-architect, forming-an-openrig-mental-model, plus the rest of the openrig-core plugin skills). |
| openrig-core plugin skills | Product built-in skills that ship with OpenRig (installed via the openrig-core plugin). |
| `~/.openrig/skills/` | Runtime install home for OpenRig-shipped skills. |
| `~/.claude/skills/`, `~/.agents/skills/` | Your personal / user-installed global skills, loaded by the harness itself (independent of OpenRig). NOT where OpenRig's own bootstrap skills live — those ship in the product (below) and project into the cwd `.claude/skills/` at `rig up`. |
| `openrig/packages/daemon/{specs/agents/shared/skills,assets/plugins/*/skills}/` | Product skills that ship with OpenRig — the spec pool + the bundled plugin assets (openrig-user, openrig-operator, openrig-architect, forming-an-openrig-mental-model, queue-handoff, claude-compaction-restore, …). |
| `~/.openrig/skills/` | Future runtime install home for OpenRig-shipped skills. |
| the skills authoring workspace | Skill authoring source (not runtime-loaded). |
The harness only sees the first two. Other locations are shipping and
source-of-truth — they reach the harness via projection or NPM install,
not directly.
The harness only sees the first two. Other locations are authoring,
shipping, and source-of-truth — they reach the harness via projection or
NPM install, not directly.
---
@@ -230,10 +236,8 @@ If you're booting into a new seat in an OpenRig rig:
that tells you when to reach for it.
5. **Check your peers** — `rig capture <peer-session>` to see what they're
doing.
6. **Recover from durable artifacts** if you're returning to an in-flight
workstream: read the restore map, current `MISSION_NOTES.md`, and owned queue
items. Use `rig transcript <session> --tail 100` only as a secondary check;
little or no output does not prove the workstream was quiet.
6. **Check the transcripts** if you're returning to an in-flight workstream
— `rig transcript <session> --tail 100` for recent context.
7. **Ask `rig ask <rig> "<question>"`** if you need cross-cutting evidence
from the rig's transcripts and chat.
@@ -252,19 +256,25 @@ For real depth, these are the load-bearing canonical docs:
| `openrig/docs/reference/rig-spec.md` | The RigSpec YAML format — pods, members, edges, all fields |
| `openrig/docs/reference/agent-spec.md` | The AgentSpec YAML format — resources, profiles, imports |
| `openrig/docs/reference/agent-startup-guide.md` | The 7-layer startup layering model; delivery hints |
| the product taxonomy | Canonical vocabulary (read literally) |
| `substrate/shared-docs/HOST-TOPOLOGY.md` | Host-level doctrine — rig classes, context patterns, lifecycle, authoring SOP |
| `substrate/shared-docs/SUBSTRATE-CONVENTIONS.md` | Filesystem layout doctrine for substrate |
| `https://agentskills.io/specification` | The cross-runtime skill standard |
If your team maintains a host-level topology doc (rig classes, context
patterns, authoring SOPs), read its rig-authoring section before
touching YAML for high-stakes rigs.
If you're going to be authoring rigs, read `HOST-TOPOLOGY.md` §7 (the
authoring SOP) before touching YAML.
If you're going to be doing skill work, read
the factory-design reference and the
`operating-the-skill-library` skill that lives in
`substrate/shared-docs/rigs/skill-library/agents/shared/skills/`.
---
## What this skill is NOT for
- **HA pair compaction recovery.** Forming an initial mental model is a
solo orientation task — different from the pair-of-seats coordination
pattern that preserves a shared mental model across compactions.
- **Compaction recovery.** That's `claude-compaction-restore`. Different
skill, different scenario.
- **Operating a specific rig.** Specific rigs have their own DESIGN.md and
CULTURE.md. Read those.
- **Authoring a new rig.** Use the `openrig-architect` skill for that.
@@ -287,7 +297,7 @@ that fit your actual work.
| "I should manage Codex's compaction the way I manage Claude's" | No. Codex auto-compacts cleanly; Claude doesn't. Different runtimes, different lifecycles. |
| "MEMORY.md auto-loads, so I don't need to read it" | Maybe. Sometimes MEMORY.md auto-loads via system reminders; sometimes not. Don't assume. If your work touches the topics it covers, read it explicitly. |
| "Skills inherit from a parent or compose like classes" | No. Skills are flat artifacts; composition happens via AgentSpec `profile.uses.skills` (structural) or soft cross-references in skill bodies (advisory). Not via OO-style inheritance. |
| "Any folder I keep skill files in is the canonical runtime path" | No. The harness only loads from `<rig-cwd>/.claude/skills/`, `<rig-cwd>/.agents/skills/`, and the runtime-installed plugin skills. Other folders are authoring or source-of-truth. |
| "The substrate `shared-docs/skills/` folder is the canonical runtime path" | No. The harness doesn't read there. It's an authoring workspace. Runtime loads from `.claude/skills/`, `.agents/skills/`, and product built-in. |
---
@@ -0,0 +1,108 @@
---
name: messaging-the-human
description: |
When and who should send a message to the human operator, at
operator-human@your-rig — which routes straight to his Slack. Role-gated:
orchestrators and PMs use discretion to send anything worth his attention
(blockers, ships/completions, changes, good news); every other agent may
message him ONLY for a real blocker he can personally unblock, and routes
everything else through an orchestrator. Use to protect a scarce human's
manage-by-exception attention. NOT for agent-to-agent coordination (send/queue
a peer) or durable agent work-handoffs (use the queue to the owning seat).
metadata:
openrig:
stage: provisional # operator-directed, freshly authored 2026-07-30; hardens as agents use it
audience: ALL agents (universal); orchestrators + PMs are the primary discretionary senders
sibling_skills:
- queue-handoff
- status-not-chat-orchestrator
- human-in-the-loop
- openrig-user
---
# Messaging the Human
## The one-line mechanism
```bash
rig send operator-human@your-rig "your message"
```
That goes straight to the human's Slack. That is the entire *how*. Everything
below is the *when* and the *who* — which is the part that actually matters.
## The mental model: the human is a scarce attention resource managing by exception
There is one human. He is single-threaded across many agents, so his attention
is the bottleneck of the whole system. He operates **by exception**: he wants to
be pulled in when it genuinely matters and left alone when it doesn't. Every
message you send spends a slice of that scarce attention.
So the rule is not "can I reach him" (you can, trivially — one `rig send`). The
rule is **should this reach him, coming from me**. Two things decide that: **who
you are** (your role sets how much of his attention you're trusted to spend) and
**what it is** (does it clear the bar for that role). Get the altitude wrong in
either direction and you fail him: spam his Slack with noise, or sit silently on
something he needed to know or could have unblocked.
## WHO sends WHAT
### If you are an ORCHESTRATOR or a PRODUCT MANAGER — use discretion
You are the primary channel to the human. You may send **more than blockers** —
anything you judge he would want to know:
- something **shipped**, **completed**, or a **milestone** was hit
- something **important happened**, or something **changed**
- **environmental** changes (infra, hosts, tools, external state)
- **good news**
- anything that needs his attention, or is simply **good for him to know**
There is no hard trigger here — it is judgment, and you are trusted with it. The
test is: **"would he want to know this?"** If yes, send it. Lean toward sending
genuine signal and real good news; do not manufacture noise or narrate routine
churn. Discernment is the skill: you are curating his attention, not flooding it.
### If you are ANY OTHER agent — blockers only
You may message the human **only** when you are **blocked** and **he** is the one
who can unblock you. That authority is universal — you do **not** have to be an
orchestrator to raise a real blocker. But a blocker is the **only** thing you may
send him directly.
For anything that is **not** a blocker — an update, an idea, a question, an
interesting finding — do **not** message the human. Send it to your
**orchestrator**, who decides whether it is the human's role to handle or whether
it is handled another way. The orchestrator/PM layer is the filter that protects
the human's attention; routing through it is how the system keeps his queue at
manage-by-exception altitude.
## What counts as a real blocker (for non-orchestrator / non-PM agents)
You are **blocked** AND **only the human** can clear it:
- a **decision** only he can make,
- **access / a credential / an authority** only he holds,
- an **external action** only he can take (something in the real world, an
account or service he owns).
Not a blocker: "I'd like a second opinion," "which approach do you prefer,"
"here's a cool thing I found." Those go to your **orchestrator**. And if an
orchestrator or PM *could* unblock you, route to them first — reserve the human
for what genuinely only he can do.
## How to write it (so it earns the interruption)
- **Lead with the point.** Blocker: what is blocked + exactly what you need from
him. Update: the headline first, detail after.
- **Full absolute paths.** No internal jargon he can't parse. **No backticks** in
`rig send` bodies (they trigger shell substitution).
- `rig send` is an **ephemeral conversation** to his Slack. For a durable *agent*
work-handoff, use the queue to the owning seat — not the human.
## Quick reference
| You are… | You may send the human… |
|---|---|
| Orchestrator / PM | anything worth his attention — blockers, ships, completions, changes, good news (your discretion) |
| Any other agent | a real blocker only he can unblock — **and nothing else** (everything else → your orchestrator) |
@@ -4,17 +4,6 @@ description: "Use when working a mission or slice: the SDLC flow (intent -> mini
metadata:
openrig:
stage: shipped
last_verified: "2026-07-06"
distribution_scope: product-bound
source_evidence: |
The canonical product SDLC skill: it teaches the full SDLC flow the
Living Notes UI projects — the convention sections, the proof-contract
pairing, the two staged-approval locks, C1 proof drops, and the three
role contracts. Conventions SSOT: docs/reference/sdlc-conventions.md
in the repo; on an installed package the daemon materializes the same
document at $OPENRIG_HOME/reference/sdlc-conventions.md (default
~/.openrig/reference/sdlc-conventions.md). The deterministic backstop
is the `rig scope audit` classifier.
sibling_skills:
- queue-handoff
- seat-continuity-and-handover
@@ -23,7 +12,10 @@ metadata:
# Mission/Slice SOP — how you work a mission & slice
Use this skill to actually **do** mission/slice work the way OpenRig expects: author the convention sections, track on the canonical files, prove on them, hand off through them, and survive compaction on them. **Do the work described here; do not merely explain the protocol.** The deterministic backstop is `rig scope audit` — the audit classifier is the source of truth for adherence. The conventions themselves live in ONE document: **`docs/reference/sdlc-conventions.md`** in the repo, materialized by the daemon at **`$OPENRIG_HOME/reference/sdlc-conventions.md`** (default `~/.openrig/reference/sdlc-conventions.md`) on an installed package — this skill teaches the flow; the SSOT defines the formats.
Use this skill to actually **do** mission/slice work the way OpenRig expects: author the convention sections, track on the canonical files, prove on them, hand off through them, and survive compaction on them. **Do the work described here; do not merely explain the protocol.** The deterministic backstop is `rig scope audit` — an **advisory, fail-open** check (it records and advises, never blocks a write; see Proportionality below), not an authority you serve. The conventions themselves live in ONE document: **`docs/reference/sdlc-conventions.md`** in the repo, materialized by the daemon at **`$OPENRIG_HOME/reference/sdlc-conventions.md`** (default `~/.openrig/reference/sdlc-conventions.md`) on an installed package — this skill teaches the flow; the SSOT defines the formats.
## Proportionality — this SOP serves shipping; it is not the work itself
The working product is the deliverable. This bookkeeping exists so the work survives handoff, compaction, and review — nothing more. **Match it to stakes:** OpenRig core = full ceremony; Studio Box / SDK / app slices = pragmatic — the mini-requirements may BE the whole PRD, and a couple of honest, LOOKed proof lines beat an elaborate contract. The `rig scope audit` backstop is **advisory and fail-open** (its own SSOT says so): it never blocks a build and is not a gate you clear before proceeding. If you're spending more time on the convention files or the audit than on the running product, stop and go build. Running the full apparatus on a small change is the letter-worship failure, not diligence.
## The SDLC flow (intent → proof)
@@ -38,7 +30,10 @@ intent → mini-requirements + proof contract → (UI slices: mockups)
1. **Record intent** verbatim in the slice's `## Intent` section (`rig scope slice create` scaffolds it — every template kind).
2. **Author the mini-requirements + proof contract**: `## Mini-requirements` is the concise one-glance tier (approval starts there); `## Proof contract` is a checkbox list of promised deliverables, each written as an observable outcome. UI deliverables name their planned mockup. The IMPLEMENTATION-PRD opens with the mini-requirements; everything between intent and proof is **elastic** — for a small slice the mini-requirements may BE the whole PRD.
- **PARSER CONTRACT (README AND IMPLEMENTATION-PRD, from first draft — a parser contract, not stylistic):** each doc carries a verbatim, **undecorated** `## Mini-requirements` heading with a **numbered list**, and a verbatim, **undecorated** `## Proof contract` heading whose checkbox (`- [ ]`) lines are **character-identical** across the two files. `rig scope audit` parses the PRD's `## Proof contract`; a prose rollup (e.g. `## Required proof …`) or any renamed/decorated heading trips **`proof_contract_missing_or_malformed`** and forces a post-lock format patch. Never rename or decorate these two headings, and keep the PRD's checkbox lines byte-for-byte equal to the README's.
- **REFERENCE-NOT-RESTATE (public / runnable examples — an honesty rail, from first draft):** any example that shows output or a value the referenced file/command **derives** — repo/runtime counts, current-state totals, hashes, timestamps — must **reference the source/derivation, omit the volatile value, or pin an explicitly stable fixture**; never hardcode the live count/state in a public or shipped doc. "Illustrative" derived output is a lie on a timer: `OK registry (2 manifests)` goes false the instant an entry lands. Write the invariant form (`OK registry (<N> manifests)`, N = entries in `registry.json`) or name the fixture instead of the momentary number. Restated derivable state in a public doc is a defect `rig scope audit` will not catch — the author owns it.
3. **Plan-lock**: `rig scope slice approve <slice> --scope spec` — "the PRD matches the intent; THIS artifact set is what gets built." One daemon-side write: frontmatter stamp + append-only audit row.
- **PRE-PLAN-LOCK SELF-CHECK (advisory, not a gate):** before requesting `--scope spec`, it's worth running `rig scope audit --mission <mission> --json` and clearing any real **format** defect (e.g. `proof_contract_missing_or_malformed`) so the parser can read your proof contract — that's a genuine machine-parsing need, cheap to fix. But the audit is fail-open: findings do NOT block the lock or the build, and you do NOT need a zero-findings score to proceed. Fix what's real, skip what isn't, keep moving.
4. **Build the locked set** — look at the mockups, not just the spec text.
5. **QA visual compare**: for each deliverable, load the planned mockup, produce the real artifact in a test/demo environment, visually compare, and record the verdict.
6. **Drop proof**: `rig proof add <slice> --artifact-type qa --verdict PASS --candidate-sha <tip> --money-evidence "…" --evidences "1,3" --media "walk.webm,panel.png" --self-check "…"` — the C1 header's closed sets validate at drop time; `--evidences` joins the drop to its proof-contract items and `--media` names the curated proof/-relative media the drop stands behind (that pairing + media set is what the UI's DELIVERED section renders).
@@ -52,7 +47,7 @@ intent → mini-requirements + proof contract → (UI slices: mockups)
## The canonical files (the operating surface)
> The canonical files below are the **operating surface of the work** — you track on them, prove on them, hand off through them, and survive compaction on them. They are NOT side-artifacts to "maintain"; keeping them current *is* the work.
> The canonical files below are the **operating surface of the work** — you track on them, prove on them, hand off through them, and survive compaction on them. Keep them current because that is what lets the work survive handoff, compaction, and review — but they **serve** the product, they are not the product. If you're polishing these files while the actual thing isn't shipping, you've inverted it: go build, then update them.
- **README.md** (mission + slice) — the overview, OPENING with the convention sections (`## Intent` / `## Mini-requirements` / `## Proof contract`). The **mission README carries this SOP at its bottom.**
- **IMPLEMENTATION-PRD.md** — the full PRD; opens with the mini-requirements; the `## Proof contract` here is what the UI's DELIVERED pairing joins proof against.
@@ -108,7 +103,7 @@ When you `rig capture` a pane, **greyed / ghost autocomplete suggestions are NOT
## Moment-of-truth checklist
- **Starting a slice?** → intent recorded verbatim? mini-requirements + proof contract authored? mockups attached (UI slices)? plan locked (`--scope spec`)?
- **Starting a slice?** → intent recorded verbatim? **PRD carries a verbatim numbered `## Mini-requirements` + a verbatim `## Proof contract` whose `- [ ]` lines are character-identical to the README's** (parser contract)? **no example restates derivable state** — counts/hashes/timestamps referenced, omitted, or pinned to a stable fixture, never hardcoded (reference-not-restate)? mockups attached (UI slices)? ran `rig scope audit` and fixed any real **format** defect so the parser reads the proof contract (advisory — a clean score is NOT required to lock)?
- **Finishing a slice?** → every proof-contract item has curated evidence via `rig proof add … --evidences --media` (C1 drops — never only hand-placed files)? PROGRESS updated? MISSION_NOTES `§1` refreshed? proof locked (`--scope delivery`)? Handed off via queue?
- **Committing?** → PROGRESS updated?
- **Compacting?** → filed your state in MISSION_NOTES?
@@ -1,363 +0,0 @@
---
name: openrig-architect
description: Use when designing multi-agent topologies that run ON OpenRig — authoring RigSpec and AgentSpec files for new rigs, creating agent startup content (guidance / skills / culture), or diagnosing why a launched rig's agents aren't behaving as intended. NOT for changing OpenRig itself (work in the openrig product repo); NOT for ordinary CLI operation of an existing rig (use openrig-user). Covers the full authoring lifecycle from user intent to validated, launchable rig.
metadata:
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Bootstrap skill — NPM install lands this in personal homes (~/.claude/skills/, ~/.agents/skills/) for users authoring their own rigs.
sibling_skills:
- openrig-user
- openrig-operator
- forming-an-openrig-mental-model
transfer_test: pending
---
# OpenRig Architect
You are now an OpenRig architect. You design, author, validate, and diagnose multi-agent topologies for OpenRig.
Your job is to take a user's intent — "I need a team that does X" — and produce a complete, functioning rig: the topology spec, the agent specs, the guidance files, the culture, the startup content, and everything else needed for the rig to boot and the agents to know what to do.
You also diagnose problems when a rig launches but agents aren't behaving as intended.
## Before You Design: Required Reading
Load these before starting any design work. The quality of your output depends on the depth of knowledge you bring.
**Required (read all of these):**
1. **`openrig-user` skill** — full OpenRig CLI surface. You must know the operator primitives. If your runtime supports skills, load it by name. Otherwise, look for it at `~/.openrig/skills/openrig-user/SKILL.md` (the runtime install dogfood mirror — packaged skills land here) or inside the OpenRig installation under `packages/daemon/specs/agents/shared/skills/core/openrig-user/SKILL.md`. The `~/.openrig/reference/` directory holds reference docs (rig-spec.md, agent-spec.md, etc.), NOT skills.
2. **OpenRig reference docs** — these are installed at `~/.openrig/reference/` when the daemon starts. Read all of them:
- `~/.openrig/reference/rig-spec.md` — canonical RigSpec YAML reference. Every field, validation rule, default.
- `~/.openrig/reference/agent-spec.md` — canonical AgentSpec YAML reference. Same depth.
- `~/.openrig/reference/agent-startup-guide.md` — how to think about what goes into agent startup. Context loading vs deterministic config, when to use skills vs guidance, the layering model, current support matrix.
- `~/.openrig/reference/edge-types.md` — what edges do today vs what they're intended to do.
If `~/.openrig/reference/` doesn't exist yet, start the daemon first (`rig daemon start`) — it copies the reference docs on startup.
**Read as worked examples:**
3. **Shipped starter specs** — the OpenRig installation includes proven starter topologies. Find them by running `rig specs ls`. Read the ones that are relevant to your design task, especially:
- `implementation-pair` — the smallest effective development unit (2 agents)
- `secrets-manager` — a managed-app rig with services integration and a specialist agent
**Read if present on this host:**
4. **Host-level doctrine file** (if your team maintains one — e.g., a HOST-TOPOLOGY doc that defines canonical rig classes, context-sharing patterns, and authoring SOPs for high-stakes rigs). If present, it supersedes the baseline process below for complex or high-stakes rigs (≥4 members, HA, managed-app, or shared/copied). Solo operators and small/focused rigs use the baseline below directly.
5. **Agent-facing software design principles** if your rig ships a new CLI, service, or managed app that agents will operate. Treat the operating surface as a context-engineering problem: every error message and help text gives the agent information to act on.
**Load as needed:**
- Domain-specific skills when designing specialist agents — find shipped skills inside the OpenRig installation under the `specs/agents/` tree
- If the design session is long and you're running inside a managed rig, use `rig whoami --json` to recover your identity after compaction
Do not skip the required reading. A rig architect who doesn't know the spec format will produce specs that don't validate. An architect who doesn't know the startup layering model will produce agents that boot without knowing their role. An architect who doesn't check for host-level doctrine will reinvent conventions the host has already established.
## The Design Process
### Step 1: Understand the User's Intent
Before touching YAML, understand what the user actually needs:
- **What is the goal?** Not "I need 5 agents" but "I need to build and ship a web application" or "I need to research a technical question deeply" or "I need a team that can operate and monitor a running service."
- **What are the workflows?** How does work flow from intent to completion? Who does what? Where are the handoffs?
- **What is the project?** What codebase, what tech stack, what domain? This shapes agent specialization and startup content.
- **What runtimes are available?** Does the user have Claude Code? Codex? Both? Runtime availability constrains topology design.
- **How autonomous should it be?** Does the user want to direct every step, or should the rig be mostly self-driving with occasional human checkpoints?
Ask clarifying questions if the intent is ambiguous. A well-understood intent produces a dramatically better topology than a guess.
### Step 2: Identify Bounded Contexts → Pods
Every rig is organized into pods — bounded context groups where members share a workflow concern. The question is: what are the natural groupings?
**Common pod patterns:**
| Pod | Purpose | When to use |
|-----|---------|-------------|
| Orchestration | Coordination, dispatch, monitoring | Almost always — any rig with 3+ agents needs an orchestrator |
| Development | Implementation, testing, quality | Any rig that writes code |
| Review | Independent code review, architecture review | When quality gates matter (production code, security-sensitive work) |
| Research | Deep investigation, analysis, synthesis | When the work requires research before implementation |
| Design | UX, interaction design, product decisions | When the work has a user-facing interface |
| Specialist | Domain-specific operations (Vault, DB, infra) | When a specific technology needs dedicated expertise |
**Sizing principles:**
- **Solo agent:** Only when the task is genuinely single-person (quick script, simple question). No rig needed.
- **Pair (2 agents):** The minimum effective unit for quality work. One does, one verifies. The `implementation-pair` pattern.
- **Small team (3-5 agents):** Orchestrator + one or two working pods. Good starting point for focused projects.
- **Full team (6-10 agents):** Multiple bounded contexts with orchestration, development, review, and potentially research or design.
- **Large team (10-40+ agents):** Complex projects with many concerns. Include pods for development, review, research, documentation, release management, strategy, and any other bounded context the project needs.
**Important:** Agents do NOT all need to be busy at the same time. A rig is a network, not an assembly line. Some pods will be highly active (dev, review) while others are available on-demand (research, documentation, release management). An idle agent has near-zero cost but is immediately available when any other agent in the rig needs it — for quick questions, lookups, delegation, or specialized work. Design for availability, not constant utilization.
**Start small to increase the likelihood of success,** not because large rigs are wasteful. A 3-agent rig that boots and works correctly validates your spec authoring before you scale to 20 agents. Once the core topology works, expand with additional pods as needed.
### Step 3: Design Agent Roles → Members
Each pod member needs a clear role. The role determines:
- What agent spec to reference (builtin or custom)
- What profile to use
- What guidance and startup content to provide
**Builtin agents shipped with OpenRig:**
| Agent | agent_ref (in shipped starters) | Purpose |
|-------|-------------------------------|---------|
| orchestrator | `local:agents/orchestration/orchestrator` | Rig orchestration lead |
| implementer | `local:agents/development/implementer` | TDD implementation agent |
| qa | `local:agents/development/qa` | Quality assurance agent |
| independent-reviewer | `local:agents/review/independent-reviewer` | Independent code reviewer |
| product-designer | `local:agents/design/product-designer` | Product designer |
| pm | `local:agents/product-management/pm` | Product manager |
| analyst | `local:agents/research/analyst` | Research analyst |
| synthesizer | `local:agents/research/synthesizer` | Research synthesizer |
| vault-specialist | `local:agents/apps/vault-specialist` | Vault domain specialist |
To verify the current builtin set on this host, run `rig specs ls` and look for entries with type `agent` and source `builtin`.
**Path resolution:** The `local:` prefix means relative to the rig spec file's directory. In shipped starters, these paths resolve against the builtin specs directory inside the OpenRig installation. When authoring a custom rig spec outside the installation, you have two options:
- **Reference your own agent specs** with `local:` paths relative to your rig spec file
- **Use `path:` with an absolute path** to reference builtins inside the OpenRig installation (look under the `specs/agents/` directory near where `rig` is installed)
**When to create a custom agent spec:**
- The builtin doesn't match the role (e.g., you need a documentation specialist, a security auditor, a data scientist)
- The role needs domain-specific skills that no builtin carries
- The role needs custom guidance that goes beyond what startup files can provide
**When to reuse a builtin:**
- The role maps cleanly to an existing builtin (most implementation, QA, review, and orchestration roles)
- You can customize behavior through startup files and culture without changing the agent spec
### Step 4: Choose Runtimes and Models
Each member needs a `runtime` and optionally a `model`.
**Runtime selection:**
- `claude-code` — Claude Code. Best for: complex reasoning, architecture, code review, orchestration. Supports `/loop` for recurring tasks, rich hooks system, MCP servers.
- `codex` — Codex. Best for: parallel work, implementation, testing. Different approval model. Less reliable for recurring tasks.
- `terminal` — Infrastructure nodes. Servers, log tails, build watchers. Not an agent — a process.
**Runtime diversity is valuable.** Using both Claude Code and Codex in the same rig gives you different reasoning perspectives. The `product-team` starter uses Claude Code for the lead/impl/design/r1 roles and Codex for peer/qa/r2 roles. This is deliberate — model diversity catches different classes of issues.
**Model selection** is optional. The runtime's default model is usually fine. Override only when you have a specific reason (e.g., a complex architecture agent might benefit from a specific model).
### Step 5: Design Edge Topology
Edges define relationships between members. See `~/.openrig/reference/edge-types.md` for the full reference.
**Practical rules:**
- Every working pod should have at least one `delegates_to` edge from the orchestrator
- Review pods should have `can_observe` edges to the pods they review
- Within a pod, the primary workflow direction should be expressed as `delegates_to` (e.g., impl → qa)
- `delegates_to` and `spawned_by` affect launch order. Use them for dependency chains.
- `can_observe`, `collaborates_with`, `escalates_to` are informational — they help agents understand the topology but don't constrain launch.
**Start simple.** You can always add edges later. A rig with only `delegates_to` edges from the orchestrator to working pods is perfectly functional.
### Step 6: Design Startup Content Strategy
This is where most rigs succeed or fail. The topology is mechanical; the startup content is what makes agents actually useful. See `~/.openrig/reference/agent-startup-guide.md` for the full guide.
**Minimum for every rig:**
1. Each agent has a `guidance/role.md` — who they are, what they do
2. The rig has a `CULTURE.md` — how the team works together
3. Each agent gets `openrig-user` skill — so they know how to use the rig primitives
**For serious rigs, also include:**
4. `startup/context.md` per agent — boot-time grounding (project info, environment details)
5. Pod SOP skills — how each pod operates (implementation-pair SOP, review-pair SOP, etc.)
6. Project-specific documentation in rig-level startup files
**The key principle:** An agent that boots without knowing its role, its team's culture, and its project context will produce generic, unhelpful work. The startup content IS the product value. Invest in it.
### Step 7: Services Integration (If Needed)
If the rig needs managed software (databases, API servers, etc.), add a `services` block. See `~/.openrig/reference/rig-spec.md` for the full services reference.
**When to add services:**
- The agents operate ON software (not just write code)
- The project needs a local dev environment (Postgres, Redis, etc.)
- You're building a managed-app rig (software + specialist agent)
**Services boot before agents.** If health checks fail, no agents start. This is the hard gate — the environment must be healthy before agents can work.
## Authoring: The File Creation Workflow
### Directory Layout
```
my-rig/
rig.yaml # The RigSpec — required
culture/
CULTURE.md # Rig-wide culture — strongly recommended
agents/
my-custom-agent/
agent.yaml # AgentSpec — if custom agent needed
guidance/
role.md # Role guidance
startup/
context.md # Boot-time context
skills/
my-skill/
SKILL.md # Custom skill if needed
docker-compose.yaml # Only if services block is used
```
For rigs that reuse builtin agents, the agents directory is often unnecessary — the rig spec references the builtins directly.
### Workflow
1. **Write the rig spec** (`rig.yaml`) — define pods, members, edges, optionally services
2. **Write or reference agent specs** — builtins for standard roles, custom for specialized roles
3. **Write CULTURE.md** — the team operating manual
4. **Write role guidance** for each custom agent — who they are, what they do
5. **Write startup context** for agents that need environment grounding
6. **Validate:** `rig spec validate rig.yaml` and `rig agent validate agents/*/agent.yaml`
7. **Audit authoring completeness:** `rig spec audit rig.yaml` — advisory findings identify missing culture or startup context without blocking launch.
8. **Confirm the runtime cwd** — do not assume agents should work from the directory where the rig spec is stored. The spec root controls file resolution; the runtime cwd controls trust, project guidance, permissions, and repo context.
9. **Launch:** `rig up rig.yaml --cwd /path/to/project`
10. **Verify:** `rig ps --nodes` — all agents ready? Check `rig capture` on each agent.
### Validation Is Non-Negotiable
Always validate before launching:
```bash
rig spec validate rig.yaml
rig spec audit rig.yaml
rig agent validate agents/my-agent/agent.yaml
```
If validation fails, fix the errors. Do not try to launch an invalid spec — it will fail with a less helpful error.
## Diagnosis: When Things Go Wrong
### Agent doesn't know its role
**Symptom:** Agent produces generic output, doesn't follow team conventions.
**Root cause:** Missing or insufficient `guidance/role.md`.
**Fix:** Write a clear role guidance file. Include responsibilities, working rhythm, and principles. Reference it in both `resources.guidance` and `startup.files`.
### Agent can't coordinate with peers
**Symptom:** Agent tries raw tmux commands instead of `rig send`, doesn't know peer session names.
**Root cause:** Agent didn't receive `openrig-user` skill or `openrig-start` overlay.
**Fix:** Ensure the agent's profile `uses.skills` includes `openrig-user`. Verify via `rig ps --nodes` that the agent shows expected startup status; check installed skills via direct startup/capture/transcript evidence or the UI node detail (the `rig ps --nodes` projection does not expose installed-resource counts).
### Agent hits approval prompts on rig commands
**Symptom:** Agent stalls on `rig whoami`, `rig send`, etc.
**Root cause:** Claude Code permissions not configured for rig commands.
**Fix:** Describe the required permissions in startup context. The agent should configure `~/.claude/settings.json` with allowlisted rig commands. See `~/.openrig/reference/agent-startup-guide.md` for the current support matrix.
### Agents idle — topology doesn't engage the team
**Symptom:** Orchestrator works with one or two agents, others sit idle.
**Root cause:** Missing `CULTURE.md` or pod SOP content that describes how the full team coordinates.
**Fix:** Write a culture file that explicitly describes the coordination protocol. Include delegation patterns, review gates, and when each pod should be engaged.
### Services don't boot
**Symptom:** `rig up` fails before agents launch with a service health error.
**Root cause:** Docker Compose issue, health check failure, or port conflict.
**Fix:** Check `docker compose up` manually with the compose file. Verify health check URLs are correct. Check for port conflicts.
### Agent boots from the wrong project context
**Symptom:** Agent misses expected guidance, trust settings, permissions, or repo context even though the spec validates.
**Root cause:** The rig spec directory was treated as the agent's runtime cwd by assumption.
**Fix:** Confirm the intended cwd before launch. The spec can live in a rig/spec shelf while the agent works from the project or hub directory that carries the relevant `AGENTS.md`, `CLAUDE.md`, trust, and permissions. Use member `cwd` or `rig up --cwd` deliberately.
### Startup content not delivered
**Symptom:** Agent is missing expected guidance/skills.
**Root cause:** File paths in the spec don't resolve, or `delivery_hint` is wrong.
**Fix:** Verify file paths resolve relative to their owning artifact — AgentSpec resource paths are relative to the agent spec directory; RigSpec startup, culture, compose, cwd, and `local:` agent-ref paths are relative to the rig root. Check `delivery_hint` — use `guidance_merge` for pre-boot content, `send_text` for post-boot instructions.
### Agent startup delivered but agent doesn't use skills
**Symptom:** Skills are projected but agent doesn't invoke them.
**Root cause:** Agent wasn't told to load them.
**Fix:** In the startup context or role guidance, explicitly tell the agent which skills to load. The belt-and-suspenders pattern: project the skills via the spec AND tell the agent to read them in the guidance.
## Pattern Catalog
### The Implementation Pair
**2 agents, 1 pod.** The smallest effective development unit. One implements (TDD), one does QA. The implementer proposes, QA approves or rejects, then the implementer commits.
```yaml
pods:
- id: dev
label: Development
members:
- id: impl
agent_ref: "local:agents/development/implementer"
runtime: claude-code
profile: default
cwd: "."
- id: qa
agent_ref: "local:agents/development/qa"
runtime: codex
profile: default
cwd: "."
edges:
- kind: delegates_to
from: impl
to: qa
```
**Use when:** Focused feature work, bug fixes, small-to-medium implementation tasks.
### The Orchestrated Team
**5-7 agents, 3 pods.** Orchestration + development + review. The orchestrator dispatches work, the dev pair implements, the review pair validates independently.
**Use when:** Production-quality work that needs coordination and independent review.
### The Research Team
**3 agents, 2 pods.** Orchestrator + research pair (analyst + synthesizer). The analyst investigates deeply, the synthesizer consolidates findings.
**Use when:** Technical research, competitive analysis, architecture exploration.
### The Managed App
**1+ agents, 1 pod, services block.** Software infrastructure (Docker Compose) plus a specialist agent who knows how to operate it.
```yaml
services:
kind: compose
compose_file: docker-compose.yaml
wait_for:
- url: http://127.0.0.1:8200/v1/sys/health
pods:
- id: vault
label: Vault
members:
- id: specialist
agent_ref: "local:agents/apps/vault-specialist"
runtime: claude-code
profile: default
cwd: "."
edges: []
```
**Use when:** The work involves operating software, not just writing code.
### The Full Product Team
**7 agents, 3 pods.** The kitchen-sink topology: orchestration pair, development pod (impl + qa + design), review pair. See the `product-team` starter spec for the complete worked example.
**Use when:** Full product development with design, implementation, QA, and independent review. Requires strong culture and SOP content to keep all agents engaged.
## Final Notes
**Start simple, add complexity when needed.** A working implementation pair is better than a broken full team. Launch with the minimum viable topology, verify it works, then expand.
**Culture is not optional for team rigs.** Any rig with 3+ agents needs a CULTURE.md. Without it, agents will default to generic behavior and the topology will underperform.
**Validate early and often.** Run `rig spec validate` after every change. Run `rig agent validate` after every agent spec edit. Fix errors immediately — don't accumulate them.
**The startup content IS the product.** The YAML topology is scaffolding. What makes a rig actually useful is the guidance, culture, skills, and startup context that agents receive. Invest your authoring time there.
@@ -1,86 +0,0 @@
---
name: openrig-cmux
description: >
Use when opening OpenRig fleet terminals into cmux — turning a rig, pod, mission, slice, or saved
view into live agent tiles via `rig terminal --provider cmux`, or driving cmux on an agent's
request. Same OpenRig view semantics as openrig-herdr (the verbs, honest-partial/degrade, read-only
cross-rig, scroll/copy, same-size-only duplicates); cmux is the **best-effort** provider (herdr is
the default and the proof-gated one). Prefer openrig-herdr unless cmux is specifically wanted.
metadata:
openrig:
stage: candidate
distribution_scope: product-bound
source_evidence: |
cmux is OpenRig's shipped terminal provider generalized onto `rig terminal <provider>` —
best-effort, not proof-gated. Authored clean-room.
transfer_test: pending
sibling_skills:
- openrig-herdr
- openrig-user
---
# openrig-cmux
cmux is a **provider** for OpenRig views — the same `rig terminal` surface as herdr, rendering the
tiles into cmux instead. It is the provider OpenRig already shipped (the existing "Launch in cmux"
affordance generalizes onto `rig terminal <provider>`), kept working. The OpenRig-semantic half is
identical to openrig-herdr: OpenRig decides **which** agents form a view; the provider renders the
pixels. **Read openrig-herdr first for the full model** — this skill only calls out what differs for
cmux.
## Provider status — cmux is best-effort
- **herdr is the default and the proof-gated provider**; **cmux is best-effort** — it ships on the
same `rig terminal <provider>` + web-launcher neighborhood, but a cmux miss is not a slice failure.
Reach for cmux when it is specifically wanted; otherwise default to herdr (`rig terminal open <view>`
with no `--provider`).
- Views are **provider-agnostic**: the same view + the same agents + the same semantics carry across
herdr and cmux. A saved view opens in either.
## The surface (same three verbs, `--provider cmux`)
```bash
rig terminal open <view> --provider cmux [--json] # open a view into cmux (herdr is the no-flag default)
rig terminal views [--json] # the same view library, provider-agnostic
rig terminal status --provider cmux [--json] # cmux liveness / health
```
`<view>` resolves exactly as with herdr: a **rig name** · **`pod:<rig>/<podNamespace>`** ·
**`mission:<id>`** · **`slice:<id>`** (derived live) · a **saved-view name**.
## What carries over unchanged from openrig-herdr
All of these behave identically — see openrig-herdr for the detail:
- **Honest-partial / honest-degrade** — opened / absent / degraded, each named; partial opens exit 0,
zero-pane exits non-zero; an http-registered host's agents degrade with the reason ("host `<id>` is
http-registered; tiles need ssh"), never silently dropped.
- **Read-only policy** — a rig or `pod:` view is interactive; `mission:` / `slice:` views are
read-only by construction; a saved view is per-member (`readOnly`). A read-only pane is
`tmux attach -r` (client `readonly=1`, keystrokes physically cannot reach the agent). See openrig-herdr.
- **Safety rails (the fleet-safety rail)** — a tile is a *view* (nested `tmux attach`) of a
daemon-owned session; never move/join/kill/re-parent a daemon-owned pane; closing a tile detaches
one client and leaves the session untouched; never live-flip tmux options on a running seat in
production (prove it in an isolated environment first).
- **Scroll + copy out of the box** — the daemon's terminal defaults (per-session scroll at launch +
the server's clipboard defaults); running seats pick up wheel-scroll at their next relaunch.
- **Limits** — tile chrome v1 = a plain label; same-size panes for duplicate/multi-view membership
(the different-size resize mismatch is an inherent tmux multi-client limit, documented not fixed).
## cmux-specific notes
- **Open-or-focus per agent** — cmux's shipped integration opens a node or focuses it if already open;
expect focus (not a duplicate) when a seat is already tiled in cmux.
- **The shipped "Launch in cmux" affordance is preserved** (byte-compatible) and generalizes into the
provider + view picker; opening cmux from the web launcher still works.
- **No AGPL arm's-length concern** — unlike herdr, cmux is OpenRig's shipped provider integration; the
clean-room/never-embed rail that applies to herdr is not a cmux constraint. (This skill itself is
still authored clean-room.)
## Saved views — provider-agnostic
Saved views are **hand-authored** in `terminal-views.yaml` (v1 has no save/write verb) and are
**provider-agnostic** — see **openrig-herdr** for the exact schema, the store facts (atomic tmp+rename,
byte-stable, at the OpenRig home root), and the derived-views-never-persisted rule. Reopen any saved
view in cmux with `rig terminal open <id> --provider cmux`. Derived views (a rig, `pod:<rig>/<pod>`,
`mission:<id>`, `slice:<id>`) are computed live and never written to the file.
@@ -1,158 +0,0 @@
---
name: openrig-herdr
description: >
Use when opening OpenRig fleet terminals as a herdr wall — turning a rig, pod, mission, slice, or
saved view into live interactive agent tiles via `rig terminal`, watching another rig read-only,
or driving herdr on an agent's request ("open all my rigs + a mission as views"). Covers the
`rig terminal open|views|status` verbs, the honest-partial/degrade reading of the result, the
read-only-by-construction rail for cross-rig views, scroll/copy out of the box, and the
same-size-only duplicate-pane limit. herdr is the default, proof-gated provider.
metadata:
openrig:
stage: candidate
distribution_scope: product-bound
source_evidence: |
Empirical herdr 0.7.1 hands-on findings + the ratified implementation PRD. Authored
clean-room (patterns only, no herdr source text; AGPL arm's-length).
transfer_test: pending
sibling_skills:
- openrig-cmux
- openrig-user
---
# openrig-herdr
OpenRig decides **which** agents make up a view (a rig, a pod, a mission, a slice, or a saved
group); **herdr** renders the pixels. A view opens as live, interactive terminal tiles — each tile
is a nested `tmux attach` to a daemon-owned agent session, so you get the real session, not a
snapshot. OpenRig owns the semantics; herdr owns the surface. You drive it entirely through the
`rig terminal` CLI, which rides the installed herdr binary at arm's length — never link, embed, or
plugin it.
## The whole surface — three verbs
```bash
rig terminal open <view> [--provider herdr|cmux] [--json] # herdr is the default provider
rig terminal views [--json] # list openable views (saved + derived)
rig terminal status [--provider] [--json] # provider liveness / health
```
`<view>` resolves, in order, to one of:
- a **rig name** — every live agent in that rig, auto-laid-out;
- **`pod:<rig>/<podNamespace>`** — every live agent in one pod of a rig (the rig's inventory filtered by pod);
- **`mission:<id>`** — the agents working that mission (derived live from topology);
- **`slice:<id>`** — the agents working that slice (derived live);
- a **saved-view name** — a user-defined group (see Saved views).
## Compose a view from a sentence
An agent asked "open all my rigs plus a mission as views" runs one `open` per target:
```bash
rig terminal open acme-web # a whole rig, live agents as tiles
rig terminal open mission:site-relaunch # exactly the agents working the mission
rig terminal open slice:02-search-filters # the agents working one slice
```
No hand-listing of seats: the mission/slice membership is derived from live topology at open time.
## Read the result honestly — partial and degrade
The result is a partition — every seat lands in exactly one bucket, each **named**:
- **opened** — the live agents now showing as tiles.
- **absent** — seats in the view that aren't currently live: **named and skipped, never silently
dropped.** A view that opens *some* of its seats is a success (the partial is disclosed) and exits
**0**. Only a view where **no** pane opens exits **non-zero**.
- **degraded** — an agent that structurally cannot tile, named **with the reason**. The v1 case:
an agent on a host registered over HTTP has no ssh path, so its tile can't be composed — it reads
as **"host `<id>` is http-registered; tiles need ssh"** and is skipped, never dropped. (ssh-reachable
hosts tile via an ssh-wrapped attach; full http-host tiling is deferred to the cross-host transport
seam.)
Read `--json` to branch on the partition programmatically; the exit code alone tells you opened-something
(0) vs opened-nothing (non-zero).
## Read-only — who's interactive, who's watch-only
Read-only is composed into the pane at open time — a read-only tile is a `tmux attach -r`, the client
reports `readonly=1`, and it **physically cannot send input**. The current policy, by view kind:
- **A rig view or a `pod:` view is interactive** — you asked for that rig (or pod) directly, so you
can drive its agents.
- **`mission:` and `slice:` views are read-only by construction** — these derived views cut across
rigs; you watch and scroll, you don't keystroke into them.
- **A saved view is per-member** — each member carries its own `readOnly` (omit = interactive;
`true` = `attach -r`).
So you don't have to remember to be careful: the view kind (and, for a saved view, the per-member
flag) sets it at open time.
## Safety rails (hard — the fleet-safety rail)
- A tile is a **view** (a nested `tmux attach`) of a daemon-owned session. **Never** move, join, kill,
or re-parent a daemon-owned pane. Closing a tile detaches one tmux client — the daemon's session is
untouched and its addressing (send/capture/nudge) is unaffected.
- Host-local read-only viewing mutates nothing. Anything that would change a **live** daemon session's
shared state (e.g. flipping a tmux option on a running seat) is a config/design change — prove it in
an isolated environment, never live-flip in production.
## Scroll + copy work out of the box
On a freshly-launched agent tile the mouse wheel scrolls the pane's history and a drag-select copies
to your **system** clipboard — with no tmux commands typed. This rides the daemon's terminal defaults
(a per-session scroll option set at launch, plus the daemon tmux server's clipboard defaults). Honest
timing: agents that were already running before this shipped pick up wheel-scroll at their **next
natural relaunch** (the scroll default is per-session and running seats are never retro-flipped);
system-clipboard copy works immediately (it's server-wide).
## Limits — state them, don't paper over them
- **Tile chrome v1 = a plain label** (agent + slice). Rich per-tile status is roadmap.
- **Duplicate / multi-view membership** (the same agent live in two views at once) works — put the
duplicates in **same-size panes**. Different-sized duplicate panes have an inherent tmux
multi-client resize mismatch (tmux clamps to the smallest client); it is **documented, not fixed** —
don't expect a setting to remove it.
- **Inner tmux status bar** is hidden by default (herdr provides the chrome); one config key
(`terminal.status_bar`) flips it back on for raw-tmux / no-provider surfaces, and the flip applies
to **future launches only**.
## Saved views — the library (`terminal-views.yaml`)
In v1 you **create** a saved view by **hand-authoring** `terminal-views.yaml` — there is no save/write
verb (`open` / `views` / `status` are the whole surface; a `rig terminal save <id>` verb is a named
stretch/follow-up). You **reopen** it like any other view: `rig terminal open <id>`.
The file lives at the OpenRig home root (resolved via `getDefaultOpenRigPath()`), is written
atomically (tmp + rename), and is byte-stable. **Only hand-authored saved views live here — derived
views (a rig, `pod:<rig>/<pod>`, `mission:<id>`, `slice:<id>`) are computed live and never written to
this file.**
Schema — use these field names **exactly**, in this order; **omit** optional fields when absent
(never write `null`):
```yaml
version: 1
views:
- id: my-view-id # required — the id `rig terminal open <id>` takes
name: Human Name # required
members:
- seat: pod-member@rig # required — the canonical session name
label: agent . slice # optional — pane label
host: some-host-id # optional — STRUCTURED host id (NEVER a `member@rig@host` string);
# omit for local. ssh-registered hosts tile;
# http-registered hosts honest-degrade (named + skipped, with reason)
tmuxSession: sessname # optional — defaults to `seat`
readOnly: true # optional — omit = interactive; true = `tmux attach -r`
```
An agent composing a saved view on request **writes this YAML** and then opens the id:
`rig terminal open my-view-id` (add `--provider cmux` for cmux). The library is provider-agnostic —
the same saved view opens in herdr or cmux.
## AGPL / clean-room
Driving herdr through the `rig terminal` CLI (which talks to the installed herdr binary over its
CLI/socket) is arm's-length and fine. Do **not** link herdr's source, embed it in-process, or ship a
herdr plugin — a plugin needs legal review. This skill and its docs are clean-room: patterns only,
never herdr source text.
@@ -1,222 +0,0 @@
---
name: openrig-operator
description: |
Use when debugging host-side OpenRig runtime issues: daemon reachability, Codex permission or writable-root failures, command approval friction, rate limits/account switches, helper cleanup, or topology health confusion. NOT for ordinary CLI operation (use openrig-user) or for changing OpenRig itself (work in the openrig product repo).
metadata:
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Bootstrap skill — NPM install lands this in personal homes (~/.claude/skills/, ~/.agents/skills/).
Companion to openrig-user (daily CLI surface) — this skill is host-side troubleshooting.
transfer_test: pending
sibling_skills:
- openrig-user
- openrig-architect
- forming-an-openrig-mental-model
---
# OpenRig Operator
## Overview
This skill covers host/runtime/operator triage around OpenRig itself.
Use it when the problem may be the daemon, the shell/runtime surface, or stale helper processes rather than the product workflow you are trying to run.
> **CANONICAL SURFACE NOTE (2026-05-11)** — for durable queue routing while doing
> operator triage, use `rig queue` (daemon-backed SQLite). `rigx queue` is
> recovery-only fallback; qitems written there are invisible to daemon-backed
> reads and should not be used for new substantive work.
## When to Use
Use this skill when you see:
- `rig whoami --json` returning partial identity
- `rig ps --nodes --json` failing while some other `rig` commands still work
- `Sent to ...` plus `Verified: no`
- repeated unified-exec-process warnings
- suspicion that stale helper processes are accumulating
- Codex seats hit `Operation not permitted`, command approval friction, or stale writable roots
- Codex seats report usage-limit/rate-limit or need a ChatGPT account switch
Do not use this skill for normal product workflow routing, queue handling, or ordinary peer communication. Use `openrig-user` for that.
Do not use this skill to decide how to change OpenRig behavior. Changes
to the OpenRig product (CLI, daemon, UI, specs) happen in the openrig
product repo — operate that as a normal software project, not via
this troubleshooting skill.
## First Checks
Start with the minimum truthful operator read:
```bash
rig whoami --json
rig daemon status
rig ps --nodes --json
```
Interpret them together, not in isolation:
- partial `whoami` can mean identity is inferable while daemon-backed surfaces are degraded
- `daemon status` tells you whether the host daemon is up, not whether every seat can reach it cleanly
- `ps --nodes --json` is the best machine-readable topology check when it works
## Verification Drift Vs Send Failure
For `rig send`:
- `Sent to ...` + `Verified: yes` = strong positive delivery evidence
- `Sent to ...` + `Verified: no` = ambiguous delivery, not automatic failure
- no `Sent to ...` line or a hard error = send failure
When verification is ambiguous, check:
- direct reply
- `rig capture <session>`
- transcript evidence
- queue/outbox state if the message asked for a durable handoff
Do not blindly retry until you have checked one of those.
## Unified Exec Warning
If you see:
- `Warning: The maximum number of unified exec processes you can keep open is 60 ...`
treat it first as a host/tooling-layer warning, not as automatic proof that the OpenRig topology is unhealthy.
This warning can coexist with a healthy live topology.
## Safe Process Triage
Inspect the process surface first:
```bash
ps -axo pid,ppid,command | rg 'tmux send-keys|rig queue create|tmux attach|codex|claude'
```
Think in layers:
- host/tooling layer: stale one-shot wrappers, session bookkeeping, helper shells
- topology layer: live `tmux attach` seats, live `codex` / `claude` runtimes, daemon health
Do not diagnose topology failure from tooling-layer warnings alone.
## Safe Cleanup Boundary
Usually safe to reap when clearly orphaned / one-shot:
- `tmux send-keys ...`
- short-lived shell wrappers created only to enqueue or send one message
Do not mass-kill:
- `tmux attach ...`
- `codex ...`
- `claude ...`
- other long-lived daemon/runtime processes
The point is to remove garbage, not workers.
## Terminal Node Escalation
Use a terminal node when evidence shows a seat-level sandbox/profile cannot perform required host work, but another approved operator surface can. This is an explicit operator lane, not a silent permission bypass.
Good fits:
- Codex/Claude seat cannot access Tart, SSH, tmux, queue directories, or host files needed for a proof
- a VM/test-proof or current-host-operator task needs real host capability
- another seat or terminal/sysadmin node has approved access and can return command evidence
Do not use this lane to bypass repo safety, dirty-worktree boundaries, review gates, or destructive-action approval. If the command would stop live rigs, delete data, reset git state, or mutate VM state beyond the accepted plan, require explicit authorization and record it.
Protocol:
1. Classify the original failure as seat/profile-specific if possible, not product failure.
2. Write or cite a packet with objective, lane, exact commands, cwd, expected outputs, stop conditions, and artifact path.
3. Route to an existing sysadmin/infrastructure/terminal node when available; otherwise provision a named terminal node through the topology/config layer instead of using a hidden ad hoc shell.
4. Terminal node runs only the packeted commands and returns command log, exit codes, cwd/env notes, and artifacts.
5. Original agent keeps task ownership and proof classification; terminal node supplies host capability.
Field lesson: if tester sees `Operation not permitted` for Tart/SSH while driver or another approved seat can reach the VM, treat it as permission/profile variance and route a terminal-node/operator remediation before changing product code.
## Codex Permission Policy
Use the `security-and-consequence-boundary-policy` skill for the security model.
OpenRig gates consequence boundaries, not ordinary work inside the intended boundary.
Treat Codex permissions as two independent layers:
- command approval rules decide which shell commands can run outside the sandbox
- filesystem writable roots decide which paths a `workspace-write` seat can mutate
Codex `auto_review`, `--full-auto`, and approval-bypass modes are not normal fleet defaults. They
can burn quota catastrophically and do not widen filesystem roots for an already-running seat. Full
access scope with `approvals_reviewer = "user"` is the intended Codex default here.
Claude Code auto permissions are different and are the preferred Claude default on this host when
the consequence-boundary rules still apply.
Current host policy:
- default profile is `fleet`
- `fleet` uses `sandbox_mode = "danger-full-access"`, `approval_policy = "on-request"`, `approvals_reviewer = "user"`
- top-level `[sandbox_workspace_write].writable_roots` intentionally includes `~/code` and tool dotdirs: `.codex`, `.claude`, `.openrig`, `.agents`, `.config`, `.cache`, `.local`, `.docker`, `.npm`, `.nvm`, `.pnpm-store`
- `permissions.fleet.filesystem` mirrors those writes and denies `.ssh`, `.gnupg`, and project env files
- `default.rules` broadly allows `rig` and `rigx`; `rigx` is fully permitted for now because it is the fast-moving config-layer overlay
- `default.rules` still prompts for destructive/publishing surfaces such as `rm`, `mv`, `chmod`, `git push`, PR mutation, `sudo`, process kills, daemon lifecycle, and destructive Docker/Brew/rig commands
## Codex Account / Usage-Limit Refresh
When Codex seats hit usage limits or need a ChatGPT/OpenAI account rotation, use the focused
`codex-seat-auth-refresh` skill instead of improvising.
Key reminder: host auth can switch while already-running Codex TUIs keep the old account. Refresh
only the scoped seats, preserve stable seat names, and record auth-seat registry rows sequentially.
Known failure modes this policy prevents:
- Codex seats assuming a task is impossible when the real issue is stale launch roots
- agents creating workaround slices/features for what is actually a sandbox/config problem
- writing load-bearing canon into `state/`, `/tmp`, or a nearby writable folder because the intended durable path was blocked
- trusting labels like `full access`; verify actual roots and command policy instead
- changing `config.toml` and expecting already-running seats to pick it up without restart
When `Operation not permitted` appears:
1. Identify whether it is command approval, filesystem root, macOS privacy, or stale session.
2. Check effective roots with `codex -p fleet debug prompt-input <probe-name>`.
3. Verify with a tiny direct write probe in an allowed target and a negative probe in a protected target such as `.ssh`.
4. If `config.toml` changed, restart one seat and re-run the probes before fleet rollout.
5. If the target should be durable and is not writable, stop and escalate; do not invent fallback storage.
Field note: as of Codex CLI `0.125.0`, top-level `[sandbox_workspace_write]` was the shape reflected by `debug prompt-input`; profile-scoped writable roots did not show in the effective prompt. Re-test this if Codex changes.
## Durable Write Escalation
If the task requires writing load-bearing knowledge or behavior and the intended target is not writable, stop and escalate. Do not silently write to `state/`, `/tmp`, or a nearby writable folder.
Use the intended durable home for the kind of content:
- `skills/` (e.g. `~/.claude/skills/`, `~/.agents/skills/`, or your team's
shared skill folder) for operating rules and refocus behavior
- Your team's workstream notebook (field notes, lab experiments, mission
packets, etc.) for durable observations and PM canon
- The product repo for shipped OpenRig daemon/CLI/config/spec/test behavior
A runtime mirror under a rig `state/` path may be used only as a temporary live patch, must be labeled as non-canonical, and must have a canonical sync follow-up.
## Common Mistakes
- treating `Verified: no` as if it proves the message did not land
- treating the unified-exec warning as if it proves the rig is overloaded
- killing live seats when only stale helper wrappers needed cleanup
- concluding "daemon down" from one seat's failure without checking host-level daemon status
- assuming Codex config changes apply to already-running seats without a restart/probe
- confusing command approval with filesystem write permission
- calling a VM or product path broken before comparing another approved seat or terminal-node probe
- assuming a label like `full access` proves effective write/network capability; verify command approval and filesystem writable-root coverage separately
## Practical Rule
Clean the smallest safe surface that matches the evidence.
If the warning or failure remains after stale-wrapper cleanup, re-check:
```bash
rig daemon status
rig ps --nodes --json
```
If those remain healthy, the residual issue may still be in the host/tool/session layer rather than in OpenRig topology state.
@@ -0,0 +1,95 @@
---
name: openrig-skills
description: "Use when you're operating OpenRig and don't know which skill or context applies — this is the index of what ships with OpenRig, when to reach for each, and how to load it. Start here from a cold boot when nothing else is projected."
metadata:
openrig:
stage: shipped
---
# OpenRig skills — the index (start here)
You're running inside OpenRig. OpenRig ships a set of **skills** — small documents that tell you *when* to do something and *how*. This file is the map: what ships, when to reach for each, and how to load it. If you don't know which skill applies, or nothing is projected into your context, **start here.**
## How OpenRig context works (30 seconds)
Skills are **progressive disclosure**: a skill's *name + description* sit in your context ambiently (the "hot tier"); its *body* loads only when you open it. So you don't pre-read everything — you pattern-match a skill's "when" to your moment, then open just that one. This file is the index over the whole shipped set. (For the full model of building/operating agent software, open `software-for-agents`.)
Every row below names **how to reach the skill** — already-hot, or an exact load path. No row is a dead end.
For repo-shipped skills, resolve the installed CLI package root once:
```sh
OPENRIG_CLI_ROOT="$(dirname "$(dirname "$(realpath "$(command -v rig)")")")"
```
Paths below use that variable. Tier-A skills live in the daemon-vendored plugin at
`~/.openrig/plugins/openrig-core/skills/`; selected and vendored skills live in the installed CLI package.
## The index
### Always loaded — the universal spine (open its body when its moment hits)
These are auto-delivered to every rig; their name+description are already in your context. Open the body when the "when" matches.
- **forming-an-openrig-mental-model** — first boot, or you're unsure how the pieces fit. The runtime mental model. Load: `~/.openrig/plugins/openrig-core/skills/forming-an-openrig-mental-model/SKILL.md`.
- **openrig-user** — you need a `rig` CLI command (send / queue / ps / whoami / scope / broadcast). The daily CLI surface. Load: `~/.openrig/plugins/openrig-core/skills/openrig-user/SKILL.md`.
- **claude-compaction-restore** — you just compacted (Claude). Restore from durable evidence before resuming real work. Load: `~/.openrig/plugins/openrig-core/skills/claude-compaction-restore/SKILL.md`.
- **session-compaction-and-restore** — preparing for, or recovering from, compaction (any runtime). The write- and read-side protocol. Load: `~/.openrig/plugins/openrig-core/skills/session-compaction-and-restore/SKILL.md`.
- **queue-handoff** — you're passing durable work to another seat or ending your turn. The queue is the work ledger, not chat. Load: `~/.openrig/plugins/openrig-core/skills/queue-handoff/SKILL.md`.
- **seat-continuity-and-handover** — handing your seat's work across a restart or to another owner. Load: `~/.openrig/plugins/openrig-core/skills/seat-continuity-and-handover/SKILL.md`.
- **mission-slice-sop** — you're working a mission/slice (the SDLC: intent → mini-requirements + proof contract → build → QA → proof). The operating manual. Load: `~/.openrig/plugins/openrig-core/skills/mission-slice-sop/SKILL.md`.
- **messaging-the-human** — composing a message to the human operator. Plain language, no insider jargon. Load: `~/.openrig/plugins/openrig-core/skills/messaging-the-human/SKILL.md`.
- **software-for-agents** — you want the full first-load model of how agent software is built and operated here. Load: `~/.openrig/plugins/openrig-core/skills/software-for-agents/SKILL.md`.
- **openrig-skills** — this index (you're reading it). Always loaded; the entry point to everything below. Load: `~/.openrig/plugins/openrig-core/skills/openrig-skills/SKILL.md`.
### Load when your role or task calls for it (repo-shipped, profile-selected)
These ship in the installed OpenRig CLI and reach a seat when its profile selects them. To use one, select it in your profile's `uses.skills`, or open the exact installed path below.
- **openrig-architect** — authoring a rig or topology (NOT for changing OpenRig itself — that's `openrig-builder`). Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/openrig-architect/SKILL.md`.
- **openrig-cmux** — driving the `cmux` terminal provider. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/openrig-cmux/SKILL.md`.
- **openrig-herdr** — opening/managing seat terminals via the default proof-gated provider. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/openrig-herdr/SKILL.md`.
- **agent-startup-and-context-ingestion** — a seat is booting and ingesting its startup context. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/agent-startup-and-context-ingestion/SKILL.md`.
- **topology-mutation-and-seat-management** — adding, removing, renaming seats or otherwise mutating rig topology. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/topology-mutation-and-seat-management/SKILL.md`.
- **rig-lifecycle** — rig up / down / pause / resume lifecycle operations. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/rig-lifecycle/SKILL.md`.
- **rig-bundles-and-shareable-artifacts** — packaging or installing a rig bundle / shareable artifact. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/rig-bundles-and-shareable-artifacts/SKILL.md`.
- **cross-host-rig-commands** — reaching seats or queues on another host (`--host`). Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/cross-host-rig-commands/SKILL.md`.
- **openrig-upgrade** — upgrading OpenRig or the daemon. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/openrig-upgrade/SKILL.md`.
- **agent-starters** — composing an agent's starter context / priming packs. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/agent-starters/SKILL.md`.
- **specification-system** — authoring or reading AgentSpecs and rig specs. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/specification-system/SKILL.md`.
- **attention-queue** — managing the attention / needs-attention surface. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/attention-queue/SKILL.md`.
- **human-in-the-loop** — deciding when to involve the human vs. proceed on your own authority. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/human-in-the-loop/SKILL.md`.
- **watchdog** — monitoring or recovering a seat (health, restore, stuck state). Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/watchdog/SKILL.md`.
- **session-source-fork** — forking a session's source/context. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/core/session-source-fork/SKILL.md`.
Pod handbooks (load when you're in that pod):
- **orchestration-team** — you're orchestrating a rig: dispatching, monitoring, keeping the loop moving. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md`.
- **development-team** — you're on the dev pod: building and shipping product changes. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pods/development-team/SKILL.md`.
- **review-team** — you're reviewing: fresh scrutiny, anti-slop, empirical verification. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pods/review-team/SKILL.md`.
Product-management craft (load when shaping/reviewing work):
- **requirements-writer** — turning intent into clear requirements. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pm/requirements-writer/SKILL.md`.
- **plan-review** — reviewing a plan before it's built. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pm/plan-review/SKILL.md`.
- **exec-summary** — writing a decision-ready summary for a human. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pm/exec-summary/SKILL.md`.
- **office-hours** — running a structured advisory / decision session. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pm/office-hours/SKILL.md`.
- **context-builder** — assembling the context a task or seat needs. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pm/context-builder/SKILL.md`.
- **backlog-capture** — capturing and shaping backlog items. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pm/backlog-capture/SKILL.md`.
- **ui-mockup** — producing a UI mockup for a slice. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/pm/ui-mockup/SKILL.md`.
### Vendored craft — load when you're coding (ships with upstream provenance)
General engineering skills OpenRig ships as vendored copies. Open when the task matches; they carry "modified by OpenRig" provenance.
- **test-driven-development** — implementing a feature or bugfix: write the failing test first. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/test-driven-development/SKILL.md`.
- **verification-before-completion** — about to claim done / passing / fixed: run the check and read the output first. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/verification-before-completion/SKILL.md`.
- **systematic-debugging** — debugging: find the root cause before the fix. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/systematic-debugging/SKILL.md`.
- **writing-plans** — writing an implementation plan. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/writing-plans/SKILL.md`.
- **executing-plans** — working through a written plan. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/executing-plans/SKILL.md`.
- **brainstorming** — divergent ideation before converging. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/brainstorming/SKILL.md`.
- **using-superpowers** — discovering and using the vendored "superpowers" skill set. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/using-superpowers/SKILL.md`.
- **agent-browser** — driving a browser (screenshot / screencast) from an agent. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/agent-browser/SKILL.md`.
- **frontend-design** — designing frontend / UI. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/frontend-design/SKILL.md`.
- **dogfood** — web-QA / dogfooding a shipped UI. Load: `${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/process/dogfood/SKILL.md`.
## Need more than what ships here?
This index covers the **shipped** surface. A dev host carries far more (factory, architecture, PM-craft, studio skills) reached through the host's own routers/codemaps — if you're on a builder host and need something not listed above, that deeper routing is the next hop, not a wall. (Host-scale routing is the subject of the context-routing architecture doc; at product scale, this one file is the whole map.)
> Membership note: this index lists exactly the approved product-public oracle set (45 skills as of 2026-08-02: 10 Tier-A + 25 Tier-B + 10 vendored). Skills graduated but not yet in the oracle (e.g. `culture-drift`, `triple-gate-verification`, `reference-first-verification`) join this index when they land in `conventions/product-public-skills.yaml` — index and shipped set stay one scope.
@@ -8,10 +8,28 @@ description: Use when operating OpenRig with the `rig` CLI and you need the ship
This is an as-built guide to the shipped `rig` CLI.
Use current code and `rig ... --help` as ground truth if anything here ever conflicts with older planning docs.
If you need a different shipped skill, open `openrig-skills` — the global index that routes to every shipped skill in one hop.
This is not the config-layer or builder guide. Use the substrate control-plane guidance for `rigx`
and experimental overlays. Use the OpenRig builder guidance when changing OpenRig behavior,
doctrine, or release posture.
## Coordination trust boundary
Coordinate as openly as the trust boundary you actually control allows. Within a set of machines you
own that already trust each other — they can reach each other's daemon URLs and the daemon itself
requires no authentication — direct `rig send`, `rig capture`, and `rig queue` should just work.
Don't invent bearer placeholders, allowlists, trust handshakes, or guest-reach restrictions the
environment doesn't require.
Do not add or defend a restriction without naming the protected asset, the actual adversary, the
blocked attack path, and the concrete consequence. Missing capability is not protection — repair the
route, registration, runtime posture, or product defect directly. Arbitrary boundaries create
constraint-induced circumvention: under goal pressure, agents build shadow transports, alternate
credentials, and weaker proof instead of the direct authorized path. Keep only explicitly stated
external or irreversible boundaries — public push / PR / publish, and destruction of canonical data.
## Coordination primitives — when to use which
Three coordination surfaces, used together for forward-momentum work. Internalize this
@@ -28,7 +46,7 @@ the receipt and move on.
Example:
```bash
rig send reviewer@acme-web "Heads up — filing the per-commit handoff on the search-filters slice at the current tip." --verify
rig send guard@your-rig "Heads up — filing per-commit handoff on the rig-up paper-cut fix at tip 6b8673b6." --verify
```
### `rig queue create --source <X> --destination <Y> --tags <...> --body "<...>"` — durable work item
@@ -39,18 +57,19 @@ restarts. Tracked in the daemon SQLite schema. Surfaces in Project / queue views
+ in the destination seat's inbox. Tag with mission / slice / gate / checkpoint
so future-you (and any peer) can find it.
Body discipline: substantive bodies go through a temp-file pattern, not inline
`--body` with raw backticks — `rig queue create` body parsing breaks on
unescaped backticks and rejects flag-like tokens.
Body discipline: substantive bodies go through **`--body-file <path>`** (or `-` for stdin) — the
purpose-built, corruption-safe surface (it kills the backtick-shell-corruption class for multi-line
bodies). Do NOT inline a backtick-heavy or multi-line body via `--body`: `rig queue create` body
parsing breaks on unescaped backticks and rejects flag-like tokens.
Example:
```bash
rig queue create \
--source builder@acme-web \
--destination reviewer@acme-web \
--tags "mission:site-relaunch,slice:02-search-filters,gate:guard,handoff:per-commit,checkpoint:bug-1" \
--body "$(cat /tmp/per-commit-body.txt)"
--source driver-2@your-rig \
--destination redo-guard-2@your-rig \
--tags "mission:release,slice:rig-up-paper-cut-fix,gate:guard,handoff:per-commit,checkpoint:bug-1-bonus" \
--body-file /tmp/per-commit-body.txt
```
### `rig queue handoff <qitem-id> --to <next> ...` — hot-potato handoff
@@ -64,8 +83,8 @@ Example:
```bash
rig queue handoff qitem-20260601012431-d78aa805 \
--to qa@acme-web \
--tags "mission:site-relaunch,slice:02-search-filters,gate:qa,handoff:adversarial-dogfood"
--to velocity-qa@your-rig \
--tags "mission:release,slice:rig-up-paper-cut-fix,gate:qa,handoff:adversarial-dogfood"
```
### §1b doctrine — turn ends by passing the ball
@@ -99,9 +118,9 @@ process does not require.
recovery-only fallback; qitems written via `rigx queue` are invisible to
daemon-backed reads and break fleet-wide routing discipline.
- Inlining a multi-line / backtick-heavy body into `rig queue create --body`
→ write the body to `/tmp/<descriptive-name>.txt` first, then
`--body "$(cat /tmp/<file>.txt)"`. The body parser does not tolerate raw
backticks or flag-like tokens inline.
→ use `--body-file /tmp/<descriptive-name>.txt` (or `-` for stdin), the
corruption-safe surface. The body parser does not tolerate raw backticks or
flag-like tokens inline.
## Runtime-Gated Coordination Primitives
@@ -267,11 +286,15 @@ workflow spec.
workflow instance + entry-step qitem. Inspect existing surface state with:
```bash
rig workflow specs --json # list registered specs (built-in + operator-authored)
rig workflow list --json # list active workflow instances
rig workflow show <instanceId> --json
rig workflow specs --json # list registered specs (built-in + operator-authored)
rig workflow list --json # list active workflow instances
rig workflow show <instanceId> --json # inspect one instance
rig workflow project <instanceId> # ADVANCE an instance — projects the next-step packet
rig workflow continue <instanceId> # read-only inspector of an instance (does NOT advance it)
```
*(Surface note — the current `rig workflow` command group registers **13** subcommands: `validate`, `instantiate`, `project`, `list`, `specs`, `show`, `trace`, `continue`, `run`, `watch`, `route`, `resume`, `status`. There is still no `create` verb — the spec YAML is authored on disk. `project` is the advancing verb (it projects the next-step packet); `continue` is a read-only inspector, NOT an advance — do not conflate them. The 13-verb set and the project-vs-continue semantics are verified against current product main `d37a08ad` (`packages/cli/src/commands/workflow.ts`, 13 registered `.command(...)` entries; the earlier "6-verb surface / continue-advances" claim here was stale). Verify individual subcommand flags with `rig workflow --help`.)*
## v0.3.x Starter, Workspace, And Plugin Surfaces
OpenRig v0.3.0 adds `rig agent-image`, `rig context-pack`, `rig workspace`, and
@@ -388,7 +411,7 @@ reconcile:
```bash
rig seat clear-attention <session>
rig seat clear-attention <session> --reason "operator attested: founder re-authed, confirmed live"
rig seat clear-attention <session> --reason "operator attested: the operator re-authed, confirmed live"
rig seat clear-attention <session> --json
```
@@ -435,47 +458,27 @@ honestly and the UI exposes a one-click open-missing affordance.
v0.4.0 flips the five most frequently invoked read-commands from firehose-by-default to compact-by-default, and `rig queue list` adopts the docker / kubectl read-command grammar. **All defaults preserve breadth and capability — the firehose is one explicit flag away.**
### `rig ps` — consolidated all-rigs default + the disclosure ladder (v0.4.4)
### `rig ps` — current-rig default + compact-by-default + `-A`/`--all-rigs` + `--full`
```bash
rig ps # ALL ACTIVE RIGS, one compact row each + rollup line + count line + ladder footer (default)
rig ps --json # bare array of ALL non-archived rigs (incl. stopped; existing keys + additive attentionCount)
rig ps --rig <name> # one rig's detail
rig ps --nodes # compact node inventory (current rig — session default, LOCAL only)
rig ps --nodes --rig <name> # compact node inventory, named rig
rig ps --nodes -A # fleet node inventory, projected rows
rig ps --nodes -A --full # complete per-node records (the ONLY full fan-out; resumeToken VALUE retained here for downstream consumers)
rig ps # CURRENT-RIG, all-states, compact rig summaries (default)
rig ps --json # compact JSON array (TL;DR per node: session, rig, activity, assigned/pending, resumeTokenPresent boolean)
rig ps -A # all-rigs (fleet breadth; was the v0.3.4 default)
rig ps --rig <name> # explicit-rig (overrides current-rig default)
rig ps --nodes # compact node inventory (current rig)
rig ps --nodes -A # cross-rig node inventory (was v0.3.4 default)
rig ps --nodes --full # complete record (the v0.3.4 per-node default shape; resumeToken VALUE retained here for downstream consumers)
rig ps --nodes --session <sess> # narrow to one canonical session
rig ps --include-archived # archived history as rows (otherwise ONE count line)
rig ps --active # opt-in active-state filter (does NOT change the all-states default — ps surfaces topology/readiness, where stopped/recoverable/attention IS the actionable signal)
```
**v0.4.4 consolidated default + disclosure ladder (OPR.0.4.4.21)**:
- **The default is the fleet MAP**: every active rig as one O(rigs) compact row, with the host rollup ("N rigs · M seats · K need attention"), the archived/stopped count line, and the drill-ladder footer. The v0.4.0 current-rig default is RETIRED — it hid running rigs from the operator's field of view.
- **`-A` has exactly ONE meaning**: the `--nodes` fleet widener. Bare `rig ps -A` errors (all-rigs IS the default; archived history stays behind `--include-archived`).
- **The session-rig default applies ONLY to `--nodes`, and only locally.** Implicit scope defaults don't cross host boundaries: `rig ps --host <id> --nodes` requires an explicit `--rig` or `-A`; multi-host fan-out is rollup-only by default; the full explicit ladder (`--all-hosts --nodes -A`, `--full` for complete records) fans out per-node with hostId-stamped projected rows.
- **STATED JSON contract**: default `--json` = bare array of ALL non-archived rigs INCLUDING stopped ones (scope-not-shape: existing keys preserved, additive `attentionCount`); only the human table folds stopped rigs into the count line.
- **Resume-token security unchanged**: compact output never carries token material; `--full` retains it for consumers that legitimately need it.
**v0.4.0 breadth + projection changes**:
- **Default breadth is CURRENT-RIG** (derived from `OPENRIG_SESSION_NAME`'s `@<rig>` suffix), not all-rigs. `-A` / `--all-rigs` widens to fleet. Matches the `rig queue list -A` pattern.
- **Per-node TL;DR projection (compact) is the default**; `--full` returns the raw byte-equivalent passthrough. Daemon-side `recoveryGuidance` relocated to a guidance-by-reference map (no longer duplicated per-node) — even `--full` benefits.
- **All-states stays default** (different from `rig queue list` which defaults to active-only) — for `ps`, non-running states ARE often the actionable signal.
- **Resume-token security**: `--full` JSON emits `resumeTokenPresent` (boolean) — the actual `resumeToken` value also remains in `--full` for downstream consumers that legitimately need it, but the compact default never carries it (an orch glance never accidentally leaks token material).
**The casual status glance is just `rig ps`.** The old fleet firehose is the explicit last rung: `rig ps --nodes -A --full`. The ~77,000-token incident class stays closed (compact + O(rigs) default + explicit ladder).
### `rig host` — the multi-host registry verbs (v0.4.4)
```bash
rig host add --id <id> --transport ssh --target <tailnet-alias> --user openrig
rig host add --id <id> --transport http --url http://100.x.y.z:7433 --bearer-env MY_TOKEN
rig host list # pointers only — never secret values
rig host doctor <id> # stepwise: transport -> rig binary -> daemon -> identity
rig host doctor <id> --posture product-factory-vps [--public-addr <ip>]
```
Exactly three verbs (capped); the VPS factory bootstrap is script + runbook
(`docs/reference/product-factory-vps-runbook.md`). **Transport posture is
DECIDED and documented** (cli-reference §Cross-host execution): ssh = pane ops
(`send`/`capture`), http = daemon REST (`up`/`down`/`launch`), `ps`/`whoami`
follow the DECLARED transport; fan-out is http-only; no cross-transport
fallback; no http parity for send/capture in 0.4.4. Posture/doctor UNKNOWN is
never pass — each unknown carries the command that verifies it.
**STOP using `rig ps --nodes --json` as a fleet-wide casual status check assuming the v0.3.4 shape.** The v0.4.0 default is CURRENT-RIG + compact; explicit `-A --full` is the fleet firehose. The ~77,000-token status-glance incident is closed twice over (compact + scope).
### `rig whoami` — compact-by-default + `--full` (`--verbose` alias)
@@ -503,7 +506,7 @@ rig queue list --source <s> # sourced by <s>
rig queue show <qitemId> # full single item (kubectl describe)
```
Four orthogonal axes (scope × history × field-breadth × encoding), all composable. **STOP using bare `rig queue list` as the cross-rig firehose.** Default is now active + compact + current-rig. The cross-rig + history + full-body firehose (the ~64,000-token bomb on this host) is opt-in via `-A -a --full`.
Four orthogonal axes (scope × history × field-breadth × encoding), all composable. **STOP using bare `rig queue list` as the cross-rig firehose.** Default is now active + compact + current-rig. The cross-rig + history + full-body firehose (the ~64,000-token payload spike) is opt-in via `-A -a --full`.
### `rig restore-check` — summary + not-ready-only default + `--full`
@@ -535,16 +538,16 @@ This release closes the host-version-aged token-burn class: on this host the rea
The interim `token-efficiency-boot-guardrail` pack (the CLI-command prohibitions on `rig queue list` unfiltered, `rig ps --nodes --json` unfiltered, `rig restore-check`, `rig context`, `rig whoami --json`) is a host-version workaround for the bloated defaults this release closes. **The CLI-command-prohibitions half retires when 0.4.0 lands on the host.** The pack's bounded-local-search rule + scope / over-flag discipline GRADUATE to a standing convention (`conventions/bounded-local-search-and-flag-scope`) and continue to apply host-independently.
### `rig scope mission|slice progress` — deterministic progress updates (slice 33)
### `rig scope mission|slice progress` — deterministic progress updates
```bash
rig scope mission progress <mission> --status <state> --milestone <text>
rig scope slice progress <slice-path> --status <state> --note <text>
rig scope mission progress <mission> --add "<line>" # append a progress line; --set replaces; --section <heading> (default Rail); --status active|done|blocked
rig scope slice progress <slice-path> --add "<line>" # same flags: --add / --set, --section <heading>, --status active|done|blocked
```
Replaces hand-editing `PROGRESS.md` with markdown. Writes the canonical structure the OpenRig PROGRESS UI page reads. `rig scope mission create` + `rig scope slice create` now scaffold `PROGRESS.md` automatically per `conventions/scope-and-versioning/README.md`.
### `rig scope mission|slice stage / verified / reconcile` — deterministic maturity vocabulary (slice 35)
### `rig scope mission|slice stage / verified / repair` — deterministic maturity vocabulary
```bash
rig scope slice stage <slice> <new-stage> # wip / provisional / established / canonical / superseded / retired
@@ -554,40 +557,16 @@ rig scope mission stage <mission> <new-stage> # same enum + rules at mis
rig scope slice verified <slice> --against "<source>" # stamp `verified: <today> against <source>`; --against MANDATORY
rig scope mission verified <mission> --against "<source>"
rig scope slice reconcile <slice> # idempotent repair: backfill PROGRESS.md, conform id/stage/verified, repair ghosts
rig scope mission reconcile <mission> # mission-tier idempotent repair
rig scope slice repair <slice> # idempotent repair: backfill PROGRESS.md, conform id/stage/verified, repair ghosts
rig scope mission repair <mission> # mission-tier idempotent repair
rig scope slice show <slice> # derives read-time effective-reliability from (stage × verified)
# — stale-`verified` `canonical` reported as effectively `provisional`
```
Composes with slice 33's `progress` + scaffolding to make `rig scope` the **deterministic enforcer** of `conventions/scope-and-versioning` §1 (dot-IDs) + §2 (maturity vocabulary). Agents update `stage` / `verified` / `id` through commands rather than hand-editing markdown and drifting. The `--against` MANDATORY rule on `verified` is the anti-stale keystone: bare timestamps are rejected because a bare timestamp is exactly what lets stale trackers lie while looking fresh. **STOP hand-editing the `stage` / `verified` / `id` fields in scope frontmatter; use the new verbs.** Existing missions / slices with `id:null` ghosts or missing `PROGRESS.md` are repaired idempotently via `reconcile`.
Composes with the `progress` command + scaffolding to make `rig scope` the **deterministic enforcer** of `conventions/scope-and-versioning` §1 (dot-IDs) + §2 (maturity vocabulary). Agents update `stage` / `verified` / `id` through commands rather than hand-editing markdown and drifting. The `--against` MANDATORY rule on `verified` is the anti-stale keystone: bare timestamps are rejected because a bare timestamp is exactly what lets stale trackers lie while looking fresh. **STOP hand-editing the `stage` / `verified` / `id` fields in scope frontmatter; use the new verbs.** Existing missions / slices with `id:null` ghosts or missing `PROGRESS.md` are repaired idempotently via `repair`.
### The SDLC control plane — convention sections, the two locks, `rig proof` (v0.4.4)
The Living Notes UI is a plain projection of well-formed on-disk markdown. The conventions live in ONE shipped document — **`docs/reference/sdlc-conventions.md`** in the repo, materialized by the daemon at **`$OPENRIG_HOME/reference/sdlc-conventions.md`** (default `~/.openrig/reference/sdlc-conventions.md`) on an installed package — and the operating procedure is the **`mission-slice-sop`** skill. The command surface:
```bash
rig scope slice create <mission> <slug> [--template <kind>] # scaffolds ## Intent / ## Mini-requirements / ## Proof contract
# + proof/ + PROOF.md + IMPLEMENTATION-PRD.md — EVERY template kind
rig scope slice approve <slice> --scope spec # PLAN-LOCK: "the PRD matches my intent; this set gets built"
rig scope slice approve <slice> --scope delivery # PROOF-LOCK: the terminal sign-off (default scope; fires the freeze)
rig proof add <slice> --artifact-type qa --verdict PASS \
--candidate-sha <tip> --money-evidence "<one line>" \
--evidences "1,3" --media "walk.webm" \
--self-check "<looked at it>" # C1 proof drop into proof/; --evidences joins the drop to its
# proof-contract items and --media names the curated proof/-relative
# media it stands behind (what the DELIVERED section pairs + renders)
rig scope audit <mission> # deterministic backstop — flags missing sections / malformed
# proof contract / invalid C1 headers; ADVISORY, never blocks
```
The flow: intent → mini-requirements + proof contract (→ mockups for UI slices) → plan-lock → build the locked set → QA visual compare → `rig proof` drops → proof-lock. Approval is freeze/sign-off, **never** proven-green — proven-green requires recorded C1 verdicts.
### `rig skill audit` — skill cascade provenance (slice 10)
### `rig skill audit` — skill cascade provenance
```bash
rig skill audit # human report of findings
@@ -596,12 +575,46 @@ rig skill audit --severity warn # stale + mirror-drift only
rig skill audit --rig <name> # narrow to embedded skill copies for one rig
```
Read-only audit of the skill cascade. Detects `missing` / `stale` / `self-referential` / `invalid-date` / `mirror-drift` across the canonical `openrig-work/skills/` → product mirror → hub cwd → installed plugin chain. Findings route back to the lifecycle for shaped propagation runs. **False-green prevention**: when audit evidence is unavailable, the CLI emits `unable-to-audit` with exit code `2` rather than reporting `clean`.
Read-only audit of the skill cascade. Detects `missing` / `stale` / `self-referential` / `invalid-date` / `mirror-drift` across the canonical skills workspace → product mirror → hub cwd → installed plugin chain. Findings route back to the lifecycle for shaped propagation runs. **False-green prevention**: when audit evidence is unavailable, the CLI emits `unable-to-audit` with exit code `2` rather than reporting `clean`.
### `rig seat clear-attention` — extended to derived projection staleness (slice 16)
### `rig seat clear-attention` — extended to derived projection staleness
v0.3.4 shipped `clear-attention` gating on `session.startupStatus` only. v0.4.0 extends the verb to also reach **restoreOutcome-derived** attention (seat is `startupStatus=ready` + `sessionStatus=running` but carries `restoreOutcome=failed` / `continuityOutcome=failed`). Same evidence-gated audit row applies; the `--reason <text>` operator-attestation override carries the runtime / cwd-uncertainty disclosure honestly.
### Native Codex session id capture
Codex seats can now record the real native session id from the Codex
`SessionStart` hook instead of relying on scrape-shaped identity. The proof
lane for v0.4.0 matched the same id across the hook payload, rollout log, and
SQLite. Treat hook-sourced ids as stronger resume/identity evidence than
terminal scraping when present.
Managed-seat hook trust is a 0.4.1 carry: the v0.4.0 surface proves native
capture and hook-trust constraints, but do not assume every managed Codex seat
has already migrated from scrape-backed to hook-sourced ids.
### Codex resume preserves approval posture
Resuming a Codex seat preserves the launching seat's approval/sandbox posture
and profile flags. Product-emitted resume commands carry the posture flags
instead of silently falling back to implicit-deny or an unrelated profile.
Do not "fix" a resumed Codex seat by relaunching it with broader approvals
unless the operator explicitly grants a bounded window. Verify the seat's
active posture first, and preserve it when composing recovery commands.
### `rig seat set-resume-token --token-stdin`
```bash
printf '%s' "$RESUME_TOKEN" | rig seat set-resume-token <session> --token-stdin
```
Use this command to set or restore a seat resume token. It replaces direct
SQLite edits, rejects unauthorized writes and bad/null token false-ready paths,
records redacted audit/provenance, and keeps token material out of command
arguments, stdout, logs, and normal status rows. Use stdin, not an inline flag,
when passing token material.
## Core Loop
Most work in OpenRig reduces to this loop:
@@ -628,7 +641,7 @@ Typical operator loop:
```bash
rig up secrets-manager --cwd /path/to/project
rig ps --nodes --rig secrets-manager --json
rig ps --nodes --json
rig send vault-specialist@secrets-manager "Check Vault health and report back." --verify
rig env status secrets-manager
rig env logs secrets-manager
@@ -675,19 +688,18 @@ JSON form exposes `peersNote` directly for programmatic consumers.
## Inventory and Monitoring
```bash
rig ps
rig ps --json
rig ps --nodes
rig ps --nodes --rig <name> --json
rig ps --nodes -A --json
rig ps --nodes -A --full --json
rig ps # CURRENT-RIG, compact rig summaries (v0.4.0 default)
rig ps --nodes # compact node inventory (current rig)
rig ps -A # all-rigs breadth (was the pre-0.4.0 default)
rig ps --nodes --full # complete per-node record (the firehose — opt-in)
rig ps --nodes --json # compact JSON node inventory (add --full for the full record)
```
Use `rig ps --nodes --rig <name> --json` for one rig's node inventory, or `rig ps --nodes -A --json` for fleet-wide projected node inventory. Use `--full` only when a downstream consumer truly needs complete per-node records. The node inventory surface carries:
**v0.4.0 flipped these to compact-by-default — see the `rig ps` compact-defaults section above; STOP using bare `rig ps --nodes --json` as a fleet-wide firehose (the ~77k-token status-glance incident).** The compact `rig ps --nodes` node inventory (add `--full` only when you need the complete record, `-A` for cross-rig breadth) carries, per node:
- session name
- runtime
- session/startup status
- restore outcome
- restore outcome (compact: `resumeTokenPresent` boolean; the token VALUE is in `--full`)
- attach/resume commands
- latest error
@@ -719,13 +731,25 @@ rig transcript <session> --json
```bash
rig send <session> "message"
rig send <session> "message" --verify
rig send <session> "message" --force
rig send <session> "message" --wait-for-idle <seconds>
rig send <session> "message" --raw
rig send <session> "message" --dangerously-interact --reason "<why>"
rig send <session> "message" --host <id>
rig send <session> "message" --json
```
Use `--verify` when you want delivery evidence. Use `--force` only when you intentionally want to bypass activity-risk checks.
**The send-guard (v0.4.0) — the default is SAFE.** A default `rig send` is guarded: it will NOT submit into an interactive prompt / permission block on the target pane (the footgun that prematurely shipped 0.4.0). Flags:
- `--verify` — delivery evidence.
- `--force` — **a back-compat no-op on the send DECISION**: it never bypasses the interactive-prompt/permission guard and never changes whether a message is delivered (a mid-task/busy pane already sends-with-advisory by default). *(It does NOT "bypass activity-risk checks" — that earlier teaching is retired.)* It is **not fully inert**, though — it is still parsed solely to be **rejected in combination with `--wait-for-idle`**: `rig send … --force --wait-for-idle <n>` prints `--wait-for-idle cannot be combined with --force`, exits 1, and sends nothing. So do not read "no-op" as "`--force --wait-for-idle` is harmless"; that pairing errors. *(Verified against current product main `d37a08ad`: the guard-bypass no-op is declared at `send.ts` and confirmed by runtime capture — a plain `--force` send delivers through the ordinary path; the `--wait-for-idle` rejection is enforced at `send.ts`, `routes/transport.ts`, and `session-transport.ts`, and confirmed by runtime capture — exit 1, nothing sent.)*
- `--wait-for-idle <seconds>` — wait until the target is explicitly idle before sending. **Cannot be combined with `--force`** (that pairing is rejected: exit 1, nothing sent).
- `--raw` — send exact text/keystrokes without the From/To messaging envelope (still guarded against interactive prompts).
- `--dangerously-interact --reason "<why>"` — the ONLY override of the prompt/permission guard: deliberately drive an interactive prompt/permission block (implies `--raw`, requires `--reason`, audit-logged).
- `--host <id>` — send on a remote host declared in `~/.openrig/hosts.yaml` (ssh hosts shell out; http hosts go CLI-direct to the remote daemon).
- `--from <session>` — originating session for the envelope sender/actor (provenance; defaults to `$OPENRIG_SESSION_NAME`, and is plumbed through cross-host sends so the remote envelope names the origin, not the relay).
As of v0.3.3 (slice 17), content beginning with `--` or `-` is safe:
> **Durable work goes to the QUEUE, not `send`.** `rig send` is an *ephemeral* message to a pane — it can be missed, and its delivery status is pane-render, not receipt. If you are **assigning work, or the message is important enough that losing it would be a real bummer**, use `rig queue` (below): it's durable, owned, tracked, and survives compaction and restart. Reach for `send` for a quick conversational nudge; reach for the **queue** for anything that must not get lost. Do not default to `send` for work — that's the most common mistake.
As of v0.3.3, content beginning with `--` or `-` is safe:
`rig send <session> "content starting with -- or - is now safe"` delivers
literally. The daemon's `send_text` path carries an explicit `--`
end-of-options sentinel so tmux no longer parses dash-prefixed content
@@ -774,7 +798,17 @@ rig broadcast "message"
rig broadcast --rig <name> "message" --json
```
Without `--rig` or `--pod`, broadcast targets all running sessions.
**Use `rig broadcast` sparingly — prefer `rig send` fan-out.** Without `--rig` or `--pod`, broadcast targets
**every running session across ALL rigs** (plus attached external_cli nodes) — the fastest way to cause a
broadcast storm. Reserve `rig broadcast` for small rigs or a genuine all-hands emergency. For the normal
"message several seats at once" case, use `rig send`, which scopes the fan-out and keeps the messaging
envelope, the delivery/interactive-prompt guards, and per-recipient results:
```bash
rig send --to dev-impl@my-rig,dev-qa@my-rig "message to specific seats" # named seats (comma-list or repeat --to)
rig send --pod dev "message to one pod" # scoped fan-out
rig send --rig my-rig "message to one rig" # scoped fan-out
```
### Chatroom
@@ -792,6 +826,27 @@ rig chatroom watch <rig> [--tmux]
- `history` — retrieve with composable filters (sender, since, after, topic)
- `wait` — block until new matching messages arrive (polls history, times out honestly)
- `clear` — delete all messages for the rig (destructive, rig-scoped)
## See something, say something
OpenRig has an **observation stream** — the fleet's zero-friction institutional memory, mined for
real product improvements. When you notice **anything worth externalizing**, say something and keep
working:
- a **bug**, a rough edge, or something that needs fixing
- a **feature idea** or an improvement
- something that **worked really well** — a technique, tool, or pattern worth spreading
- an **observation**, positive or negative feedback, or something genuinely cool, productive, or funny
```bash
rig stream emit --source <your-session> --body "what you noticed"
```
That's the whole reflex. **Don't** decide where it goes or who it's for — the intake router triages
(destination/type/urgency/tags are optional hints — `--hint-type review|handoff|idea`,
`--hint-urgency routine|urgent|critical`, `--hint-tags` — never required). One command, then carry
on; the value is the habit, not the polish. **Don't overdo it, either:** stream real signal, not
narration — a good observation beats ten noisy ones. It's a passing thought you externalize, not a chore.
- `topic` — set a topic marker
- `watch` — SSE or tmux-based live stream
@@ -822,6 +877,21 @@ Current shipped behavior:
This is an evidence/context command. It is not a hidden second-LLM call.
### `rig auth` — agent auth-profile management (v0.4.1, product-native)
Product-native switching of agent auth profiles from the CLI. The runtime is a **flag** (`--runtime <codex>`), not a command noun — never `rig codex-auth`.
```bash
rig auth status --runtime codex # presence / mode / parseability / login-state (never prints token contents)
rig auth list --runtime codex # saved profiles
rig auth save <profile> --runtime codex # snapshot the auth FILE (mode-guarded), never echoes contents
rig auth switch <profile> --runtime codex
rig auth validate <profile> --runtime codex
rig auth seats … --runtime codex # seat -> profile registry (metadata only; NOT proof of a live account)
```
**Hard secret boundary:** no token value is ever printed, logged, queued, streamed, or committed; status/validate report presence/mode/login-state only; seat labels are metadata, not live-account proof. MVP is `--runtime codex`; other runtimes use the same surface with a different `--runtime`, never a parallel command.
## Lifecycle
### Bring a rig up
@@ -1010,7 +1080,7 @@ rig whoami --json
Notes:
- for tmux-backed self-attach, `rig whoami --json` is the right verification
- for raw/external self-attach, `rig ps --nodes --rig <rigId-or-name> --json` is currently the more reliable verification surface
- for raw/external self-attach, `rig ps --nodes --json` is currently the more reliable verification surface
- if the current shell is outside tmux, pass `--display-name <name>` when you want a stable human session label recorded
### Adopt a topology and bind live sessions
@@ -1077,13 +1147,13 @@ Verification loop:
```bash
rig discover --json
rig adopt <fragment.yaml> --bindings-file <bindings.yaml> --target-rig <rigId>
rig ps --nodes --rig <target-rig-name> --json
rig ps --nodes --json
rig export <rigId> -o rig.yaml
```
Success looks like:
- the new sessions stop appearing in `rig discover`
- the new logical IDs appear in `rig ps --nodes --rig <target-rig-name> --json`
- the new logical IDs appear in `rig ps --nodes --json`
- `rig export` includes the new pod
### Mixed-origin rigs are allowed
@@ -1101,7 +1171,7 @@ Current safety rule:
The proven operator pattern is:
- keep one OpenRig manager session outside the rig it manages
- address the target by rig name, not cached rig ID
- resolve the current owner from fresh `rig ps --nodes -A --json`
- resolve the current owner from fresh `rig ps --nodes --json`
- send the manager the spec path, bindings path, and verification steps with `rig send`
This lets ordinary agents ask the manager for OpenRig help instead of every agent needing to be an OpenRig expert.
@@ -1198,7 +1268,7 @@ When the CLI behaves strangely, use the smallest truthful check first:
```bash
rig whoami --json
rig daemon status
rig ps --nodes
rig ps --nodes --json
```
Specific operator rules:
@@ -1234,7 +1304,7 @@ Design assumptions that hold in the shipped CLI:
1. `rig whoami --json`
2. `rig transcript <your-session> --tail 100`
3. `rig ps --nodes`
3. `rig ps --nodes --json`
4. `rig chatroom history <rig> --limit 50`
## Commands That Do Not Exist
@@ -2,14 +2,31 @@
name: queue-handoff
description: Use when ending a turn, finishing a slice, blocked on another agent's work, or escalating to a human — durable work handoff via queue items so the system keeps moving across compactions, missed messages, and interruptions. Covers the hot-potato terminal-turn-rule (active work ends by passing the ball, not by going idle), default-nudge semantics, and when `--no-nudge` is appropriate for intentional cold park or human gate.
metadata:
cli_surfaces_referenced:
- queue
- queue create
- queue handoff
- queue handoff-and-complete
openrig:
stage: factory-approved
last_verified: "2026-06-24"
distribution_scope: product-bound
source_evidence: |
Daemon-backed `rig queue` shipped in v0.2.0 (PL-004 Phase A) with handed-off-to / handed-off-from / state field shape. `rig queue` is canonical for new work; `rigx queue` is recovery-only fallback. The daemon enforces hot-potato strict-rejection at the API. Body resynced from canonical 2026-06-24 (demo-blocker fix: corrected the default-nudge guidance — the default already nudges; the previously-described extra notify flag does not exist on the shipped CLI).
sibling_skills: []
transfer_test: pending
sibling_skills:
- workflow-runtime
- watchdog
- alignment-trace
- looping-workflows
- intake-routing
- human-in-the-loop
- attention-queue
- dispatching-parallel-agents
- subagent-driven-development
- structured-ack-dispatch
- control-plane-capabilities
- status-not-chat-orchestrator
- control-plane-queue
- control-plane-watchdog
- control-plane-workflows
- control-plane-delivery-loop
- control-plane-rollout-manager
---
# Queue Handoff
@@ -67,7 +84,7 @@ every surface (CLI, MCP, future UI) inherits the same guarantee.
| `rig queue create` | yes | New qitem created from scratch |
| `rig queue handoff` | yes | Transactional close-as-handed-off + create-new |
| `rig queue handoff-and-complete` | yes | Atomic close + create-new; default nudge wakes the new owner |
| `rigx queue handoff` (filesystem v0 prototype; **recovery-only fallback since 2026-05-11**) | yes | Legacy artifact; qitems invisible to daemon-backed reads; deprecated with removal queued. Use `rig queue handoff` (daemon-backed) for all new substantive work. |
| `rigx queue handoff` (filesystem v0 prototype; **recovery-only fallback since 2026-05-11**) | yes | Legacy artifact; qitems invisible to daemon-backed reads; deprecation warning + removal queued at `missions/bug-fix/slices/rigx-queue-deprecation-message/`. Use `rig queue handoff` (daemon-backed) for all new substantive work. |
**Footgun**: `--no-nudge` accidentally added to a live-loop handoff.
The shipped 0.3.1 CLI nudges by default on every queue write surface
@@ -96,8 +113,8 @@ recipient.
at the file for the detail. A pasted dump makes `rig queue show <id>
--json` huge — a second-order token bloat: bloated DATA living in the
queue, distinct from the command-default output bombs the token-burn
emergency pack covers. (Sensor: dev1-guard token-burn-flag 8ea201e4,
2026-06; founder-directed cure.)
emergency pack covers. (Sensor: guard token-burn-flag 8ea201e4,
2026-06; operator-directed cure.)
- **Substantive bodies go through `--body-file`, not inline `--body`.**
For anything beyond a short line, write the body to a file and pass
`--body-file <path>` (or `-` for stdin). Inline `--body` with shell
@@ -4,16 +4,17 @@ description: Use when replacing a seat's occupant (rebuild/handover/swap), reaso
metadata:
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Option A rebuild MVP shipped 2026-04-30. Option B (full code-direct
seat handover via SeatHandoverService daemon module) is a future
follow-on.
sibling_skills:
- claude-compaction-restore
- mental-model-ha
- scope-recovery
- session-compaction-and-restore
- agent-startup-and-context-ingestion
transfer_test: pending
- agent-starters
- composable-priming-packs
- session-source-fork
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# Seat Continuity and Handover
@@ -133,5 +134,6 @@ enough to receive new work or needs re-handover.
## See also
- `claude-compaction-restore` skill — packet-driven restore after Claude compaction
- `agent-startup-and-context-ingestion` skill — ingestion path for restore packets at agent boot
- `session-source-fork` skill — `fork` occupant-creation primitive (sibling)
- `agent-starters` skill — composes occupant-creation + binding into named reusable starting points
- `cross-host-rig-commands` skill — multi-host handover (deferred)
@@ -0,0 +1,162 @@
---
name: session-compaction-and-restore
description: Use when reasoning about what survives compaction/context-loss/restart/seat-refresh, designing a high-fidelity restore packet, or distinguishing native runtime resume vs fork vs artifact-backed mental-model rebuild. Covers the 4 failure modes that prevent honest restore (compacted seat drops hot potato; restore packet preserves details but loses product intent; runtime resume mistaken for handover or fork; rebuilt seat starts with stale instructions).
metadata:
cli_surfaces_referenced:
- whoami
openrig:
stage: factory-approved
sibling_skills:
- claude-compaction-restore
- mental-model-ha
- scope-recovery
- agent-startup-and-context-ingestion
- agent-starters
- composable-priming-packs
- session-source-fork
- seat-continuity-and-handover
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# Session Compaction and Restore
Preserving useful working state across **compaction, context loss,
restart, or seat refresh.** Includes Claude compaction restore, Codex
resume/fork mechanics, transcript-based mental-model rebuilds, and
durable handoff packets.
**Long-lived seats are valuable only if they can survive context
pressure.** If compaction turns a senior seat into a cold-started
agent, users will avoid persistent topologies and fall back to
throwaway agents.
## Use this when
- A seat is approaching compaction or just compacted
- Designing a high-fidelity restore packet for an active workflow
- Distinguishing native runtime resume vs fork vs artifact-backed mental-model rebuild
- Reasoning about what should be preserved vs reconstructable
- Auditing a restore for product-intent preservation (not just detail preservation)
## Don't use this when
- The session is fresh and has no working state to preserve
- The intent is to *create* a new seat from a primed source — that's `session-source-fork` or `agent-starters`
- The packet is a one-off snapshot for human review — restore packets are for re-entering active work
## The 5 distinctions (do not collapse)
Per the cross-runtime restore/reentry packet standard:
| Mode | What it means | Outcome literal |
|---|---|---|
| **Native resume** | Continue the same managed seat with native runtime token | `resumed` |
| **Fork** | New managed seat from prior native runtime conversation; new post-fork token | `forked` |
| **Rebuild** | Fresh-launch seeded with operator-declared artifacts in trust-precedence order | `rebuilt` |
| **Artifact-backed mental-model rebuild** | Restored seat derives understanding from a packet rather than native runtime continuity | (case of `rebuilt`) |
| **Fresh launch** | New agent without prior continuity | `fresh` |
These are load-bearing distinctions. **Do NOT collapse `fork` into
artifact-backed reentry; do NOT collapse `rebuild` into fork.**
## The three mechanisms — who owns each (verified vs main d37a08ad, 2026-07-21)
The outcomes above ride on three DISTINCT mechanisms; keep them separate:
1. **Claude built-in `/compact`** — a Claude Code HARNESS feature, **not OpenRig
code**. OpenRig only *emits* the literal `/compact` toward the pane after a prep
turn; there is no compaction algorithm in the OpenRig repo. Provider-owned.
2. **OpenRig-managed restore** — the enforcer + hook bridge: a precompact hook
WRITES a restore packet; a bridge READER injects exactly ONE restore directive
back via the harness hook channel (`hookSpecificOutput.additionalContext`),
seat-isolated. The OpenRig-owned half.
3. **Codex session continuity** — resume/rollout tokens (`codex resume <token>`),
a separate path from the Claude mechanisms. Never conflate with Claude restore.
**Safety boundary (ties to `native-session-file-lab-boundary`):** no supported
OpenRig path EDITS provider-owned native **session / auth / transcript** files to
inject context. Context enters ONLY through sanctioned channels: the hook
`additionalContext`, a normal user message via `rig send`, or Codex resume tokens.
Precise nuance: OpenRig *does* write `~/.codex/config.toml` — but only to install
OpenRig activity **hooks** and `[features]`, never session or auth state. So the
rule is "never edits native session/auth/transcript files," NOT "never touches any
provider-owned file."
## Current CLI surface (operator / kernel seats; verified vs main d37a08ad)
Managed compaction/restore is driven by five shipped verbs — pick per intent, and
stay durable-substrate-first (the packet/artifacts are the truth; the CLI is the trigger):
- **`rig compact <session>`** — guided managed compaction for ONE Claude seat
(prep → `/compact` → restore → audit). Non-Claude seats rejected. ~180s.
- **`rig compact-plan`** — READ-ONLY triage; *does not compact*. Flags `--rig`,
`--refresh`, `--threshold-tokens`, `--threshold-percent`. (Codex seats flagged
`codex_not_managed_by_claude_compact_in_place`.)
- **`rig restore-check`** — restore-readiness probe across running rigs; read-only;
exit 0/1/2. Flags `--full`, `--ready`, `--rig`, `--no-queue`, `--no-hooks`.
- **`rig restore-packet {write,read,validate}`** — the cross-runtime restore
packet (v0): write / read / validate the durable packet this skill's contract defines.
- **`rig restore <snapshotId> --rig <rigId>`** — ⚠ RIG SNAPSHOT restore (infra), a
DIFFERENT mechanism — NOT session-context restore. Do not conflate.
## Failure modes (4)
1. **A compacted seat forgets active workflow state and drops the hot potato.** Compaction without continuity preservation is silent failure.
2. **A restore packet preserves details but loses the user's product intent.** Restore must preserve *why this work matters*, not just *what was happening*.
3. **A runtime resume is mistaken for a seat handover or fork.** These have different continuity outcomes and provenance — don't conflate.
4. **A rebuilt seat starts with stale instructions that conflict with current workflow mode.** Restore must include current state, not just historical state.
## Proof standard
Proof should include a deliberate compaction/restart of a seat with
active work, followed by **measured recovery**: identity, current
workflow, next owner, relevant files, and constraints all restored
without human re-briefing.
## Canonical packet contract (16-field, v0)
The cross-runtime restore/reentry packet standard v0 defines:
- Source/target identity
- Runtimes
- Workspace root, default repo, role pointer
- Bounded latest transcript
- Touched-path inventory
- Durable work pointers
- Current work + next owner
- Caveats + authority boundaries
- Omitted classes + redaction policy
- Source-trust ranking
- Generated-at + generator version
Plus a 6-item restored-seat acceptance checklist.
Source-trust ranking applies when restored seat ingests packet evidence:
**`rig whoami` > target rigspec > bounded latest transcript > full
transcript > touched-files > `restore-summary.json`.**
## Memory surfaces consumed at restore time
This primitive consumes multiple externalized memory surfaces. Per the
externalized-memory-surfaces convention's 13-row first inventory pass,
the primary rows for restore are:
| Row | Surface |
|---|---|
| 1 | Transcripts |
| 2 | Durable chat |
| 3 | Startup replay context |
| 5 | Checkpoints |
| 12 | Restore/reentry packets and Agent Starters |
The umbrella's authority-rank + permission-posture columns govern which
surfaces a restore path can write vs only read.
## See also
- `claude-compaction-restore` skill — the Claude Code restore SOP (PreCompact hook + JSONL restore script for post-compaction recovery)
- `mental-model-ha` skill — HA-pair compaction recovery (different scenario; sister primitive)
- `session-source-fork` skill — `fork` mode for native-runtime-continuity-based restoration
- `seat-continuity-and-handover` skill — occupant-creation primitives (resume/fork/rebuild/fresh) that this primitive instantiates
- `externalized-memory-surfaces` skill — umbrella convention listing all surfaces this primitive consumes
@@ -0,0 +1,165 @@
---
name: software-for-agents
description: |
Load this FIRST, before you assume how anything here works — especially before building, modifying, or
"fixing a bug" in an OpenRig or studio-box system, or when something behaves unexpectedly and you're
about to treat it as a code bug. You are almost certainly NOT operating in traditional software. This
is a self-improving MARKDOWN CONTROL PLANE: the substrate is markdown + YAML + JSON + folder structure
(skills, instructions, bootstrap files, schemas, conventions), and most "bugs" are coherence gaps in
that layer, not broken functions. Read this to form the correct mental model so your fixes land at the
precise spot that stops the footgun for every future rig — not just patch a symptom. NOTE: the
bug-tolerance in this model is SCOPED to agent-managed software; the OpenRig core and rigs.to stay
rock-solid — see the scope block up top before you apply anything here.
metadata:
openrig:
stage: factory-approved
audience: any agent building on OpenRig or a studio box — the first-load mental model
sibling_skills:
- forming-an-openrig-mental-model
- openrig-program-manager
- mission-slice-sop
- openrig-user
---
# Software for agents — the markdown control plane
## Where this applies — and where it does NOT (read this first)
This mental model — *most bugs are coherence gaps, not code*; *ship-and-flag when unsure*; iterate fast —
is scoped to **agent-managed software: the studio-box mini-apps and any agent-in-the-middle / rapidly-
evolving lightweight UI** where an agent sits in the loop and downstream cleanup is cheap. It is NOT a
universal license.
**It does NOT apply to TRADITIONAL software held to a rock-solid, no-bugs bar:** the **OpenRig CLI
surfaces**, the **OpenRig repo** (daemon / CLI / UI / adapters), and the **rigs.to website**. There, a bug
is a bug — reproduce it, fix it in code, hold the full-rigor gate. Do NOT treat a real defect there as a
markdown coherence gap, and do NOT "ship and flag." If you are building or fixing OpenRig core or rigs.to,
the tolerance in this skill is OFF and `product-is-the-truth-not-the-proof` governs. **Know which lane
you're in before you apply anything below.**
---
You inherited the accumulated footgun-map of thousands of rigs that ran before you. They found and
solved most of the traps. Your job is to find the *next* one and patch it at the precise optimal spot
in the substrate, so the rig after you starts from a higher ledge. That is the actual work. Whatever
you were "assigned" (a video, a feature, a fix) is the vehicle for surfacing it.
## 1. This is not traditional software — it's a control plane made of markdown
In traditional software a bug is a broken function you fix in code. Here, the system you operate in is
an **agent-in-the-middle** system whose substrate is **markdown + YAML + JSON + folders**: skills,
instructions, bootstrap files (`CLAUDE.md`/`AGENTS.md`), schemas, `culture.md`, mission/slice notes,
conventions. **The agents ARE the backend.** So most "bugs" are not broken code — they are **coherence
failures in the markdown layer**: an instruction that's unclear or missing, a schema that drifted from
its documented state, a convention living in one seat's head instead of a skill.
**Consequence:** when something surprises you, your first hypothesis is *"the control plane is unclear
or drifted here,"* not *"the code is broken."* Sometimes it IS the code (fix it — don't overfit on
markdown; see §5, and mind the scope block above: in OpenRig core / rigs.to the code IS the first
hypothesis). But the highest-leverage fixes in the agent-managed layer are usually: make the substrate
coherent again at the exact spot the confusion arose. Keep the markdown/schemas/conventions in sync with
reality and the system **self-improves** — the next rig inherits the patched substrate and never re-hits it.
## 2. Progressive disclosure — skills are a hot tier, not a manual
Skills are misnamed. They are a **progressive-disclosure primitive**. Think CPU cache / hot storage
tier: the **name + description of every skill is always ambiently loaded** — a hot tier of awareness
the agent carries without opening anything. That is enormous leverage, good or bad. So:
- **Write skill name + description as TRIGGERS** — *why/when do you reach for this?* — not as titles.
The hot tier's whole job is to fire when an agent doesn't yet know it needs the skill (the
"you don't know what you don't know" problem). This skill's own description is written that way.
- **Reaching for a skill unfurls a trail.** A good skill routes you — breadcrumbs, pointers, maps —
so it becomes *inevitable* you find the exact context on disk for what you're doing.
- **If the context doesn't exist, generate it.** A skill can ship **scripts** that produce context
optimally shaped for a decision, or that execute a fiddly API surface so you don't stumble through 12
tool calls discovering it. Use a **script as a prompt**: run it — if it works, the result IS your
context; if it fails, it should fail in a way that *teaches* you how the system works, so you can
read the script, understand the edge case, and do the thing manually. Scripts belong in the skill
folder next to the SKILL.md.
## 2b. Self-certifying artifacts — the convention 5 seats (both models) converged on
The single most expensive failure class in production is **not being able to tell a finished artifact
from an unfinished one.** A mid-write file read as final; a render OOM-killed mid-write left a corrupt
`.mp4` that passed a filename check; a truncated clip passed a duration check and froze on playback. In
one build, five seats — Claude *and* Codex, independently — each invented a *different* ad-hoc
completeness check (ffprobe moov, duration compare, filename convention, manifest assetExists, ffmpeg
input count). Five blind spots. So make it ONE shared primitive:
**When you author ANY tool that produces an artifact (render / composite / export / cut), it must
self-certify:**
1. Write to `<name>.partial` (never the final path directly).
2. **Verify the content** — the specific property that can be wrong, not a proxy: moov atom present,
duration matches the intended window, audio stream present, colorspace/hue correct, resolution =
delivery res. (Filename ≠ correct; duration ≠ complete; "clean-encoded" ≠ right.)
3. **`fsync`, then atomically `rename`** `<name>.partial` → `<name>` (rename is atomic; a half-written
file never appears at the real path).
4. Write the manifest, then a **`.done` sentinel LAST.**
Then *"is this finished?"* is **one `stat` of `<name>.done`** — identical for every tool, seat, watcher,
and a compacted agent restoring cold (who is least equipped to know what was mid-write when the lights
went out). **Consumers fail closed:** e.g. a swap-into-slot (`restore_occupant`) must refuse an artifact
lacking `.done` or failing the verify-gate. This convention collapses the whole "content over filename,
disk over memory" discipline into one check the substrate enforces for you. Build the sentinel; the
workarounds disappear. (Code-side companion: a fail-closed verify-gate wired into the swap verb — a
coordinated build with the tool owner, not a solo markdown edit.)
## 3. Build it like software — piggyback on what agents are trained for
Agents are fine-tuned to write code and build software; the harness itself is a terminal/coding
instrument. So **whatever you're asked to build — even a video — map the process to a software SDLC**
and you inherit all that baked-in muscle memory. This is why, e.g., the mini-NLE's beats carry
reference IDs like `1.1 / 2.1`: a storyboard is the **human-facing visual metaphor**, but underneath it
is a **specification** — sections, beats, success criteria, the thing being built.
Use an **agent SDLC**, not the antiquated human one (which was shaped around human-org weaknesses):
**intent → plan → spec → build → verify → review → QA → done.** The human slots in as **steering,
judgment, taste, review**; the agents do the technical nitty-gritty, in parallel, fast. Map any
"build X with agents" task onto this and the primitives (specs, locks, proof, verification) become
intuitive instead of alien.
## 4. Phases and the LOCK gate (spec-locking, not just "done")
Building runs in **phases**, and each phase has a **lock gate** — you don't advance until the taste/
steering owner has locked it. This is exactly *don't start building until the PRD is locked by product*:
- **Storyboard / intent phase** — done on the **canvas** now (the highest-bandwidth human↔agent surface:
the human steers, chats, annotates/circles; agents build structure fast). Iterate here; get the
storyboard through the canvas gate. (Canvas largely replaced the NLE's old in-timeline storyboard.)
- **Plan phase (brief, in the NLE)** — build the spine with placeholders so the human can click through
the main-stage player and *feel the flow* (sequencing problems surface when placeholders are strung
together with audio). **Lock every beat** = the spec is approved; this is what unlocks parallel build.
- **Fill phase** — many agents build each beat in parallel, in clear lanes. **Lock a beat when it's
final** (`/api/approve`): lock means *don't touch, we're good, signal to everyone incl. the human.*
Unlock to revise. **All beats locked = done.**
The lock is the "finished" primitive at the editorial layer. Locking a whole phase's beats before the
next phase is the discipline that lets 10 agents work in parallel without catastrophic collisions —
everyone knows the target, their lane, and who judges done (the **producer owns the final product**).
## 5. Where to fix — and don't overfit on markdown
- **Precise-spot discipline:** find the *one* place a coherence fix belongs (the skill, the schema, the
bootstrap, `culture.md`) so it can't recur — not a symptom patch. Ask: *what would have prevented
this for every future rig?*
- **Don't overfit on the markdown layer** — deterministic code bugs exist and you should fix them. The
studio-box apps (NLE, canvas, media manager, shell) live in the **studio-box repo**, portable across
hosts (VPS/Mac/VM). **A code fix there fixes ALL studio boxes, not just this host** — so: clear bug or
broadly-useful feature → ship it; host-specific behavior → make it optional/guarded. When unsure, ship
and flag it; downstream cleanup beats you becoming the bottleneck. *(This ship-and-flag latitude is the
studio-box / agent-managed lane only — re-read the scope block: OpenRig core + rigs.to hold the
rock-solid bar, no ship-and-flag.)*
- **Culture lives in `culture.md`** — the rig's social contract / constitution: how the team
coordinates, the parallel-agent lanes, the phase-locking discipline, who owns the final call.
Coordination is largely **emergent** (bottom-up, evolutionary pressure across thousands of rigs) — but
once a pattern proves out, *write it down there* so it's inherited, not re-discovered.
## The one-line seed
You're not maintaining code; you're **gardening a self-improving control plane made of markdown and
schemas, using software-engineering muscle memory, with the lock as your spec-gate** — and every
footgun you patch at the right spot (in the agent-managed lane) makes every future rig better. See also:
`forming-an-openrig-mental-model` (the OpenRig runtime), `mission-slice-sop` (the SDLC operating
procedure), `openrig-user` (the CLI surface), `product-is-the-truth-not-the-proof` (the doctrine that
governs the rock-solid lane). *(The "agents ARE the backend" idea — agent-in-the-middle — is inlined in
§1; a standalone `agent-in-the-middle` skill is a future candidate, not yet authored.)*
@@ -97,8 +97,18 @@ export async function extractSkillEdgeLayout({
config.forward_overrides ?? {},
).sort()) {
validateOverride(skill, override, config.edges, sourcePath);
if (override.edges.length === 0) {
skills.delete(skill);
continue;
}
const edges = new Set(override.edges);
if (edges.has("spec")) {
for (const [edge, edgeConfig] of Object.entries(config.edges)) {
if (edgeConfig.layout === "mirror-of-spec") edges.add(edge);
}
}
skills.set(skill, {
edges: [...new Set(override.edges)].sort(),
edges: [...edges].sort(),
category: override.category ?? null,
});
}
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, openrig-user, systematic-debugging, verification-before-completion, vault-user]
skills: [using-superpowers, systematic-debugging, verification-before-completion, vault-user]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user, mission-slice-sop, development-team, test-driven-development, systematic-debugging, executing-plans, verification-before-completion]
skills: [development-team, test-driven-development, systematic-debugging, executing-plans, verification-before-completion]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user, mission-slice-sop, orchestration-team, backlog-capture, writing-plans, executing-plans, verification-before-completion, brainstorming]
skills: [orchestration-team, backlog-capture, writing-plans, executing-plans, verification-before-completion, brainstorming]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user, mission-slice-sop, requirements-writer, context-builder, writing-plans, verification-before-completion]
skills: [requirements-writer, context-builder, writing-plans, verification-before-completion]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user, mission-slice-sop, review-team, plan-review, systematic-debugging, verification-before-completion]
skills: [review-team, plan-review, systematic-debugging, verification-before-completion]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, openrig-user, mission-slice-sop, development-team, frontend-design, verification-before-completion, writing-plans, brainstorming]
skills: [using-superpowers, development-team, frontend-design, verification-before-completion, writing-plans, brainstorming]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, openrig-user, mission-slice-sop, development-team, test-driven-development, systematic-debugging, verification-before-completion, writing-plans, executing-plans]
skills: [using-superpowers, development-team, test-driven-development, systematic-debugging, verification-before-completion, writing-plans, executing-plans]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, test-driven-development, openrig-user, mission-slice-sop, development-team, systematic-debugging, verification-before-completion, agent-browser, dogfood, writing-plans, executing-plans]
skills: [using-superpowers, test-driven-development, development-team, systematic-debugging, verification-before-completion, agent-browser, dogfood, writing-plans, executing-plans]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, openrig-user, mission-slice-sop, dogfood, systematic-debugging, verification-before-completion]
skills: [using-superpowers, dogfood, systematic-debugging, verification-before-completion]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, openrig-user, mission-slice-sop, verification-before-completion]
skills: [using-superpowers, verification-before-completion]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, openrig-user, mission-slice-sop, orchestration-team, systematic-debugging, verification-before-completion, writing-plans, executing-plans, brainstorming]
skills: [using-superpowers, orchestration-team, systematic-debugging, verification-before-completion, writing-plans, executing-plans, brainstorming]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -15,8 +15,6 @@ profiles:
default:
uses:
skills:
- openrig-user
- mission-slice-sop
- office-hours
- context-builder
- requirements-writer
@@ -24,6 +22,7 @@ profiles:
- plan-review
- exec-summary
- backlog-capture
plugins: [shared:openrig-core]
runtime_resources:
- shared:claude-default-settings
- shared:claude-default-mcp
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user]
skills: []
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user]
skills: []
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -11,9 +11,10 @@ imports:
profiles:
default:
uses:
skills: [using-superpowers, openrig-user, mission-slice-sop, review-team, systematic-debugging, verification-before-completion, writing-plans, brainstorming]
skills: [using-superpowers, review-team, systematic-debugging, verification-before-completion, writing-plans, brainstorming]
guidance: []
subagents: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -16,18 +16,10 @@ resources:
path: skills/process/frontend-design
- id: using-superpowers
path: skills/process/using-superpowers
- id: openrig-user
path: skills/core/openrig-user
- id: openrig-operator
path: skills/core/openrig-operator
- id: openrig-installer
path: skills/core/openrig-installer
- id: openrig-architect
path: skills/core/openrig-architect
- id: rig-lifecycle
path: skills/core/rig-lifecycle
- id: mission-slice-sop
path: skills/core/mission-slice-sop
- id: systematic-debugging
path: skills/process/systematic-debugging
- id: test-driven-development
@@ -57,6 +49,11 @@ resources:
path: skills/pm/exec-summary
- id: backlog-capture
path: skills/pm/backlog-capture
plugins:
- id: openrig-core
source:
kind: local
path: ~/.openrig/plugins/openrig-core
runtime_resources:
- id: claude-default-settings
path: runtime/claude-settings.fragment.json
@@ -0,0 +1,132 @@
---
name: agent-starters
description: Use when creating, refreshing, packaging, inspecting, promoting, or deprecating a named per-seat starting point — Agent Starter manifest authoring, the 6-state lifecycle (captured → named → inspectable → used → promoted → deprecated), provenance honesty, and refusal rules. NOT a VM image; a managed starting point composed from agent role + startup context + optional native session source + provenance.
metadata:
openrig:
stage: factory-approved
sibling_skills:
- claude-compaction-restore
- mental-model-ha
- scope-recovery
- session-compaction-and-restore
- agent-startup-and-context-ingestion
- composable-priming-packs
- session-source-fork
- seat-continuity-and-handover
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# Agent Starters
A named, reusable per-seat starting point. Composes an agent role, startup
context, optional native session source, and provenance into something a
user or rig can choose when creating, refreshing, or packaging a seat.
"Agent image" is the analogy. **Agent Starter is the cleaner product
noun.** This is NOT a VM image — it is a managed starting point for an
agent seat, with provenance you can inspect.
## Use this when
- Creating a new seat from a known-good starting context.
- Refreshing a seat with `rig expand` and `starter_ref`.
- Authoring a new starter (registry entry).
- Inspecting an existing starter's provenance, freshness, or recommended status.
- Promoting / deprecating starters in the registry.
- Composing a starter with a Composable Priming Pack (record manifest id/version, runtime, source session id or transcript path, ready-check evidence, freshness state).
## Don't use this when
- You want VM-style deterministic state capture. Starters don't capture VM state.
- You want to copy provider auth material into a starter. **Starters refer to session sources and context; they do NOT copy credentials.**
## What makes a starter valuable
A starter is valuable when it is **functional** — it carries the context the seat needs to do its task well. Functional is the *only* measure of a good starter. Size is not: a smaller starter is not a better one, and a bigger one is not worse. Whatever it took for the seat to become genuinely capable at its job is the right starter — 80K tokens or 800K.
Capture the seat as it naturally is at a functional, proven point. Don't pad it with context the seat doesn't use, and — just as important — don't strip context out to make it smaller. Size is an *outcome* of what the seat needed, never a target.
Never compact, summarize, or shrink a seat in order to make or "lean" a starter. There is nothing valuable in "smaller," and compaction is lossy — you would trade away the exact capability the starter exists to preserve. (Compaction is a separate last-resort step for a seat genuinely near its context limit, with its own before/after plan — never part of capturing a starter.)
## State model — 6 states
1. **Captured** — a useful seat/session/context pattern is identified.
2. **Named** — it becomes an Agent Starter with stable id and owner.
3. **Inspectable** — runtime, context inputs, session source, and provenance are visible.
4. **Used** — a rig member or `rig expand` operation starts from it.
5. **Promoted** — evidence shows it is recommended for a role or bundle.
6. **Deprecated** — replaced, stale, unsafe, or incompatible.
## Failure modes (5)
1. **Overclaiming image semantics** — UI/docs imply deterministic VM-style state capture. Say "starter," name what's included, show provenance.
2. **Hidden provenance** — users can't tell what session, context, or spec a starter came from. **Refuse promotion until provenance is inspectable.**
3. **Stale starter** — points at outdated doctrine, missing files, or invalid native session source. **Inspect must report staleness honestly.**
4. **Secret leakage** — starter packages or displays provider auth material. **Refuse.** Refer to session sources and context, never copy credentials.
5. **Runtime mismatch** — starter used with unsupported runtime. **Refuse with a clear error.**
## Manifest shape (v0+v1 shipped)
```yaml
agent_starters:
- id: velocity-reviewer-v1
runtime: claude-code
agent_ref: local:reviewer
context_refs:
- doctrine:advisor-orchestrator-mode-judgment
- convention:workstream-continuity
session_source:
mode: fork
ref:
kind: native_id
value: "<prior-native-session-id>"
```
Member usage:
```yaml
members:
- id: reviewer
starter_ref:
name: velocity-reviewer-v1
```
When a starter points at a primed session produced from a Composable
Priming Pack, record:
- manifest id/version
- runtime
- source session id or transcript path
- ready-check evidence
- freshness state
## Proof matrix
| Surface | Test type | Authority |
|---|---|---|
| Registry schema accepts minimal starter | unit | daemon or config-layer prototype |
| Inspect shows provenance and included context | unit / snapshot | daemon or CLI |
| Member can use `starter_ref` | integration | daemon |
| Unsupported runtime or stale source refuses honestly | unit + integration | daemon |
| No secret material copied into starter artifact | grep / fixture | tester |
| Bundle can include or reference starter | package inspection | bundle layer |
## Dependencies on other primitives
- **Firm**: `session-source-fork` — native conversation-source continuity for fork-based starters
- **Firm**: `specification-system` — declarative starter and member references
- **Soft**: `rig-bundles-and-shareable-artifacts` — shareable starter packaging
- **Soft**: `context-engineering-and-retrieval` — richer declarative context assembly
- **Soft**: `seat-continuity-and-handover` — refresh and swap workflows over starters
## Required-before-RSI
Agent Starters need queryable provenance and honest inspect output before
RSI loops can rely on them for seat refresh. A workflow must be able to
answer: "what starter did this seat use, what source session or context was
included, and is that starter still recommended?"
## See also
- `session-source-fork` skill — low-level fork primitive that makes native session-based starters possible
- `composable-priming-packs` skill — manifest-driven layer for producing primed sessions starters reference
@@ -2,17 +2,22 @@
name: agent-startup-and-context-ingestion
description: Use when designing or auditing how an agent becomes useful after launch — AGENTS.md overlays, role files, skills, rig specs, workflow specs, startup checklists, refocus messages, "rig context" surface. Covers the 4 failure modes that make startup context fail (old rig spec misses current operating mode; current agents never told about new guidance; startup file as dumping ground; orchestrator transmits implementation without preserving product intent).
metadata:
cli_surfaces_referenced:
- context
- whoami
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Cross-runtime restore/reentry packet standard + externalized memory
surfaces convention. Load at agent start; revisit after compaction.
sibling_skills:
- claude-compaction-restore
- mental-model-ha
- scope-recovery
- session-compaction-and-restore
- agent-starters
- composable-priming-packs
- session-source-fork
- seat-continuity-and-handover
transfer_test: pending
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# Agent Startup and Context Ingestion
@@ -43,8 +48,8 @@ is scattered or stale, agents execute the wrong thing very efficiently.
## Don't use this when
- The agent is being created via Agent Starter — the starter's manifest carries startup context
- The work is artifact-backed mental-model rebuild from a packet — that's `claude-compaction-restore`
- The intent is to ship reusable startup content as a skill — write the skill against the agentskills.io specification, not as inline startup prose
- The work is artifact-backed mental-model rebuild from a packet — that's `session-compaction-and-restore`
- The intent is to ship reusable startup content as a skill — that's `writing-skills-for-openrig`
## Failure modes (4)
@@ -67,22 +72,18 @@ When a seat's startup is artifact-backed mental-model rebuild (active-work
reentry case, distinct from reusable Agent Starters / priming packs):
- See the **cross-runtime restore/reentry packet standard v0**
- Source-trust ranking applies: **`rig whoami` > target rigspec > restore map /
current `MISSION_NOTES.md` / owned queue items > touched files > transcript
output**. Transcript output is secondary and may be unavailable or incomplete;
little or no output does not prove the session was quiet.
- Source-trust ranking applies: **`rig whoami` > target rigspec > bounded latest transcript > full transcript > touched-files > `restore-summary.json`**
## Memory surfaces consumed at startup
The primary surfaces a startup ingestion path reads:
Per the externalized-memory-surfaces convention's 13-row inventory:
- AGENTS / role / CULTURE / startup overlays (the per-seat identity layer)
- startup replay context (what the agent did before the current boot)
- restore / reentry packets and Agent Starters (cross-runtime startup path)
- **Row 7** — AGENTS/role/CULTURE/startup overlays (primary)
- **Row 3** — startup replay context (primary)
- **Row 12** — restore/reentry packets and Agent Starters (cross-runtime startup path)
Authority-rank + read-vs-write posture governs which surfaces a
startup-ingestion path can write vs only read; treat overlays as
write-restricted unless your role explicitly authors them.
The umbrella's authority-rank + permission-posture columns govern which
surfaces a startup ingestion path can write vs only read.
## Startup files vs skills (the distinction)
@@ -92,7 +93,7 @@ Per `agent-startup-guide.md` (product reference doc) and the team handbook:
|---|---|
| Rig-specific, role-specific identity | Reusable SOPs / methodology / knowledge |
| Tell agent WHO it is, WHAT it's working on, HOW this team operates | Tell agent HOW to do something (transferable across rigs) |
| Examples: `role.md`, `CULTURE.md`, `startup/context.md` | Examples: `openrig-user`, `test-driven-development`, `dogfood` |
| Examples: `role.md`, `CULTURE.md`, `startup/context.md` | Examples: `openrig-user`, `test-driven-development`, `vault-user` |
| Authored per-rig | Authored once, used everywhere |
Don't put skill content in startup files. Don't put identity content
@@ -101,7 +102,11 @@ culture / pod / member / operator) handles the layering.
## See also
- `mission-slice-sop` skill — the universal operating procedure for working a mission/slice (the canonical PROGRESS/PROOF/MISSION_NOTES/MISSION_BRIEF files); every agent should reach for it at startup, so this general reading contract points at it here (do NOT duplicate the SOP into seat-specific startup files).
- `writing-skills-for-openrig` skill — authoring discipline for skill content (what doesn't belong in startup)
- `forming-an-openrig-mental-model` skill — orientation for new agents
- `claude-compaction-restore` skill — restore-time startup ingestion after compaction
- `seat-continuity-and-handover` skill — packet shape that survives seat resets
- https://agentskills.io/specification — the cross-runtime skill standard (what skill content should and shouldn't be)
- `session-compaction-and-restore` skill — restore-time startup ingestion
- `agent-starters` skill — reusable starter manifests that compose startup context
- `composable-priming-packs` skill — manifests that produce primed sessions
- `externalized-memory-surfaces` skill — umbrella convention for memory surfaces this primitive consumes
- `openrig/docs/reference/agent-startup-guide.md` (product reference doc; not a skill) — the 7-layer additive startup model + delivery hints
@@ -0,0 +1,264 @@
---
name: attention-queue
description: Coordination primitive for OpenRig. Per-agent queue files tracking in-flight work with explicit state transitions + handoff semantics + cross-agent composition. Prevents memory-loss drops; surfaces stalls mechanically; closes the feedback loop on handed-off work. Applied liberally by every agent on every kernel-supervised rig; composed views serve human attention, orch pod-load, rig pending-work.
status: L4-insight
authored-by: advisor-peer-observer@your-rig
date: 2026-04-13
cited-captures:
- improvements-inbox.md 2026-04-13T12:54:50Z — broadcast primitive RSI (same batching-by-theme cluster)
- Mission 4 cmux stall (2026-04-13 midday) — packet-design + queue-for-cross-rig coordination
metadata:
cli_surfaces_referenced:
- chatroom
- send
openrig:
stage: factory-approved
sibling_skills:
- queue-handoff
- workflow-runtime
- watchdog
- alignment-trace
- looping-workflows
- intake-routing
- human-in-the-loop
- dispatching-parallel-agents
- subagent-driven-development
- control-plane-capabilities
- status-not-chat-orchestrator
- control-plane-queue
- control-plane-watchdog
- control-plane-workflows
- control-plane-delivery-loop
- control-plane-rollout-manager
---
# Attention queue
Use this skill when coordinating work that must survive compaction, cross-agent handoffs, or multi-hour stall detection. Applies when you'd otherwise narrate status to chat or rely on memory for pending items.
## Live protocol override
Current live routing protocol:
- **Known target / explicit owner that should wake now**: `rigx queue handoff <destination> "<body>" --type handoff --urgency soon`
- **Passive durable assignment without wake-up**: `rigx queue create <destination> "<body>" --type handoff --urgency soon`
- **Ambiguous or raw intake**: `rigx stream emit "<body>" ...`
- **Direct dialogue / urgent 1:1 conversation**: `rig send ...`
- **Summoned 3+ party roundtable**: `rig chatroom ...`
Do not cargo-cult the earlier "stream everything with `--destination`" prototype shape into the
live control-plane. Stream is now the ambiguous-intake lane, not the universal lane.
## Core shape (minimum-viable discipline)
1. **Author a queue file at** `substrate/shared-docs/rigs/<your-rig>/state/<your-pod>/<your-member>.queue.md`. Same per-pod directory as your session log.
2. **Every known-target hot-potato work handoff** should arrive via `rigx queue handoff`, not via `rig send`. Use `rigx queue create` only when you intentionally want a passive durable item without wake-up.
3. **State transitions** (start → promote; finish → complete; stuck → block; hand off → handoff; completed handed-off work notifies source → handoff-complete) are appended to the entry body with timestamp. Never in-place rewrites.
4. **Cross-rig reads permitted; cross-rig writes forbidden.** Pod-as-authority-boundary doctrine.
### Live command surface note
When the queue control-plane wrapper is installed, treat queue identity as command-resolved, not
seat-name-guessed:
- `rigx queue whoami` resolves the durable queue that belongs to your current seat
- `rigx queue list --mine` shows your queue without guessing from member name
This matters for continuity successors such as `lead2` or `lead5`, which may intentionally share
the canonical `lead.queue.md` file instead of owning a separate `lead2.queue.md` or `lead5.queue.md`.
Known-target direct handoff on the live wrapper:
```bash
rigx queue handoff orch-lead5@your-rig "Need PM shaping on queue attention loop" --type handoff --urgency soon
```
Passive durable write without wake-up:
```bash
rigx queue create orch-lead5@your-rig "Need PM shaping on queue attention loop" --type handoff --urgency soon
```
## Six operations
| Op | Effect |
|---|---|
| append | New entry (state=pending) on inbound request |
| promote | state=in-progress when you start work |
| complete | state=done with optional result |
| block | state=blocked + blocked-on=<id or condition> |
| handoff | state=handed-off + handed-off-to=<target>/<new-id>; send rig-send with `[queue-handoff:]` prefix to target |
| handoff-complete | target signals source that handed-off work finished (closes feedback loop) |
| escalate | walk authority chain when blocked past tier threshold |
| defer / drop | push-to-later or drop-with-rationale |
## When is something a queue handoff?
**Queue handoff** (`rigx queue handoff`):
- Asks a known recipient to do new work
- Transfers ownership of pending work
- Names a deliverable + acceptance criteria
**NOT a queue handoff**:
- Wake-ping `1`
- PSA / broadcast / status update
- Ack / courtesy notification / diagnostic ping / reply to question
- Raw idea or bug where you do not yet know the right owner
If you do not know the correct owner, emit to stream instead of guessing.
## Tier-based ack + notification rules
- **human-gate tier** (gated items; human-watching): mandatory ack on handoff; mandatory notification on completion
- **agent-coordination tier** (standard inter-agent work): recommended ack + notification
- **internal-self tier** (your own to-dos): optional
## Read discipline
- Read your own queue at turn start before picking up new work
- Orchestrators read pod-member queues on wake cadence (`1` ping)
- Advisor-pod reads cross-rig queues for composed views + human-attention
- Past-threshold blocked entries surface during sweeps; execute escalate op if you can't self-unblock
Recommended turn-start queue commands on the live wrapper:
```bash
rigx queue whoami
rigx queue list --mine
```
### Resume-from-idle state sweep
Agents returning from idle-standby (supervisor-wake-only pings; no substantive dispatch during the window) MUST sweep adjacent state before pulling new work. Minimum sweep:
- Supervisor-log tail (~200 lines) at `rigs/kernel/state/supervisor-log.md`
- human-attention.md at `substrate/shared-docs/human-attention.md`
- Any doctrine-decisions added since last-active (`rigs/kernel/state/doctrine-decisions/`)
- Partner queue files at `rigs/kernel/state/<pod>/<peer-member>.queue.md` (peer load-tracking for pairs)
- **Fleet-changes-feed** at `substrate/shared-docs/fleet-changes-feed.md` (pull-native rollout surface; catches any fleet-wide doctrine / skill / convention / operational changes that landed during idle; filter by scope = fleet-wide + your rig/pod)
**Trigger:** first active turn after ≥3 consecutive wake-only cycles OR on peer HA-check request. Sweep before responding to HA-check so the response is grounded in current reality, not stale memory.
**Rationale:** own-queue-at-turn-start catches own-queue drift; adjacent-state drift is a separate failure class that requires its own read discipline. Composable with own-queue sweep (both at same reading point); adds ~2-5 minutes of read time; cheap insurance against peer-driven HA-check round-trips.
**Worked example (genesis):** advisor-co-observer@your-rig after ~2h idle-standing-by on 2026-04-13 — 5-of-7 HA-check items out-of-sync when peer queried. Rule addition would have caught the drift pre-query via adjacent sweep on wake-to-active transition.
## Status-not-chat corollary
Your chat pane is for operational work + ad-hoc human exchanges. Your STATUS lives in queue files + composed views. If you finish work + hit a gate-requiring next-action, do NOT narrate to chat + idle-wait. Queue-handoff to advisor-pod with `tier: human-gate`. The operator doesn't watch agent panes; they watch human-attention.md (composed from human-gate queue entries).
## Composed views (4 layers)
- **Pod-load view** — who's loaded / blocked (orch reads)
- **Rig pending-work** — cross-pod roll-up
- **Fleet cross-rig** — host-wide
- **human-attention** — human-gate-tier items across all queues (advisor-pod composes)
v0: manual regen by orchestrators + advisor-pod.
v0.5: terminal-node watch scripts auto-regen.
v1: generative UI consuming structured queue data.
## Codex-sandbox proxy-write pattern (sanctioned workaround)
Codex members whose sandbox blocks substrate writes can still participate via proxy-write:
- Codex authors content locally (e.g., `/tmp/<rig>-attention-queue/<member>.queue.md`)
- Claude counterpart physically writes to substrate with sha256-verified integrity check
- Subsequent state transitions via `[queue-update: <id> <new-state> <reason>]` rig-send from Codex to Claude-writer
- Authorship preserved; only write-access delegated. Distinct from peer-injection (which is forbidden).
## Escalation mechanics
When entry stays blocked past tier threshold AND agent can't self-unblock:
1. Identify escalation target per authority chain:
- Pod member → pod orchestrator
- Pod orch → rig orch-lead
- Rig orch-lead → kernel orch-lead OR advisor-pod (if human-gate)
- Skip-levels allowed when agent KNOWS correct target
2. Create new entry in escalation-target's queue with `escalated-from: <source-id>`; state=pending; priority elevated
3. Send handoff-shape rig-send: `[queue-escalate: <new-id>] <title> — blocked <Nh> on <reason>`
4. Update own entry: state=escalated; escalated-to=<target>/<new-id>; transitions-log appended
Threshold guidance: 1h human-gate / 4h agent-coordination / 24h internal-self. Rigs may tighten.
## Task-close RSI-check (flywheel trigger)
Every `complete` op on substantive work reflects briefly: "what did we learn? is this worth filing as L2 capture to improvements-inbox?"
Two outcomes; both leave evidence in the transition trail:
- **Novel observation worth filing:** append L2 capture entry to `rigs/kernel/state/improvements-inbox.md` per the v1 queue template (`state: pending` + transition trail started). Transition line in your own queue: `<ts> — RSI-check: filed <capture-id>`.
- **Nothing novel:** transition line in your own queue: `<ts> — RSI-check: none`.
Applies to substantive work-streams. Does NOT apply to:
- Wake-pings (`1`) — not a work-stream
- Trivial status updates — nothing to reflect on
- Pure acks / routing-map updates — no work done
Rationale: task-close is the deterministic interval that makes recursive-self-improvement mechanical rather than ad-hoc. Pattern named in skill-maturity-convention.md §"Task-close RSI-check discipline".
## Push vs pull — when to use rig-send vs queue-write
Not every communication belongs in the receiver's chat pane. The discipline mirrors status-not-chat: most inter-agent signals can flow through queue files (pull) rather than rig-sends (push). Reduces noise; respects receiver's attention cycle.
**Sender's test:** *Does my message need the receiver's attention within their next turn cycle?*
- **Yes → push** via `rig send` (lands in chat; receiver processes on next turn)
- **No → pull** via queue-write (write to own queue OR receiver's queue via handoff; receiver sweeps at cadence)
### Push (rig-send to chat) when:
- Receiver needs info NOW to unblock their work
- Question requires specific answer to proceed
- Handoff is past ack-threshold + tier=human-gate (mandatory-ack window)
- Blocker surfacing (can't self-unblock; need help from target)
- human-gate item needing surface to advisor-pod
- Destructive or time-critical coordination
### Pull (queue-write only) when:
- Status update / adoption signal / cascade-complete ack
- Non-urgent ack (within tier threshold)
- Information that can batch in receiver's curator sweep
- Broadcast-receipt confirmation (receiver's cadence catches it)
- Observed patterns or captures with no time pressure
- Resync material for HA peers (they sweep on resume-from-idle)
### Why this matters
Push-as-default floods the receiver's chat pane with status that could be pulled. Today's rollout volume proved this: during attention-queue + EMM cascades, most acks arrived as push (rig-sends) when they could have been pull (queue-writes). Receiver (advisor-pod) had to process each ping; most were status signals needing no action.
Pull-over-push is the queue primitive's whole point. Status lives in queue files; readers sweep at cadence; only genuine unblockers + gate-surfaces push to chat.
### Worked example
orch-lead@your-rig ack'd attention-queue cascade:
- **Push version (what happened):** `rig send advisor-peer-observer@your-rig "[queue-handoff-ack: ...] ... cascaded to 8 pod members ..."` → lands in my chat; I read immediately; process the status
- **Pull version (what should happen):** write ack-receipt to `rigs/openrig-build/state/orch/lead.queue.md` as state-transition on their adoption entry; I sweep their queue on my curator cadence; pick up the ack without chat-ping
Ack-receipts for status are pull-native. Handoff-complete notifications for human-gate items stay push (they close feedback loops on time-sensitive work).
### Corollary — orchestrator-to-advisor cadence
Orchestrators writing to their own queue files lets advisor-pod read without being interrupted. The curator-sweep pattern (advisor reads pod queues on their cadence) is the canonical pull mechanism. Push only when time-matters.
## Anti-patterns (don't do these)
- **Chat-as-status** — narrating status/gates to your chat pane + idle-waiting. Use queue + human-attention instead.
- **Duplicate-storage** — writing the same fact in queue + session-log + chat + mission-control. Queue is authoritative for in-flight state.
- **Peer-injection** — writing directly to another agent's queue without their authorship. Only handoff op moves work cross-queue.
- **Silent drops** — don't leave items in pending forever without state transitions. defer or drop with rationale.
- **Global queue** — don't try to make one queue for everyone. Per-agent primary; compose for views.
## Maturity status
**L4-insight** per skill-maturity-convention. Applied liberally across the host; evolving via observation. Feedback loop: RSI filings reshape this skill; demotion valid if convention reveals wrong shape; promotion to L5-canon requires architect+reviewer pair-review per HOST-TOPOLOGY §7 SOP.
Rollout date: 2026-04-13 host-wide adoption. 48h observation cycle active; RSI with learnings due ~2026-04-15.
## Related
- Spec (full reference): the internal attention-queue spec
- Skill-maturity convention: `substrate/shared-docs/skill-maturity-convention.md`
- Config-wrapper-code loop doctrine: `config-wrapper-code-loop` skill
- HOST-TOPOLOGY §4 context-sharing patterns — attention queue is a new pattern here
- SUBSTRATE-CONVENTIONS §7 HA session logs — queue lives in same per-pod directory
@@ -0,0 +1,190 @@
---
name: cross-host-rig-commands
description: Use when issuing `rig` commands against a remote host via `--host <id>` flag (single-hop SSH to a host declared in `~/.openrig/hosts.yaml`). Covers the 4 structured failure modes (ssh-unreachable / permission-gate / remote-daemon-unreachable / remote-command-failed), the `--verify` honest pass-through (SSH success is NOT verify success), and the host-registry shape. v0 supports `rig send / capture / ps / whoami --host <id>`.
metadata:
cli_surfaces_referenced:
- capture
- daemon start
- host list
- host show
- ps
- send
- whoami
openrig:
stage: factory-approved
sibling_skills:
- rig-lifecycle
- topology-mutation-and-seat-management
- seat-scaling-and-specialization
- sidecar-operator
- rig-bundles-and-shareable-artifacts
- specification-system
- extension-and-user-workspace
---
# Cross-Host Rig Commands
A first-class OpenRig surface for issuing `rig` commands against a
remote host via single-hop SSH. v0 productizes the existing SSH-envelope
operator pattern (`ssh <host> rig <cmd>`) with declared host identity,
explicit cross-host invocation path, preserved `--verify` semantics, and
4 named failure modes.
**Current-host note (2026-07-14):** this skill still preserves the original
SSH-v0 doctrine below, but the live host registry may also contain HTTP
read-through/tunnel entries such as `your-vm` and `your-other-vm`. Use the
host registry entry as ground truth for transport shape, and use
`conventions/multi-host-naming/README.md` for host-id naming. HTTP entries
require `url` plus exactly one of `bearer_file` or `bearer_env`.
**v0 is CLI-side shell-out only — `packages/daemon/` is NOT touched.**
The remote host has its own managed `rig` available on `$PATH`.
## Use this when
- Driving a Tart VM from the host (the immediate cross-host consumer)
- Operating Mac host A against Mac host B
- Reading remote state via `rig ps --host` / `rig whoami --host`
- Sending or capturing on a remote rig session (`rig send/capture --host <id>`)
- Authoring a `~/.openrig/hosts.yaml` registry entry
## Don't use this when
- The target is local. Don't pass `--host` for local commands.
- You need multi-hop SSH (host A → host B → host C). v0 is single-hop only.
- You want reverse direction (remote initiates back to local). v0 is originator-pull only.
- Cross-host **seat handover** (moving a durable owned seat across hosts) — deferred to higher-level primitives. (Cross-host **queue writes**, by contrast, now ship — see "Cross-host queue writes" below.)
- The transport isn't SSH. v0 supports `transport: ssh` only.
## Cross-host queue writes (updated 2026-07-21 vs main d37a08ad)
Cross-host **queue writes** are no longer deferred — they ship — but the rule
differs from the interactive verbs (`send`/`capture`/`ps`/`whoami`):
- **Queue writes are EXPLICIT-only.** Address the target host explicitly with
`--host <id>` or the `member@rig@<host>` form. A queue write **never** follows a
persisted host selection.
- **`host select` stickiness does NOT apply to queue.** `host select` affects the
`resolveEffectiveHost` verbs (`send`/`capture`/`ps`/`whoami`) — those follow the
selected host — but a queue write ignores it and requires explicit addressing.
- **Host address parsing differs** between the interactive verbs and the queue
verbs; do not assume the interactive form carries over. When unsure, address the
host explicitly.
## Host registry shape (`~/.openrig/hosts.yaml`)
Host ids should follow the OpenRig-work multi-host naming convention:
`conventions/multi-host-naming/README.md`. In this environment that means
physical hosts such as `your-vm`, local OpenRig development VMs such as
`your-vm`, persistent product VMs such as `your-other-vm`, and VPS hosts such
as `your-vps`. Keep old aliases during migration until no live routing
depends on them.
```yaml
hosts:
- id: a-test-vm
transport: ssh # v0 supports "ssh" only
target: a-test-vm.local # DNS name, SSH config alias, or IP
user: wrandom # optional
notes: "Tart VM" # optional
- id: laptop-b
transport: ssh
target: laptop-b.tail-scale-net
user: wrandom
```
Validation rules:
- `hosts` required, non-null array
- Each entry: `id` required (non-empty, unique), `transport` required (`ssh` only), `target` required
- `user` and `notes` optional
- Operator-managed file; v0 does NOT include any sub-command to add/remove/list hosts (operators edit YAML directly)
- Missing or invalid file returns a clear error pointing at the canonical path
## CLI surface (v0 shipped)
```bash
rig send <session> "msg" --host <id> --verify
rig capture <session> --host <id>
rig ps --host <id> [--nodes] [...]
rig whoami --host <id>
```
Forwards every shaping flag (`--nodes`, `--full`, `--limit`, `--fields`,
`--summary`, `--filter`, `--json`) to the remote `rig` invocation. The
remote rig's output is verbatim passthrough on success.
## The 4 structured failure modes (load-bearing API contract)
The CLI distinguishes 4 failure modes; operators get an actionable error
per mode; JSON output preserves the `failedStep` enum:
| Mode | Cause | Action |
|---|---|---|
| `ssh-unreachable` | SSH itself failed (connection refused, host key mismatch, DNS failure, timeout) | Verify SSH access and the registry entry |
| `permission-gate` | SSH hit auth/permission gate (Permission denied, Keychain) | Error includes hint to keychain-over-SSH field note (L4-3 D6) |
| `remote-daemon-unreachable` | SSH succeeded but remote `rig` reported the remote daemon was not reachable | `ssh <target> rig daemon start` |
| `remote-command-failed` | SSH succeeded but remote `rig` exited non-zero for some other reason; remote stderr is surfaced | Read remote stderr; debug remote command |
Each is distinct and routable. Don't conflate them.
## `--verify` honest pass-through (load-bearing)
`--verify` against a remote target must:
- **Propagate** the verification request to the remote daemon (or remote `rig` invocation that talks to it)
- **Bring back a structured verification result** (true/false + reason if false), NOT just SSH exit code 0
- **Distinguish "SSH succeeded but verify returned false" from "SSH itself failed"** — these are different operator actions
**SSH success is NOT verify success.** The remote rig is authoritative
on `--verify`; its `Verified: yes/no` line is surfaced verbatim. Verified
at 3 layers (executor unit, command integration, source impl).
## Hard boundaries (do-not list)
- **Do NOT collapse `--verify` honest result into SSH exit code.** Operators and agents rely on the distinction.
- **Do NOT silently retry SSH failures inside the primitive.** Surface them; let the caller decide.
- **Do NOT introduce non-SSH transports in v0.** Goal is productizing the existing shipped pattern, not replacing it.
- **Do NOT touch host-side daemon code as part of v0.** Cross-host shape is on the originator side.
## Cross-host annotation
Every cross-host invocation is observable as cross-host:
- **Operator output**: `[via host=<id> (<target>)]` annotation
- **JSON output**: `cross_host: { host, target }` field
Annotation is PRESENT when `--host` is set and ABSENT otherwise
(compat regression).
## Currently shipped (v0) vs deferred
Shipped at openrig `cdce3a6` (2026-04-30):
- `--host <id>` flag on `rig send / capture / ps / whoami` (initial 2 commands; promoted to 4 at `6b7043a` same day)
- Read-only host registry validation
- Single-hop SSH executor with 4-mode `failedStep` enum
- `--verify` honest pass-through
- Cross-host annotation (operator + JSON)
- Daemon untouched
Deferred:
- Tier 2 real-runtime cross-host proof (disposable Tart VM cycle)
- `rig host list / show` read-only sub-namespace (only if host count grows past comfortable manual editing)
- Non-SSH transports
- Multi-hop SSH
- Reverse direction (remote initiates)
- Connection pooling/caching
## See also
- `seat-continuity-and-handover` skill — host-aware seat-binding semantics for cross-host handover (deferred to v1 on top of this v0 baseline)
- `openrig-user` skill — the local CLI surface that cross-host commands wrap
## Sender identity is ASYMMETRIC (verified vs current main, 2026-07-25)
The `@host` sugar is **target-addressing only**, not sender-identity. A cross-host
message's **From:** is `member@rig` — the sender carries **NO `@host` suffix**. The target
supports `member@rig@<host>` for addressing; the sender does not reflect its own host in
`From:`. **Do NOT teach or expect a host-qualified `from`** (in openrig-user / operator send
docs or anywhere) until that core gap is fixed. (pm@your-rig verified this against
current main, 2026-07-25 — a known asymmetry, not a doc error to paper over.)
@@ -0,0 +1,104 @@
---
name: human-in-the-loop
description: Use when classifying a slice closeout (auto-continue / human gate / park), routing a real decision to a human, or designing a human queue/dashboard surface. Treats humans as durable network participants with attention surfaces, queues, and decision records — escalation lands as a durable attention item, not a chat message. Approval is NOT required for every clean closeout; the default RSI conveyor continues unless an explicit human gate is reached.
metadata:
openrig:
stage: factory-approved
sibling_skills:
- queue-handoff
- workflow-runtime
- watchdog
- alignment-trace
- looping-workflows
- intake-routing
- attention-queue
- dispatching-parallel-agents
- subagent-driven-development
- control-plane-capabilities
- status-not-chat-orchestrator
- control-plane-queue
- control-plane-watchdog
- control-plane-workflows
- control-plane-delivery-loop
- control-plane-rollout-manager
---
# Human In The Loop
The primitive that treats humans as **durable network participants** —
attention surfaces, queues, decision records, routing semantics — not
as ad-hoc chat receivers.
**Autonomy is not the absence of humans; it is knowing when human
judgment is needed and making that handoff crisp.**
## Use this when
- A slice closeout needs classifying: auto-continue, human gate, or park
- A real decision needs to land in front of a human (usage limits, provider auth, roadmap tradeoff, product-intent ambiguity)
- Designing a human queue/dashboard surface
- Returning a hot potato to orchestration after human approval
## Don't use this when
- The slice closeout is clean and `PROGRESS.md` already names the next safe slice. **Default RSI conveyor continues; do NOT manufacture a human gate.**
- The escalation is just a status update. Humans are participants for *decisions*, not narration.
- The next owner is another agent. Use queue-handoff, not human-in-the-loop.
## The 3-class closeout classification
In a productized daemon-backed version, closeout classifies the next
step BEFORE touching the human queue:
| Class | When | Action |
|---|---|---|
| **auto-continue** | Slice closes cleanly, next named slice in workstream plan | Mark closed; create next-owner qitem from plan |
| **human gate** | Genuine decision needed (usage limits, provider auth, product-intent ambiguity, roadmap tradeoff) | Create human queue item with proof + decision text + recommended default + action outcomes |
| **park** | Intentionally stop the conveyor (e.g., waiting on external) | Stop with reason + resumption path |
## Failure modes (5)
1. **Human decision needed, but the rig only mentions it in chat.** Decisions belong as durable attention items, not chat messages.
2. **Human queue item lacks enough plain-English context for a decision.** Include proof + decision text + recommended default + action outcomes.
3. **Human response updates a file but does not wake the next owner.** Approval should return the hot potato; feedback should create the next durable qitem.
4. **The dashboard shows too much raw rig state and hides the actual decision queue.** Decision queue is the primary surface; rig state is secondary.
5. **A clean closeout is parked on the human even though `PROGRESS.md` already names the next safe slice.** Don't manufacture human gates.
## Proof standard (both paths)
A trustworthy human-in-the-loop system proves both directions:
- **Blocking gate path**: real item routed to human → human decision recorded through UI → resulting hot-potato handoff wakes correct next owner
- **Non-blocking closeout path**: proof inspectable by human, but orchestrator continues to next named slice without manufacturing a human gate
A primitive that only wakes humans is not trustworthy. It must also know when NOT to.
## Product shape (SHIPPED — Mission Control, PL-005)
This surface has shipped as **Mission Control** (product UI, `/mission-control`
route; actions via `POST /api/mission-control/action`). The seven verbs the
human acts with:
- **approve** (returns the hot potato to orchestration or the chosen owner)
- **deny** (reject the item)
- **route** (send to a different owner)
- **annotate** (add context without action)
- **hold** (intentional pause with reason)
- **drop** (mark not-actionable)
- **handoff** (hand to a specific next owner — creates the next durable qitem)
**Approval returns the hot potato to orchestration or the chosen owner;
feedback creates the next durable qitem rather than only mutating the source
queue file** — enforced by the shipped verbs (handoff/route create qitems).
See `docs/as-built/architecture/mission-control.md`.
## Long-term shape
Likely needs **multiple humans with different scopes**, not a singleton
human attention feed. Different humans own different decision
domains; queue items route by scope.
## See also
- `queue-handoff` skill — durable handoff via queue items; human-in-the-loop is the human-side complement
- `watchdog` skill — when to wake (humans included) vs no-op
- `looping-workflows` (convention) — the looping-workflows convention covers loop closeouts; human-in-the-loop is the escape hatch
@@ -1,115 +0,0 @@
---
name: mission-slice-sop
description: "Use when working a mission or slice: the SDLC flow (intent -> mini-requirements + proof contract -> mockups -> plan-lock -> build -> QA -> `rig proof` drops -> proof-lock), and how to track, prove, and hand off state across agents and compaction via PROGRESS.md / PROOF.md / MISSION_NOTES.md. Covers the two locks, role contracts, hot-potato queue handoff, and the `rig scope audit` backstop."
metadata:
openrig:
stage: shipped
last_verified: "2026-07-06"
distribution_scope: product-bound
source_evidence: |
The canonical product SDLC skill: it teaches the full SDLC flow the
Living Notes UI projects — the convention sections, the proof-contract
pairing, the two staged-approval locks, C1 proof drops, and the three
role contracts. Conventions SSOT: docs/reference/sdlc-conventions.md
in the repo; on an installed package the daemon materializes the same
document at $OPENRIG_HOME/reference/sdlc-conventions.md (default
~/.openrig/reference/sdlc-conventions.md). The deterministic backstop
is the `rig scope audit` classifier.
sibling_skills:
- queue-handoff
- seat-continuity-and-handover
- claude-compaction-restore
---
# Mission/Slice SOP — how you work a mission & slice
Use this skill to actually **do** mission/slice work the way OpenRig expects: author the convention sections, track on the canonical files, prove on them, hand off through them, and survive compaction on them. **Do the work described here; do not merely explain the protocol.** The deterministic backstop is `rig scope audit` — the audit classifier is the source of truth for adherence. The conventions themselves live in ONE document: **`docs/reference/sdlc-conventions.md`** in the repo, materialized by the daemon at **`$OPENRIG_HOME/reference/sdlc-conventions.md`** (default `~/.openrig/reference/sdlc-conventions.md`) on an installed package — this skill teaches the flow; the SSOT defines the formats.
## The SDLC flow (intent → proof)
```
intent → mini-requirements + proof contract → (UI slices: mockups)
→ plan-lock (rig scope slice approve --scope spec)
→ build the LOCKED set
→ QA: mockup ↔ delivered VISUAL compare
→ proof drops (rig proof add <slice> …)
→ proof-lock (rig scope slice approve --scope delivery)
```
1. **Record intent** verbatim in the slice's `## Intent` section (`rig scope slice create` scaffolds it — every template kind).
2. **Author the mini-requirements + proof contract**: `## Mini-requirements` is the concise one-glance tier (approval starts there); `## Proof contract` is a checkbox list of promised deliverables, each written as an observable outcome. UI deliverables name their planned mockup. The IMPLEMENTATION-PRD opens with the mini-requirements; everything between intent and proof is **elastic** — for a small slice the mini-requirements may BE the whole PRD.
3. **Plan-lock**: `rig scope slice approve <slice> --scope spec` — "the PRD matches the intent; THIS artifact set is what gets built." One daemon-side write: frontmatter stamp + append-only audit row.
4. **Build the locked set** — look at the mockups, not just the spec text.
5. **QA visual compare**: for each deliverable, load the planned mockup, produce the real artifact in a test/demo environment, visually compare, and record the verdict.
6. **Drop proof**: `rig proof add <slice> --artifact-type qa --verdict PASS --candidate-sha <tip> --money-evidence "…" --evidences "1,3" --media "walk.webm,panel.png" --self-check "…"` — the C1 header's closed sets validate at drop time; `--evidences` joins the drop to its proof-contract items and `--media` names the curated proof/-relative media the drop stands behind (that pairing + media set is what the UI's DELIVERED section renders).
7. **Proof-lock**: `rig scope slice approve <slice> --scope delivery` — the terminal sign-off. Approval is freeze/sign-off, **never** proven-green: proven-green requires the recorded C1 verdicts.
## The three role contracts
- **Planning agent:** authors intent + mini-requirements + the proof contract; produces mockups for UI deliverables and attaches them to the locked set (a UI slice with no mockup is an incomplete plan; non-UI slices have none — not a gate); locks the plan.
- **Build agent:** builds against the LOCKED set only; looks at the mockups.
- **QA agent (owns the compare):** visually compares planned vs delivered per deliverable, records verdict + note via proof drops, and **curates** the canonical proof set (bounded, mapped to deliverables; the fix-loop pile stays in `proof/`, one drill-in down). On mismatch: fix-and-re-review or kick back with the reason — never escalate a raw mismatch to the human.
## The canonical files (the operating surface)
> The canonical files below are the **operating surface of the work** — you track on them, prove on them, hand off through them, and survive compaction on them. They are NOT side-artifacts to "maintain"; keeping them current *is* the work.
- **README.md** (mission + slice) — the overview, OPENING with the convention sections (`## Intent` / `## Mini-requirements` / `## Proof contract`). The **mission README carries this SOP at its bottom.**
- **IMPLEMENTATION-PRD.md** — the full PRD; opens with the mini-requirements; the `## Proof contract` here is what the UI's DELIVERED pairing joins proof against.
- **PROGRESS.md** — the live delivery state. One line per outcome; links down for detail.
- **MISSION_NOTES.md** — the accruing handoff + tribal-knowledge doc. Blank-slate onboarding + **compaction-restore** read it. `§1` top-of-mind + per-seat `§A–§X`.
- **MISSION_BRIEF.md** — the steering doc (the UI "Steering" tab). The 7-section schema.
- **PROOF.md** (+ `proof/`) — acceptance evidence. **A slice is not done until every proof-contract item has evidence.**
## Per-file rules — WHO / WHEN / HOW
### PROGRESS.md
- **WHO:** the orchestrator owns `§1` (current state); every agent logs its own outcomes.
- **WHEN:** after every slice-done **AND every commit**; on any material state change.
- **HOW:** one line per outcome (checkbox), link down for detail (workstream-continuity format); keep frontmatter `stage`/`verified` honest.
### PROOF.md + proof/
- **WHO:** the impl/QA pair that worked the slice.
- **WHEN:** a slice is **NOT "done"** until every proof-contract item has evidence.
- **HOW:** proof maps **1:1 to the proof contract's deliverables** — put media under `proof/`, then ATTACH it with `rig proof add <slice> … --evidences <item> --media <files>` (the drop writes the C1 header the DELIVERED pairing joins on) + a line in PROOF.md stating what it proves. **Hand-placing files in `proof/` without a drop is the anti-pattern** — the deliverable stays unpaired and `unverified`. No proof → not done.
### MISSION_NOTES.md
- **WHO:** any agent updates `§1` (top-of-mind); each seat owns + appends to its own `§A–§X` section.
- **WHEN:** on any material change; a compacting agent **files its state here BEFORE compaction and reads it on restore.**
- **HOW:** accruing tribal knowledge — `§1` ≤ 5–15 lines (gates, open decisions, surprises); per-seat continuation entries (latest = truth; other seats read-only). Pointer-first; don't duplicate.
### MISSION_BRIEF.md
- **WHO:** product/design (steering owner).
- **WHEN:** when steering changes.
- **HOW:** the 7-section steering schema (the UI "Steering" tab reads it).
### README.md
- **WHO:** the author at creation; refreshed on rescope.
- **WHEN:** at mission/slice creation + when scope/theme changes.
- **HOW:** overview + honest frontmatter (`id`/`stage`/`verified`) + the convention sections up top; the mission README carries this SOP at its bottom.
## The lifecycle (4 legs)
**SCAFFOLD** (`rig scope` creates the files from templates — every slice kind emits the convention sections + `proof/` + the IMPLEMENTATION-PRD skeleton) → **POPULATE** (agents fill them as work happens, per the rules above) → **PROJECT** (the Living Notes UI reads them into INTENT → PLAN → DELIVERED) → **VERIFY** (`rig scope audit` checks adherence). "Loose freeform write + deterministic verify."
## Hot-potato (handoffs)
End every turn by passing the ball — a `rig queue` handoff to the next agent (close the qitem with a `closure_reason`). The **durable ball-pass is the queue close, not a chat message.** Never go idle without a handoff.
## Verify (deterministic backstop)
Run `rig scope audit` at slice-close. It flags: committed-without-touching-PROGRESS; slice-marked-done-without-PROOF; active-mission-without-MISSION_NOTES; MISSION_BRIEF off-schema; proof artifacts violating the C1 header; missing IMPLEMENTATION-PRD on a building slice; missing convention sections (`## Intent`, a well-formed `## Proof contract`, the UI-slice mockup ref). Every convention check is **advisory / fail-open** — it records and advises, never blocks a write. **Fix the flag, don't suppress it.**
## Reading terminal captures — KNOWN GOTCHA: ghost-text autocomplete is NOT real
When you `rig capture` a pane, **greyed / ghost autocomplete suggestions are NOT real content** — they are autocomplete *previews* (shell autosuggestion, the input-box ghost-text completion), not typed, staged, or committed input. **This is known, expected, and has been faking agents out a lot** — reading a ghost suggestion in a peer's input box as "staged text they're about to send," or as a real prompt, and then reasoning/acting on a string that was never actually there.
**Rule:** ignore ghost/autosuggest text entirely. Only *committed/rendered* pane output is real. If a `❯` input line shows text, treat it as an autocomplete artifact unless you have independent evidence it was actually entered. Do not build decisions (or worry about "colliding with staged text") on ghost text. When it matters, verify at source (git, the queue, the actual event) — never off a capture's ghost line.
## Moment-of-truth checklist
- **Starting a slice?** → intent recorded verbatim? mini-requirements + proof contract authored? mockups attached (UI slices)? plan locked (`--scope spec`)?
- **Finishing a slice?** → every proof-contract item has curated evidence via `rig proof add … --evidences --media` (C1 drops — never only hand-placed files)? PROGRESS updated? MISSION_NOTES `§1` refreshed? proof locked (`--scope delivery`)? Handed off via queue?
- **Committing?** → PROGRESS updated?
- **Compacting?** → filed your state in MISSION_NOTES?
- **Starting on a mission?** → read the mission README (incl. this SOP) + MISSION_NOTES + the conventions SSOT (`docs/reference/sdlc-conventions.md` in the repo, `$OPENRIG_HOME/reference/sdlc-conventions.md` on an installed package)?
@@ -1,18 +1,28 @@
---
name: openrig-architect
description: Use when designing multi-agent topologies that run ON OpenRig — authoring RigSpec and AgentSpec files for new rigs, creating agent startup content (guidance / skills / culture), or diagnosing why a launched rig's agents aren't behaving as intended. NOT for changing OpenRig itself (work in the openrig product repo); NOT for ordinary CLI operation of an existing rig (use openrig-user). Covers the full authoring lifecycle from user intent to validated, launchable rig.
description: Use when designing multi-agent topologies that run ON OpenRig — authoring RigSpec and AgentSpec files for new rigs, creating agent startup content (guidance / skills / culture), or diagnosing why a launched rig's agents aren't behaving as intended. NOT for changing OpenRig itself (use openrig-builder); NOT for ordinary CLI operation of an existing rig (use openrig-user). Covers the full authoring lifecycle from user intent to validated, launchable rig.
metadata:
cli_surfaces_referenced:
- agent validate
- capture
- daemon start
- ps
- send
- spec validate
- specs ls
- up
- whoami
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Bootstrap skill — NPM install lands this in personal homes (~/.claude/skills/, ~/.agents/skills/) for users authoring their own rigs.
sibling_skills:
- openrig-user
- openrig-operator
- openrig-builder
- openrig-upgrade
- forming-an-openrig-mental-model
transfer_test: pending
- ai-dev-workflows
notes: |
Description was already correct (starts with "Use when..."; lists specific authoring triggers including the diagnose-bad-rig case). Final sentence ("Covers the full authoring lifecycle from user intent to validated, launchable rig.") is workflow-summary-adjacent; on next iteration, consider trimming. For factory-adoption cycle, kept as-is to match product source-of-truth.
---
# OpenRig Architect
@@ -47,8 +57,13 @@ Load these before starting any design work. The quality of your output depends o
**Read if present on this host:**
4. **Host-level doctrine file** (if your team maintains one — e.g., a HOST-TOPOLOGY doc that defines canonical rig classes, context-sharing patterns, and authoring SOPs for high-stakes rigs). If present, it supersedes the baseline process below for complex or high-stakes rigs (≥4 members, HA, managed-app, or shared/copied). Solo operators and small/focused rigs use the baseline below directly.
5. **Agent-facing software design principles** if your rig ships a new CLI, service, or managed app that agents will operate. Treat the operating surface as a context-engineering problem: every error message and help text gives the agent information to act on.
4. **Host-level doctrine** in your host's topology doc, if it keeps one. If this file exists, it supersedes the baseline process below for complex or high-stakes rigs. Specifically:
- §3 defines the canonical rig classes (kernel, project, ephemeral, infra-build, managed-app). Classify before designing.
- §4 defines context-sharing patterns (pods as context domains, pair pattern, HA via mental-model-ha skill + substrate session logs, terminal nodes as common-room, chatroom/substrate/transcripts/Corpus).
- **§7 is the canonical 12-step rig-spec authoring SOP for high-stakes rigs — use it instead of the baseline "Design Process" below when the rig is ≥4 members, uses HA, is a managed-app, or will be shared/copied.** The baseline below still applies to small/focused rigs.
- §10 contains the host's bootstrap sequence so you know where your new rig fits.
- §12 has the naming canon and vocabulary mapping to shipped terms.
5. **`building-agent-software` skill** if available in your skill catalog. Design principles for agent-facing tools and surfaces. Relevant when your rig ships a new CLI, service, or managed app.
**Load as needed:**
- Domain-specific skills when designing specialist agents — find shipped skills inside the OpenRig installation under the `specs/agents/` tree
@@ -218,10 +233,9 @@ For rigs that reuse builtin agents, the agents directory is often unnecessary
4. **Write role guidance** for each custom agent — who they are, what they do
5. **Write startup context** for agents that need environment grounding
6. **Validate:** `rig spec validate rig.yaml` and `rig agent validate agents/*/agent.yaml`
7. **Audit authoring completeness:** `rig spec audit rig.yaml` — advisory findings identify missing culture or startup context without blocking launch.
8. **Confirm the runtime cwd** — do not assume agents should work from the directory where the rig spec is stored. The spec root controls file resolution; the runtime cwd controls trust, project guidance, permissions, and repo context.
9. **Launch:** `rig up rig.yaml --cwd /path/to/project`
10. **Verify:** `rig ps --nodes` — all agents ready? Check `rig capture` on each agent.
7. **Confirm the runtime cwd** — do not assume agents should work from the directory where the rig spec is stored. The spec root controls file resolution; the runtime cwd controls trust, project guidance, permissions, and repo context.
8. **Launch:** `rig up rig.yaml --cwd /path/to/project`
9. **Verify:** `rig ps --nodes` — all agents ready? Check `rig capture` on each agent.
### Validation Is Non-Negotiable
@@ -229,10 +243,11 @@ Always validate before launching:
```bash
rig spec validate rig.yaml
rig spec audit rig.yaml
rig agent validate agents/my-agent/agent.yaml
```
Then run `rig spec audit rig.yaml` for advisory checks such as stale seat references and other cross-file drift that schema validation cannot detect.
If validation fails, fix the errors. Do not try to launch an invalid spec — it will fail with a less helpful error.
## Diagnosis: When Things Go Wrong
@@ -9,11 +9,6 @@ description: >
metadata:
openrig:
stage: candidate
distribution_scope: product-bound
source_evidence: |
cmux is OpenRig's shipped terminal provider generalized onto `rig terminal <provider>` —
best-effort, not proof-gated. Authored clean-room.
transfer_test: pending
sibling_skills:
- openrig-herdr
- openrig-user
@@ -10,11 +10,6 @@ description: >
metadata:
openrig:
stage: candidate
distribution_scope: product-bound
source_evidence: |
Empirical herdr 0.7.1 hands-on findings + the ratified implementation PRD. Authored
clean-room (patterns only, no herdr source text; AGPL arm's-length).
transfer_test: pending
sibling_skills:
- openrig-cmux
- openrig-user
@@ -51,7 +46,7 @@ An agent asked "open all my rigs plus a mission as views" runs one `open` per ta
```bash
rig terminal open acme-web # a whole rig, live agents as tiles
rig terminal open mission:site-relaunch # exactly the agents working the mission
rig terminal open slice:02-search-filters # the agents working one slice
rig terminal open slice:search-filters # the agents working one slice
```
No hand-listing of seats: the mission/slice membership is derived from live topology at open time.
@@ -1,142 +0,0 @@
---
name: openrig-installer
description: Use when installing or upgrading OpenRig on a host, especially the V0.3.1 upgrade flow which includes the substrate-kernel → daemon-managed-kernel migration ceremony. Covers npm install, rig setup, rig daemon start (auto-boots kernel), and the canonical verification commands. NOT for ordinary kernel operation post-install — use openrig-operator skill for that.
metadata:
openrig:
maturity: L2
distribution_scope: shipped
source_evidence: V0.3.1 slice 05-kernel-rig-as-default IMPLEMENTATION-PRD §8 + OQ-A=B migration-ceremony decision
---
# OpenRig Installer
This skill teaches the operator agent how to install + upgrade
OpenRig cleanly. The V0.3.1 upgrade is the one with the migration
ceremony (substrate kernel → daemon-managed kernel); other upgrades
follow the same install / setup / start shape with no migration.
## Fresh install
```bash
npm install -g @openrig/cli
rig setup
```
`rig setup` is idempotent — safe to re-run if a step fails. It probes
host prereqs (tmux present, Node version, writable state path,
optional cmux), then invokes `rig daemon start` per the L2 factoring
(OQ-B). The daemon's start path auto-boots the kernel rig per the
V0.3.1 slice 05 kernel-rig-as-default logic.
## Verification after install
```bash
rig ps --nodes --rig kernel --json
```
Should report 4 members (advisor.lead + operator.agent +
operator.human + queue.worker) all ready. If a runtime is unavailable
the daemon picks the matching variant (`rig-claude-only.yaml` or
`rig-codex-only.yaml`); the topology stays the same shape with the
unavailable runtime omitted from the agent membership.
Entry point for chatting with the rig:
```bash
rig capture advisor-lead@kernel
```
Or click the CMUX button on the topology graph in the UI at
`/topology`.
## V0.3.1 upgrade ceremony (one-time migration)
Operators with a kernel spec stored outside the daemon-managed
location (any pre-V0.3.1 layout, typically wherever you kept your
own `rigs/kernel/` directory) must migrate to
`~/.openrig/specs/rigs/kernel/` as a one-time step during the V0.3.1
upgrade. The V0.3.1 upgrade IS the migration moment; it's not a
separate ceremony.
### Migration steps
1. **Snapshot first.** Take a snapshot of the running substrate
kernel so the migration is reversible:
```bash
rig snapshot kernel
```
2. **Stop the substrate kernel** (so the migration doesn't race a
running rig):
```bash
rig down kernel --snapshot
```
3. **Copy your existing kernel spec** into the daemon-managed
location:
```bash
mkdir -p ~/.openrig/specs/rigs/kernel
cp -r /path/to/old/kernel-spec/* ~/.openrig/specs/rigs/kernel/
```
4. **Upgrade the CLI + daemon**:
```bash
npm install -g @openrig/[email protected]
rig daemon stop
rig daemon start
```
At this point the new daemon detects `~/.openrig/specs/rigs/kernel.yaml`
exists and skips the V0.3.1 builtin-kernel boot (the
already-managed-rig branch). The substrate-rooted topology
continues to run under daemon management.
5. **Verify** the migrated kernel matches expectations:
```bash
rig ps --nodes --rig kernel --json
```
6. **Decommission the old copy** (only after verifying the
daemon-managed copy works):
```bash
rm -rf /path/to/old/kernel-spec
```
### If migration fails
The pre-step snapshot is the rollback. `rig restore <snapshot-id>
--rig kernel` revives the prior topology. Then `npm install -g
@openrig/cli@0.3.0` rolls the CLI back and you can retry later.
## Operator agent's role in install + upgrade
The operator agent shepherds operators through these steps when the
user asks "how do I upgrade?" or "what's the V0.3.1 ceremony?". The
agent reads this skill on demand via `find-skills` — it does not
need to memorize the steps; it consults the canonical reference
(this file) and walks the operator through.
## 3-part error remediation
| What failed | Why it matters | Fix |
|---|---|---|
| `npm install -g @openrig/cli` permission denied | Global install needs writable npm prefix; macOS Homebrew default is usually writable; some custom Node installs aren't | Either fix the npm prefix permissions or use `sudo npm install -g`; check `npm config get prefix` |
| `rig setup` host prereq fail | tmux, Node version, or writable state path missing | `rig doctor` lists each missing piece + the install command; run those, retry `rig setup` |
| `rig daemon start` auth-block error | Neither Claude Code nor Codex authenticated; kernel rig requires at least one | Run `claude auth login` OR `codex login`; then retry `rig daemon start` |
| `rig daemon start` "kernel already managed" | An existing managed rig named `kernel` exists; the daemon skips builtin-boot per design | This is the expected path after migration — no action needed |
| `rig ps --rig kernel --json` returns empty | Daemon healthy but no kernel rig managed; likely the migration step copied content but did not boot | `rig up kernel` from inside `~/.openrig/specs/rigs/kernel/`; or invoke the daemon's cold-boot path explicitly |
## What this skill is NOT
- Not the canonical OpenRig command surface; that lives in the
`openrig-user` skill.
- Not the kernel-operating-procedure for post-install daily use;
that's `openrig-operator`.
- Not for project rigs; project rigs install themselves via `rig
up <spec>` after the kernel is in place.
@@ -1,110 +0,0 @@
---
name: openrig-operator
description: Use when operating or debugging host-side OpenRig runtime issues including daemon reachability, partial identity, unified-exec warnings, stale helper-process cleanup, or when distinguishing harness/process issues from live topology health.
---
# OpenRig Operator
## Overview
This skill covers host/runtime/operator triage around OpenRig itself.
Use it when the problem may be the daemon, the shell/runtime surface, or stale helper processes rather than the product workflow you are trying to run.
## When to Use
Use this skill when you see:
- `rig whoami --json` returning partial identity
- `rig ps --nodes -A --json` failing while some other `rig` commands still work
- `Sent to ...` plus `Verified: no`
- repeated unified-exec-process warnings
- suspicion that stale helper processes are accumulating
Do not use this skill for normal product workflow routing, queue handling, or ordinary peer communication. Use `openrig-user` for that.
## First Checks
Start with the minimum truthful operator read:
```bash
rig whoami --json
rig daemon status
rig ps --nodes -A --json
```
Interpret them together, not in isolation:
- partial `whoami` can mean identity is inferable while daemon-backed surfaces are degraded
- `daemon status` tells you whether the host daemon is up, not whether every seat can reach it cleanly
- `ps --nodes -A --json` is the best machine-readable fleet topology check when it works (v0.4.4: `--nodes` needs an explicit scope outside a managed session — `-A` for fleet, `--rig <name>` for one rig; the bare `rig ps` map is the cheap first glance)
## Verification Drift Vs Send Failure
For `rig send`:
- `Sent to ...` + `Verified: yes` = strong positive delivery evidence
- `Sent to ...` + `Verified: no` = ambiguous delivery, not automatic failure
- no `Sent to ...` line or a hard error = send failure
When verification is ambiguous, check:
- direct reply
- `rig capture <session>`
- transcript evidence
- queue/outbox state if the message asked for a durable handoff
Do not blindly retry until you have checked one of those.
## Unified Exec Warning
If you see:
- `Warning: The maximum number of unified exec processes you can keep open is 60 ...`
treat it first as a host/tooling-layer warning, not as automatic proof that the OpenRig topology is unhealthy.
This warning can coexist with a healthy live topology.
## Safe Process Triage
Inspect the process surface first:
```bash
ps -axo pid,ppid,command | rg 'tmux send-keys|rig queue create|tmux attach|codex|claude'
```
Think in layers:
- host/tooling layer: stale one-shot wrappers, session bookkeeping, helper shells
- topology layer: live `tmux attach` seats, live `codex` / `claude` runtimes, daemon health
Do not diagnose topology failure from tooling-layer warnings alone.
## Safe Cleanup Boundary
Usually safe to reap when clearly orphaned / one-shot:
- `tmux send-keys ...`
- short-lived shell wrappers created only to enqueue or send one message
Do not mass-kill:
- `tmux attach ...`
- `codex ...`
- `claude ...`
- other long-lived daemon/runtime processes
The point is to remove garbage, not workers.
## Common Mistakes
- treating `Verified: no` as if it proves the message did not land
- treating the unified-exec warning as if it proves the rig is overloaded
- killing live seats when only stale helper wrappers needed cleanup
- concluding "daemon down" from one seat's failure without checking host-level daemon status
## Practical Rule
Clean the smallest safe surface that matches the evidence.
If the warning or failure remains after stale-wrapper cleanup, re-check:
```bash
rig daemon status
rig ps --nodes -A --json
```
If those remain healthy, the residual issue may still be in the host/tool/session layer rather than in OpenRig topology state.
@@ -0,0 +1,460 @@
---
name: openrig-upgrade
description: Use when upgrading the OpenRig CLI/daemon on a host with running rigs, especially when preserving tmux-backed agent sessions through a daemon restart or documenting hot-upgrade SOP evidence.
metadata:
cli_surfaces_referenced:
- capture
- daemon adopt-state
- daemon start
- daemon status
- daemon stop
- down
- ps
- restore-check
- snapshot
- up
- upgrade backup
- upgrade preflight
- upgrade promote-runtime
- upgrade verify
- version
openrig:
stage: factory-approved
sibling_skills:
- openrig-user
- openrig-operator
- openrig-builder
- openrig-architect
- forming-an-openrig-mental-model
- ai-dev-workflows
---
# OpenRig Upgrade
## Core Principle
OpenRig has two different failure domains:
- **Agent process plane:** Claude/Codex/terminal seats running inside tmux.
- **Management plane:** the OpenRig daemon, CLI, SQLite DB, transcripts, node inventory,
send/capture APIs, restore metadata, and migrations.
A hot daemon upgrade is possible when the continuity seats remain alive in tmux and
the new daemon restarts against the same DB and transcript root. Do not run
`rig down` on continuity rigs unless the goal is a disruptive restore test; `rig down`
kills OpenRig-launched tmux sessions.
## Preferred Live-Cutover Operator Mode
For live production daemon cutovers, prefer an **out-of-band upgrade operator**:
a temporary host-local tmux seat outside the managed OpenRig topology, spawned
from the lifecycle/runtime-upgrade agent's current mental model.
Why: the managed rig stays in the agent process plane while a disposable sidecar
mutates the management plane. The sidecar inherits enough context to avoid a
cold handoff, but it is not inside the failure domain it is modifying.
Use this when all are true:
- the upgrade mutates the live daemon, CLI wrapper, DB, runtime worktree, tmux
lifecycle, or active control-plane truth;
- continuity seats should keep working during the upgrade;
- a lifecycle/runtime-upgrade seat has already prepared the packet or owns the
needed context;
- the human has granted an `operator auto window`.
In this SOP, `operator auto window` means a bounded operator-authorized upgrade lane. It does not
mean standing Codex `auto_review`, `--full-auto`, or approval-bypass mode. Use
`security-and-consequence-boundary-policy` skill for the current
security and consequence-boundary policy.
Do not use this pattern as a standing orchestration seat. The sidecar exists for
one cutover and then closes after handback.
### Sidecar Contract
The in-rig lifecycle/runtime-upgrade seat owns packet preparation and final
interpretation. The out-of-band sidecar owns only execution inside the approved
window.
Sidecar starter prompt shape:
```text
You are the host-local OpenRig runtime upgrade operator, outside the managed rig
topology. Execute the approved daemon-only cutover only after explicit human
approval. First read the upgrade preflight artifact and runtime-upgrade
decision. Prove you are outside the topology before mutation. Never run rig
down. Preserve tmux topology. Stop/start only the daemon, verify protected rigs,
write cutover evidence, unblock downstream artifacts only when the blocker is
truly closed, and rollback to <previous-wrapper-or-commit> if needed.
```
Required handback:
- write the live cutover evidence under the lifecycle evidence shelf;
- include proof that the sidecar was outside the topology/failure domain it
mutated;
- update any blocked downstream dogfood/runtime task only when the blocking
condition is truly closed;
- preserve caveats as downstream material instead of using them to reopen a
closed cutover gate;
- report back to the in-rig lifecycle/runtime-upgrade seat or orch surface with
daemon provenance, topology verification, caveats, rollback state, and one
compact paragraph of operator judgment about ambiguous choices;
- close the sidecar after the original lifecycle owner has absorbed the result.
Stop conditions for the sidecar:
- preflight or runtime-upgrade decision is missing;
- human approval is absent or narrower than the requested cutover;
- protected topology is already degraded beyond the packet's expected caveats;
- target runtime cannot be verified by process path, port listener, and command
evidence;
- any step would require `rig down` or destructive DB restore without a new
explicit human decision.
Generic primitive: this upgrade specialization composes over the
`sidecar-operator` skill (the underlying out-of-band-operator pattern;
this skill is the upgrade-specific specialization).
## What Changed On 2026-04-27
Initial belief:
- All rigs had to be down before daemon restart.
- Live upgrade was research-gated because DB migrations might break session/node
state while sessions were running.
- A parallel isolated daemon/adoption path looked necessary before production use.
Observed result:
- A daemon-only hot cutover preserved the live `example-seat` tmux
sessions.
- The old daemon was stopped without running `rig down`.
- The new source-pinned daemon started against the same production DB.
- `rig ps --nodes --json`, `rig capture`, and `rig restore-check` could inspect the
still-running Velocity seats after restart.
The simpler model is now preferred for tmux-backed continuity rigs: snapshot and
back up state, stop only the daemon, start the new daemon, then verify that live
sessions are still observable and manageable.
## Proven Hot Path
Use this as the canonical first-choice workflow for a host where continuity rigs
are tmux-backed and the operator wants non-disruptive daemon upgrade.
0. **Spawn the out-of-band operator when live cutover is required.**
The sidecar must be host-local and outside the managed topology being
upgraded. Keep the lifecycle/runtime-upgrade owner inside the rig so it can
continue to observe, ask questions, and absorb the handback.
1. **Choose continuity targets.**
Name the exact rigs that must remain live. Everything else is source material.
Do not let "nice to resume later" rigs expand the success criteria.
2. **Freeze active work.**
Get continuity seats to a stable/idle checkpoint. Record resume commands if
available.
3. **Inventory with filters.**
Do not dump full `rig ps` output on this host. Use filtered JSON:
```bash
rig ps --nodes --json \
| jq -r 'map(select(.rigName=="<rig>")) | sort_by(.canonicalSessionName)[] | "\(.canonicalSessionName) \(.sessionStatus) \(.startupStatus) \(.resumeToken // "none")"'
```
4. **Take a non-destructive snapshot of each continuity rig.**
This records rollback/recovery metadata without killing tmux sessions:
```bash
rig snapshot <rigId>
```
Verify the snapshot payload in SQLite has the expected nodes, sessions,
checkpoints, and resume tokens.
5. **Create a post-snapshot SQLite backup.**
Use SQLite's online backup API while the daemon is live. Then run
`PRAGMA integrity_check` on the backup and verify it contains the continuity
snapshot.
6. **Prepare a clean runtime artifact.**
Prefer a dedicated clean source worktree pinned to a commit:
```bash
git worktree add --detach /path/to/openrig-runtime-<shortsha> <commit>
cd /path/to/openrig-runtime-<shortsha>
PATH=/path/to/node22/bin:$PATH npm ci
PATH=/path/to/node22/bin:$PATH npm run build
```
Use even/LTS Node. The 2026-04-27 upgrade used Node `v22.22.1`.
7. **Stop only the daemon.**
First try:
```bash
rig daemon stop
```
If the daemon state file is missing but the PID is known and verified as the
OpenRig daemon, gracefully terminate that PID:
```bash
kill -TERM <daemonPid>
```
Do not use `kill -9` unless recovering from a wedged process with human
approval. Do not run `rig down` on continuity rigs.
8. **Start the pinned daemon against the same production DB.**
```bash
PATH=/path/to/node22/bin:$PATH \
node packages/cli/dist/index.js daemon start \
--port 7433 \
--host 127.0.0.1 \
--db ~/.openrig/openrig.sqlite
```
9. **Verify management continuity.**
Required checks:
```bash
rig daemon status
lsof -nP -iTCP:7433 -sTCP:LISTEN
rig ps --nodes --json | jq -r 'map(select(.rigName=="<rig>")) | ...'
rig capture --rig <rig> --lines 1 --json
rig restore-check --rig <rig>
```
Success means the daemon is healthy, continuity sessions remain running/ready,
capture works, transcripts are present, and `restore-check` reports no red
blockers.
10. **Align the default CLI with the new daemon.**
If `rig` is a wrapper, make sure it delegates to the new CLI. On the
2026-04-27 host this meant repointing the rigx real CLI via
`~/.openrig/bin/rig-real-17812d5`.
11. **Write evidence and hand back.**
The sidecar writes a cutover evidence packet with daemon provenance,
protected topology counts, representative capture/restore checks, smoke
results, caveats, and rollback state. Then it notifies the original in-rig
lifecycle/runtime-upgrade owner. Do not rely on chat as the only proof.
## 2026-04-27 Proof Point
Continuity target:
- `example-seat`
Pinned daemon:
- commit `17812d5d3bfe53dfdc5e202b1da3e8c91e2f4e54`
- subject `feat(agents): make runtime config spec-driven`
- committed `2026-04-26T18:30:08-07:00`
- runtime worktree `~/code/projects/openrig-runtime-17812d5`
Evidence:
- Velocity snapshot `01KQ84D3AF9YW6FQCM9SVSM5EG`
- post-snapshot DB backup
`db-backup/openrig-post-velocity-snapshot-20260427T185003Z.sqlite`
- backup integrity `ok`
- old daemon PID `62828`, Node 25 global npm install
- new daemon PID `39708`, Node 22 source runtime
- post-cutover `example-seat`: 4/4 seats `running` / `ready`
- `rig restore-check --rig example-seat`: `RESTORABLE WITH CAVEATS`,
`20 green | 9 yellow | 0 red`, `RECOVERY: NOT NEEDED`
Important caveat: this proves hot daemon cutover for tmux-backed Claude seats on
this host and commit range. It does not prove that arbitrary migrations,
non-tmux runtimes, service-backed rigs, or dead sessions can be recovered without
separate testing.
## 2026-05-02 Proof Point
Continuity targets:
- `kernel`
- `openrig-discovery`
- `openrig-dogfood`
- `openrig-lifecycle`
- `openrig-maintenance`
- `openrig-product-lab`
- `example-rig`
- `example-seat`
Pinned daemon:
- commit `6af2754824a07291562622ac019b68615fc41abe`
- runtime worktree `~/code/projects/openrig-runtime-6af2754`
- wrapper `~/.openrig/bin/rig-real-6af2754`
Pattern proven:
- lifecycle/runtime-upgrade prepared the decision and preflight artifacts;
- a host-local tmux sidecar (`host-upgrade-operator-6af2754`) was spawned
outside the managed topology with the current operator context;
- the sidecar stopped only the daemon, using verified PID fallback after
`rig daemon stop` refused due to missing daemon state;
- the sidecar started the target daemon on port `7433`, repointed the
config-layer wrapper default, verified protected topology, ran targeted
Agent Starter smoke/tests, wrote evidence, and unblocked Dogfood;
- Velocity delivery continued working throughout the cutover.
Evidence:
- preflight:
(internal upgrade-preflight evidence, 2026-05-01)
- live cutover:
(internal live-cutover evidence, 2026-05-02)
Important caveat: live `rig up --plan --json` accepted valid `starter_ref`
specs and rejected forbidden compositions, but plan-mode output did not emit the
`resolve_starter.detail.starterContent` stage expected by the Dogfood proof bar.
This is a product/dogfood caveat, not an upgrade failure.
## Brittle Edges Observed On 2026-04-27
Detailed field note:
(internal upgrade-brittleness field note, 2026-04-27)
Operator lessons from the daemon upgrade:
- `rig down` kills OpenRig-launched tmux sessions. Do not use it as a snapshot
primitive when resumability depends on keeping sessions alive.
- Old daemon/CLI combinations can be partially functional even when newer health
checks fail. A `/healthz` mismatch blocked `rig down --snapshot` even though
other daemon APIs still worked.
- `rig daemon stop` can fail when the daemon state file is missing. Operators
need a verified PID fallback, but the product should reconcile daemon state
automatically.
- If the sidecar has an operator auto window and `rig daemon stop` refuses only
because state is stale, a verified graceful PID termination is acceptable:
identify the daemon PID, verify its runtime path, send graceful `TERM`, and
verify the port is gone before starting the target daemon.
- CLI and daemon provenance can drift. Repointing or verifying the default
`rig` wrapper is part of the upgrade, not an afterthought.
- Raw `rig ps` is too noisy on this host. Use filtered JSON until the product
has compact first-class inventory views.
- Snapshot and backup verification is too manual. The SOP currently depends on
checking snapshot rows, resume tokens, SQLite backups, and integrity by hand.
Separate follow-on note, not part of the daemon-upgrade SOP:
(internal add-node-brittleness field note, 2026-04-27)
## Disruptive Restore Path
Use disruptive restore when the goal is to test recovery from killed sessions, or
when hot upgrade is blocked by incompatible migrations or corrupted management
state.
```bash
rig snapshot <rigId>
rig down <rigId>
# upgrade daemon/CLI
rig up <rigName>
rig restore-check --rig <rigName>
```
Expected restore results:
| Result | Meaning | Action |
|---|---|---|
| `fully_restored` | All nodes resumed or rebuilt | Resume normal work |
| `partially_restored` | Some nodes succeeded, some failed | Inspect failed nodes and relaunch manually |
| `failed` | Zero nodes restored | Check daemon logs, snapshot integrity, provider tokens |
| `not_attempted` | Pre-restore blockers | Fix blockers before retrying |
Do not confuse this path with hot upgrade. `rig down` is intentionally
disruptive.
## Stop Conditions
Do not proceed with hot upgrade if:
- continuity targets are mid-task and cannot checkpoint;
- continuity target tmux sessions are missing before upgrade;
- no verified DB backup exists after continuity snapshots;
- the target runtime cannot build under an even/LTS Node version;
- the daemon migration plan is known to rewrite session/binding semantics in a
way that has not been tested;
- disk space or DB integrity checks fail;
- the operator cannot identify the current daemon PID and runtime source.
## Rollback
Rollback means restoring the previous daemon runtime and, if necessary, the DB
backup.
For source runtime:
1. Stop the new daemon.
2. Start the previous runtime or npm/global daemon.
3. Verify `/healthz`, filtered continuity inventory, and `rig capture`.
4. Restore the DB backup only if migration or DB corruption is confirmed. Do not
replace the DB just because continuity sessions are still live but management
projection is degraded.
For npm runtime:
```bash
npm install -g @openrig/cli@<previous-version>
rig daemon stop
rig daemon start
```
## Roadmap: Better Hot Upgrades
The product should make the proven manual path boring and explicit.
Needed product surfaces:
- `rig upgrade preflight`:
daemon PID/runtime source, CLI source, DB path, migration plan, active rigs,
continuity targets, tmux liveness, disk space, DB integrity, backup target,
and rollback runtime.
- `rig daemon adopt-state` or equivalent:
recover a healthy daemon on a port when `daemon.json` is missing.
- `rig upgrade backup`:
online SQLite backup plus integrity and snapshot-presence verification.
- `rig upgrade promote-runtime <commit|artifact>`:
start from a clean worktree or packaged artifact under an even/LTS Node.
- `rig upgrade verify --rig <name>`:
filtered inventory, capture, transcript, restore-check, and honest continuity
classification.
- CLI/daemon provenance:
`rig version --json` should report CLI path, daemon path, commit/package
version, Node version, DB path, and started-at.
- Wrapper alignment:
rigx/default `rig` should clearly show which real CLI it delegates to.
- Compact inventory:
first-class `rig ps --rig <name> --nodes --compact` or equivalent, so
operators do not need ad hoc `jq` for routine safety checks.
Research still needed:
1. Migration-bearing hot upgrade on a throwaway rig.
2. Hot upgrade with non-critical live Codex seats.
3. Hot upgrade with service-backed rigs.
4. Adoption/reconciliation when daemon DB says sessions are running but tmux has
partially drifted.
5. Automated rollback on daemon startup failure or migration failure.
## Operator Summary
Hot upgrade rule:
**Snapshot continuity rigs, back up the DB, stop only the daemon, start the new
daemon against the same DB, then verify live tmux sessions through filtered
management surfaces.**
Disruptive restore rule:
**Use `rig down` only when testing or accepting session teardown.**
@@ -1,153 +0,0 @@
---
name: openrig-user-settings
description: Use when the user asks an OpenRig agent to read or change OpenRig configuration settings — workspace paths, file allowlists, progress scan roots, daemon port/host, transcripts, or anything stored in ~/.openrig/config.json
---
# OpenRig User Settings
OpenRig settings live in `~/.openrig/config.json` and are managed via the
`rig config` CLI family. The agent-editable surface is **CLI shell-out**;
do NOT write the JSON file directly unless the operator specifically asks
for raw-text editing (which is handled by the UI Files browser, not by you).
## Read
```bash
rig config # all keys, value + source
rig config --json # JSON: full RiggedConfig
rig config --json --with-source # JSON: {key: {value, source, default}}
rig config get <key> # single value
rig config get <key> --show-source # value + source on one line
rig config get <key> --json # {value, source, default}
```
Resolution order: **env var > config file > default**. Always use
`--show-source` (or `--json`) when reporting back to the operator so they
see *where* the value came from.
## Write
```bash
rig config set <key> <value> # set a key
rig config reset <key> # clear one override (revert to default)
rig config reset # delete the whole file
```
## Initialize a default workspace
```bash
rig config init-workspace # scaffold ~/.openrig/workspace/ with missions + slices
rig config init-workspace --dry-run # show what would be created
rig config init-workspace --root /path # use a custom root
rig config init-workspace --force # overwrite scaffolded files (NOT operator content)
```
This creates a file-backed Project workspace under the workspace root:
```text
README.md
STEERING.md
missions/<mission-id>/README.md
missions/<mission-id>/PROGRESS.md
missions/<mission-id>/slices/<slice-id>/README.md
progress/
field-notes/
specs/
```
It seeds two starter missions with multiple slices so the Project UI has a
real mission/slice map out of the box. It is operator-explicit; do NOT run it
on your own initiative unless the operator asks for workspace initialization
or repair.
## Common keys
| Key | Type | Purpose |
|---|---|---|
| `daemon.port` | number | OpenRig daemon HTTP port (default 7433) |
| `daemon.host` | string | Daemon bind host (default 127.0.0.1) |
| `db.path` | string | SQLite DB path (default ~/.openrig/openrig.sqlite) |
| `transcripts.enabled` | boolean | Whether the daemon writes transcripts |
| `transcripts.path` | string | Transcripts dir (default ~/.openrig/transcripts) |
| `workspace.root` | string | Single-root override (default ~/.openrig/workspace) |
| `workspace.slices_root` | string | Slice discovery root; default `<root>/missions` |
| `workspace.steering_path` | string | STEERING.md path; default `<root>/STEERING.md` |
| `workspace.field_notes_root` | string | Field notes dir; default `<root>/field-notes` |
| `workspace.specs_root` | string | Specs dir; default `<root>/specs` |
| `files.allowlist` | string | `name:/abs/path,name:/abs/path` — UI Files browser roots |
| `progress.scan_roots` | string | `name:/abs/path,name:/abs/path` — Progress browse roots |
Resolution order for workspace per-subdir keys: per-subdir override >
`workspace.root` cascade > built-in default.
## Common operator requests → canonical commands
> **"Make the UI work against an existing workspace layout"**:
> set the per-subdir workspace overrides explicitly:
>
> ```bash
> rig config set workspace.slices_root /path/to/your/workspace/missions
> rig config set workspace.steering_path /path/to/your/workspace/STEERING.md
> rig config set workspace.progress_scan_roots 'work:/path/to/your/workspace,missions:/path/to/your/workspace/missions'
> rig config set workspace.field_notes_root /path/to/your/workspace/field-notes
> ```
>
> No restart needed for the CLI; for the daemon's reads to pick up
> changes affecting startup-time wiring (`files.allowlist`,
> `progress.scan_roots`), restart with `rig daemon restart`.
> **"Initialize a default workspace"**:
>
> ```bash
> rig config init-workspace
> ```
After initialization, the Project UI expects this mapping:
- `workspace.root` maps to the Project workspace.
- `workspace.root/missions/<mission-id>` maps to a Project mission.
- `workspace.root/missions/<mission-id>/slices/<slice-id>` maps to a Project slice.
Queue item bodies or tags should mention the mission id and slice id when the
work belongs to a slice. That lets the Project Story, Queue, Tests, and
Topology tabs attach runtime work to the filesystem slice.
> **"Allow the file browser to see X directory"**:
>
> ```bash
> # Append to existing list (operator decides the name token):
> rig config get files.allowlist --show-source # check current
> rig config set files.allowlist 'workspace:/path/to/ws,docs:/path/to/docs'
> rig daemon restart # picks up new roots
> ```
> **"What's my current setting for X and where does it come from?"**:
>
> ```bash
> rig config get <key> --show-source
> ```
## When NOT to use this skill
- **Per-rig config** — settings are host-global at v0; per-rig is v0+1.
- **Secrets / credentials** — the `vault.specialist` managed-app handles
secrets. Don't put API keys or tokens in `~/.openrig/config.json`.
- **Settings sync across hosts** — out of scope at v0.
## Errors you might see
- `Unknown config key "<x>". Valid keys: …` — the key name is wrong.
Check the table above; suggest the correct key.
- `Config file at <path> is malformed. Fix the JSON or reset with: rig config reset` —
hand-edit broke the JSON. Operator can `rig config reset` (deletes the
whole file) or fix the syntax in the Files browser.
- `Invalid value for <key>: expected a number/true-false, got "<x>"` —
wrong type for a typed key. Reach for the key's type in the table.
## Provenance + safety
- Never write to `~/.openrig/config.json` directly. Use `rig config set`.
- Don't run `rig config init-workspace` on your own initiative — wait for
an operator request.
- Always cite the resolved source (env / file / default) when reporting
values back, so the operator knows whether their change actually took.
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,101 @@
---
name: rig-bundles-and-shareable-artifacts
description: Use when authoring or installing a rig bundle (packaged, shareable artifact that instantiates an opinionated OpenRig topology + workflow), reasoning about the bundle vs extension boundary, or auditing a bundle for portability. Covers the 4 failure modes that prevent bundles from working anywhere but the operator's machine, and the inspect-before-install discipline.
metadata:
cli_surfaces_referenced:
- bundle create
- bundle inspect
- bundle install
openrig:
stage: factory-approved
sibling_skills:
- rig-lifecycle
- topology-mutation-and-seat-management
- seat-scaling-and-specialization
- cross-host-rig-commands
- sidecar-operator
- specification-system
- extension-and-user-workspace
---
# Rig Bundles and Shareable Artifacts
A **rig bundle** is a packaged, shareable artifact that can instantiate
an opinionated OpenRig topology and workflow. It may include:
- rig specs
- agent specs
- workflow specs
- startup files
- skills or skill references
- operating-mode declarations
- proof expectations
- supporting fragments
**Shareable artifact** is broader than bundle: specs, bundles, skills,
workflows, and extensions can all be shared. A bundle is the packaged
form for "load this topology and way of working."
## Use this when
- Authoring a bundle from a proven lab pattern
- Installing a bundle (`rig bundle install <path>`)
- Inspecting a bundle before install (`rig bundle inspect <path>`)
- Reasoning about bundle vs extension boundary (bundle declares topology + workflow; extension adds behavior)
- Auditing a bundle for portability — does it work on a clean OpenRig environment, or only the author's machine?
## Don't use this when
- The work is a one-off topology you won't reuse. Specs alone are sufficient.
- The intent is to add runtime behavior (commands, views, dashboards). Use `extension-and-user-workspace`, not bundles.
- You want to ship a workflow as a daemon feature. Bundle is the path *before* daemon promotion.
## The bundle vs extension boundary (load-bearing)
| Concept | Declares | Example |
|---|---|---|
| **Bundle** | Rig shape + workflow ("load this topology and way of working") | A Velocity Team bundle |
| **Extension** | Behavior added to user workspace/runtime | A custom command, view, or dashboard |
Don't confuse them. A bundle is *opinionated content*; an extension is
*added behavior*. Both can be shareable artifacts, but they're
structurally distinct.
## Failure modes (4)
1. **A bundle works only on the operator's machine** because paths, providers, or credentials are implicit. Bundles must be self-describing for a clean OpenRig environment.
2. **A bundle includes too much local state and becomes a backup archive instead of a reusable artifact.** Bundle is the *intended shape*, not the current state of one specific install.
3. **A bundle declares topology but omits proof expectations or workflow mode.** Topology alone doesn't tell users what "working as advertised" means.
4. **Users cannot inspect what a bundle will create before installing it.** `rig bundle inspect` must show what will be created without side effects.
## Proof standard
Proof should:
1. Install the bundle into a **clean OpenRig environment**
2. Instantiate it
3. Verify the expected seats and workflow mode
4. Run a small smoke proof that the topology behaves as advertised
## Bundle path → product
Bundles are how proven lab patterns become reusable product experiences:
```
local dogfood pattern
→ bundle (with manifest, parameterization, proof expectations)
→ installed by another user on clean OpenRig
→ opinionated workflow shipped without becoming a daemon feature
→ if dependable, graduate parts into core daemon
```
This is also how OpenRig can ship opinionated workflows **without making
every workflow a daemon feature.**
## See also
- `extension-and-user-workspace` skill — sibling primitive for user-owned behavior added to runtime; bundle vs extension boundary
- `specification-system` skill — rig specs / agent specs / workflow specs that bundles package
- `agent-starters` skill — bundles can include or reference Agent Starters
- `composable-priming-packs` skill — bundles can package priming packs
- `openrig-user` skill — `rig bundle create / inspect / install` CLI surface
@@ -2,18 +2,27 @@
name: rig-lifecycle
description: Use when reasoning about the rig lifecycle operations family (create / start / stop / resume / restore / snapshot / release / unclaim / destroy), reading or trusting `rig ps` / lifecycle projections after recovery, or designing proof for a lifecycle scenario. Covers the 4 failure modes (auto-restore creates partial rig; projections report healthier than reality; provider auth treated as impl work; resume succeeds for one runtime fails another) plus the restore-honesty rule (failed resume is FAILED loudly — no auto fresh fallback).
metadata:
cli_surfaces_referenced:
- destroy
- down
- ps
- release
- restore
- restore-check
- resume
- snapshot
- unclaim
- up
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Lifecycle Reboot/Recovery Scenario Matrix (Tier 1 complete; Tier 2
human-gated). Codex auth-refusal surfaces as attention_required.
sibling_skills:
- openrig-user
- openrig-operator
- seat-continuity-and-handover
transfer_test: pending
- topology-mutation-and-seat-management
- seat-scaling-and-specialization
- cross-host-rig-commands
- sidecar-operator
- rig-bundles-and-shareable-artifacts
- specification-system
- extension-and-user-workspace
---
# Rig Lifecycle
@@ -53,7 +62,7 @@ states.
**Failed resume is FAILED loudly.** No automatic fresh fallback. Fresh
launch is **explicit follow-up only.** This is enforced architecturally
at the daemon level (per `docs/as-built/architecture/architecture-rules-and-event-system.md` rule 15).
at the daemon level (per `architecture.md` §7 rule 15).
The locked restore-outcome vocabulary:
@@ -112,5 +121,7 @@ different claims; don't conflate.
- `openrig-user` skill — CLI surface for `rig up / down / restore / etc.`
- `openrig-operator` skill — operator-level discipline for OpenRig itself
- `seat-continuity-and-handover` skill — occupant-creation modes for restore (`resume` / `rebuild` / `fresh` / `failed`)
- `seat-continuity-and-handover` skill — sub-primitive: occupant-creation modes for restore (`resume` / `rebuild` / `fresh` / `failed`)
- `session-source-fork` skill — `forked` continuity outcome for fork-based restore
- `permission-and-capability-preflight` skill — provider-auth blocker → escalation path
- `openrig/docs/as-built/architecture/lifecycle-snapshot-restore.md` (product reference doc) — daemon enforcement of restore-honesty rule
@@ -0,0 +1,160 @@
---
name: session-source-fork
description: |
Use when authoring a rig spec member or `rig expand` payload that needs to start a new managed seat from a prior runtime conversation source — `session_source: { mode: fork, ref: { kind, value } }`. v1 supports `mode: fork` with `ref.kind: native_id` for Claude and Codex. The new seat persists a NEW post-fork token; the parent token is NEVER written onto the new seat. NOT for restoring an existing seat or for artifact-backed mental-model rebuild.
metadata:
openrig:
stage: factory-approved
sibling_skills:
- claude-compaction-restore
- mental-model-ha
- scope-recovery
- session-compaction-and-restore
- agent-startup-and-context-ingestion
- agent-starters
- composable-priming-packs
- seat-continuity-and-handover
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# session_source Fork
`session_source` is a **member-level OpenRig field** that declares how a
newly-launched managed seat should derive its initial conversation
continuity from a prior runtime conversation source.
v1 supports one mode: **`fork`** — start a *new* managed seat from a
prior native runtime conversation source without claiming the original
seat continued.
The schema is runtime-neutral; implementation is runtime-specific (Claude
and Codex have their own native fork commands).
## Use this when
- Authoring a rig spec member that should fork from a prior session
- Authoring a `rig expand` payload with `session_source`
- Reasoning about whether to use `fork` vs `rebuild` vs `resume` vs `fresh` for a new seat
- Composing fork + handover (seat-handover-over-fork) — see `seat-continuity-and-handover` skill
## Don't use this when
- The seat is being **restored**, not created. Restore continues an existing managed seat. Fork creates a new seat.
- The continuity is **artifact-backed mental-model rebuild** (packet-derived understanding, not native runtime continuity). Use `mode: rebuild` (see `seat-continuity-and-handover` for the rebuild surface) — do NOT collapse fork into artifact-backed reentry; the distinction is load-bearing.
- The runtime is `terminal`. Terminal runtime rejects `session_source`.
## The shape (canonical YAML)
```yaml
members:
- id: reviewer-2
runtime: claude-code # or "codex"; not valid on terminal
agent_ref: specs/agents/reviewer.yaml
profile: reviewer
cwd: .
session_source:
mode: fork
ref:
kind: native_id # v1 fork mode supports native_id only
value: "0b0165d7-cb4d-4650-90de-15c0a1ede9e6"
```
Rules:
- `mode` v1 only valid value: `fork`.
- `ref.kind` v1 supports `native_id` only. Schema rejects `artifact_path`, `name`, `last`, and `artifact_set` pre-launch with explicit deferred/weaker/wrong-mode error messages (see `packages/daemon/src/domain/rigspec-schema.ts` validateSessionSourceFork). Adapter-level refusal exists as defensive handling but should not be reachable in v1 because schema rejects first.
- `value` required for `ref.kind: native_id` in v1 (the only schema-accepted kind). Future-state value semantics for `artifact_path` / `name` / `last` are not active in v1 because schema rejects those kinds pre-launch.
- `rig expand` accepts the same shape so dynamically-added members can carry session-source attribution.
The primitive does NOT introduce a new top-level command. It flows
through existing rig spec and expansion pathways.
## State model
`session_source` is a **launch-time input**, not a long-lived stateful field:
1. **Declared** — present in member config or expansion payload
2. **Resolved** — at launch time, OpenRig resolves the `ref` against the runtime
3. **Realized** — runtime fork succeeds; new managed seat receives a **NEW** native continuity token (Claude session id or Codex thread id). OpenRig persists that NEW token. **Parent token is NEVER written onto the new seat.**
4. **Failed** — resolution or fork failed; seat not launched as a fork; clear error names the resolution step that failed
Once realized, `session_source` is essentially history. Restoring the
seat later is `restore` of the new seat, not re-fork-from-parent.
## Failure modes (5)
1. **Source session id not found** — runtime cannot resolve `native_id`. **Action**: emit error naming runtime + missing id; do NOT silently launch fresh. (Future-state note: when `artifact_path` is supported in a follow-up slice, it could become a candidate fallback for Claude; in v1 schema rejects `artifact_path` pre-launch so no fallback path exists.)
2. **Source artifact path missing** *(out of v1 scope)* — would apply once `ref.kind: artifact_path` becomes schema-accepted. v1 schema rejects this kind pre-launch.
3. **Unsupported runtime/kind combination** *(largely pre-empted in v1 by schema rejection)* — schema rejects all non-`native_id` kinds upfront. Adapter-level refusal exists as defensive handling but is not reached in v1.
4. **Fork launch failed after source resolution** — runtime command (`claude --resume <parent> --fork-session` or `codex fork <id>`) returned non-zero or hung. Preserve runtime stderr; do not record new seat as launched; do not write parent token onto seat.
5. **Persistence inconsistency** — fork succeeded but seat-token persistence cannot record new continuity token. **Internal failure**: seat is not considered launched until new token is durably written.
## Honest UX rule (verbatim)
The primitive must NOT report "restored the original agent" or "resumed
the original seat" or "snapshot." The correct framing is **"forked from
source session"** / **"started from prior conversation source."**
Negative-grep over adapter source confirms ZERO `restored` / `resumed` /
`snapshot` strings in fork code paths.
## Hard boundaries (do-not list; verbatim)
- **Do NOT introduce a new top-level command** (e.g., `rig fork`). The primitive flows through existing spec/expansion pathways.
- **Do NOT report "restored" / "resumed the original seat" / "snapshot"** in any UX surface.
- **Do NOT couple `session_source` to AgentSpec.** It's a member-level launch-time input.
- **Do NOT change `restore` semantics.** `session_source` creates a seat; `restore` continues an existing managed seat.
## Adapter command shape (shipped v1)
| Runtime | Command shape |
|---|---|
| Claude (`mode: fork` + `ref.kind: native_id`) | `claude --resume <parent-id> --fork-session` |
| Codex (`mode: fork` + `ref.kind: native_id`) | `codex... fork <parent-id>` |
| Terminal | Rejected at schema level |
Mutual exclusion between `resumeToken` (restore path) and `forkSource`
(fork path) is enforced at three layers in the daemon.
## Continuity outcome literals
| Outcome | When |
|---|---|
| `forked` | Fork succeeded; new seat has new native token; parent never written onto new seat |
| `fresh` | Fresh launch (no `session_source` declared) |
| `resumed` | Restore of existing managed seat |
| `failed` | Resolution or fork failed |
For `seat handover over fork` composition, the binding outcome is
independent (see `seat-continuity-and-handover` skill).
## Active-daemon caveat (live-runtime gap)
2026-04-30 live scale-out dogfood found: source checkout contained fork
support, but active daemon was running from a pre-fork commit. **Verify
the active daemon/runtime commit contains the fork path before live
proof.** Isolated daemon proof at the target commit can prove the
feature safely; live forked scale-out remains unproven until the active
daemon parity is verified.
## Currently shipped (v1) vs deferred
Shipped at openrig `c7b6df1` (2026-04-30):
- Schema accept/reject for full Honest Refusal Matrix
- Codec roundtrip (serialize → parse → normalize preserves `session_source` faithfully)
- Expansion path through `rig expand` member-input
- Adapter command shape for Claude + Codex `native_id`
- Persistence honesty (seat's `resume_token` is the NEW post-fork token; parent token NEVER written)
- Honest UX literal contract (`continuityOutcome: forked`)
Deferred:
- Tier 2 real-runtime fork proof (disposable Tart VM cycle, human-gated)
- Claude `artifact_path` mode (schema currently refuses with deferred message)
- Provenance columns (`parent_native_id` / `created_via` for queryable RSI consumer)
- Cross-host fork (source on host A, new seat on host B) — depends on `cross-host-rig-commands`
## See also
- `seat-continuity-and-handover` skill — sibling occupant-creation primitives (resume / fork / rebuild / fresh) + seat-binding (handover composes with fork)
- `agent-starters` skill — composes session_source fork into named reusable starting points
- `cross-host-rig-commands` skill — multi-host fork (deferred)
@@ -0,0 +1,103 @@
---
name: specification-system
description: Use when authoring rig specs, agent specs, workflow specs, startup/context fragments, operating-mode declarations, or designing the user spec library. Covers the 4 failure modes (spec instantiates topology but not workflow/mode; spec depends on local paths and fails on another host; agents modify specs as one-off files instead of preserving reusable intent; validation proves YAML shape but not whether topology can run) and the validation-vs-runtime-realization distinction.
metadata:
cli_surfaces_referenced:
- agent
- bundle
- spec
- specs
openrig:
stage: factory-approved
sibling_skills:
- rig-lifecycle
- topology-mutation-and-seat-management
- seat-scaling-and-specialization
- cross-host-rig-commands
- sidecar-operator
- rig-bundles-and-shareable-artifacts
- extension-and-user-workspace
---
# Specification System
The declarative primitive family for OpenRig intent: **rig specs, agent
specs, workflow specs, startup/context fragments, operating-mode
declarations, and the user spec library that stores and reuses them.**
Specs are how humans and agents describe **repeatable topology and
behavior** without re-explaining it in chat. They are also shareable
artifacts: a user should be able to publish a spec or spec family so
another user can instantiate the same rig shape, role structure, or
workflow pattern.
**Without a dependable spec primitive, OpenRig depends on manual
startup prompts and tribal memory.** That blocks repeatability, product
demos, rig bundles, and autonomous rig construction.
## Use this when
- Authoring a RigSpec / AgentSpec / workflow spec
- Designing a startup/context fragment
- Reasoning about spec-library lifecycle (validation, sharing, upgrade semantics)
- Auditing a spec for portability (does it run on another host?)
- Distinguishing spec vs bundle vs extension cleanly
## Don't use this when
- The work is one-off and won't be reused. Manual rig assembly is fine for one-shot work.
- The intent is to package a topology + workflow as a shareable artifact. That's `rig-bundles-and-shareable-artifacts`.
- The intent is to add runtime behavior. That's `extension-and-user-workspace`.
## Failure modes (4)
1. **A spec can instantiate a topology but not the workflow or operating mode needed to use it.** Topology is necessary but not sufficient — workflow and operating mode must be declared too.
2. **A shared spec depends on local paths or hidden startup fragments and fails on another host.** Specs must be self-describing for portability.
3. **Agents modify specs as one-off files instead of preserving reusable user/library intent.** Specs are reusable; treating each instance as one-off destroys the primitive's value.
4. **Validation proves YAML shape but not whether the declared topology can actually run.** Structural validation is not enough; runtime realization is the real proof.
## Proof standard
Proof should:
1. Author a spec
2. Validate it (structural)
3. Install it (into spec library)
4. Instantiate it on a **clean OpenRig environment**
5. Show **both structural validation AND runtime realization**
Validation alone is insufficient.
## Spec / bundle / extension boundary
| Concept | Declares | Example |
|---|---|---|
| **Spec** | Topology / role / workflow shape (declarative intent) | `rig.yaml`, `agent.yaml`, `workflow.yaml` |
| **Bundle** | Spec(s) + supporting fragments packaged for shareable instantiation | A Velocity Team bundle |
| **Extension** | Runtime behavior added to user workspace | RigX command, custom view |
Don't conflate them. The contract should distinguish spec, bundle, and
extension cleanly.
## Currently shipped surfaces
OpenRig already has:
- RigSpec / AgentSpec authoring (`agent.yaml`, `rig.yaml` formats; see `openrig-architect` skill)
- Workflow specs (markdown/YAML files, daemon read-through cache via `workflow_specs` table; see `workflow-runtime` skill)
- Bundle/spec command surface (`rig bundle / spec / agent / specs ls/show/preview/add/sync/remove/rename`)
- Spec library (filesystem-backed at `packages/daemon/specs/` + `~/.openrig/specs/` per cli-reference.md)
Not yet shipped:
- Spec library lifecycle (validation, sharing, upgrade) treated as a first-class primitive
- Cross-host spec sharing
- Marketplace / public registry
## See also
- `openrig-architect` skill — RigSpec / AgentSpec authoring discipline
- `workflow-runtime` skill — workflow spec authoring + transactional-scribe contract
- `rig-bundles-and-shareable-artifacts` skill — bundle is the packaged form of specs
- `extension-and-user-workspace` skill — extensions add runtime behavior; specs declare intent
- `openrig/docs/reference/rig-spec.md` (product reference doc) — RigSpec format specification
- `openrig/docs/reference/agent-spec.md` (product reference doc) — AgentSpec format specification
@@ -0,0 +1,118 @@
---
name: topology-mutation-and-seat-management
description: Use when changing a rig while it is alive — `rig expand` / `rig shrink` / `rig launch` / `rig remove` / `rig discover` / `rig bind` / `rig adopt` / `rig attach`. Covers the 4 failure modes (newly created seat lacks queue/startup/role; edges and permissions not updated; adopt/bind succeeds at tmux but not OpenRig identity; shrink/remove leaves stale topology references) and the rule that mutation must work while the rig is active, not just in clean fixtures.
metadata:
cli_surfaces_referenced:
- adopt
- attach
- bind
- discover
- expand
- launch
- ps
- release
- remove
- shrink
- unclaim
- up
- whoami
openrig:
stage: factory-approved
sibling_skills:
- rig-lifecycle
- seat-scaling-and-specialization
- cross-host-rig-commands
- sidecar-operator
- rig-bundles-and-shareable-artifacts
- specification-system
- extension-and-user-workspace
---
# Topology Mutation and Seat Management
The ability to change a rig **while it is alive**: expand, shrink,
launch, remove, discover, bind, adopt, and attach seats or sessions.
Seat management includes the **stable identifiers, edges, roles, and
startup context** that make those mutations coherent.
**OpenRig should be easy to reach for.** A user should be able to add
capacity, retire capacity, adopt an existing session, or attach a
terminal **without rebuilding the whole topology.** If mutation is
rarely tested, users avoid it and the product collapses back into
static launch scripts.
## Use this when
- Adding capacity to a running rig (`rig expand <rig> <pod-fragment-path>`)
- Removing capacity (`rig shrink` / `rig remove`)
- Launching/relaunching a node in a running rig (`rig launch`)
- Binding a discovered session into an existing logical node (`rig bind`)
- Adopting a topology + binding live sessions (`rig adopt`)
- Attaching a shell or agent into a rig node (`rig attach --self`)
## Don't use this when
- The rig is being created fresh from scratch — use `rig up` (lifecycle, not mutation)
- The intent is to scale specifically (add specialized capacity) — use `seat-scaling-and-specialization` skill
- The intent is occupant replacement on a stable seat — use `seat-continuity-and-handover` skill
## Failure modes (4)
1. **A newly created seat lacks the queue, startup context, or role files it needs to operate.** Topology mutation creates the seat, but the seat needs more than a tmux session to be useful.
2. **Edges and permissions are not updated when a seat is added or removed.** Topology references go stale; later workflows route to nonexistent seats.
3. **Adopt/bind succeeds at the tmux/session layer but not at the OpenRig identity layer.** The session is attached but `rig whoami` doesn't know about it; downstream consumers see partial state.
4. **Shrink/remove leaves stale topology references that later workflows route into.** Cleanup is part of the operation, not an afterthought.
## Proof standard
Proof must cover **mutation while a rig is active**, not just in a
clean test fixture. The useful matrix:
| Operation | What to verify |
|---|---|
| Add seat | New seat has queue, startup context, role; `rig whoami` resolves it |
| Remove seat | Stale references cleaned; edges/permissions updated |
| Adopt existing session | tmux session bound at OpenRig identity layer; `rig whoami` reports correctly |
| Attach observer terminal | External CLI attachment recorded |
| Verify topology projections after each move | `rig ps --nodes` reflects current truth, not pre-mutation cache |
A clean-fixture proof is necessary but not sufficient. Live-rig proof
catches the failure modes that fixture-mode misses.
## Why important strategically
The current coordination experiments repeatedly need new queues,
watchdogs, humans, and test seats — which makes this family
**strategically important.** Seat continuity work will eventually
separate stable seat identity from runtime occupant identity (see
`seat-continuity-and-handover`).
## Currently shipped surfaces
Per `cli-reference.md` v0.2.0:
- `rig expand <rig-id> <pod-fragment-path>` (with optional `session_source`)
- `rig shrink <rigId> <podRef>`
- `rig launch <rigId> <nodeRef>`
- `rig remove <rigId> <nodeRef>`
- `rig discover [--draft]`
- `rig bind <discoveredId> --rig <rigId> (--node <id> | --pod <ns> --member <name>)`
- `rig adopt <path> --bind <logicalId=tmuxSessionOrDiscoveryId>`
- `rig attach --self --rig <rigId> --node <logicalId>`
- `rig unclaim <sessionRef>` / `rig release <rigId>`
## Active proof gap (current)
The 2026-04-30 topology mutation add-seat proof pass is **active**.
Product Lab shaped it; planner authored `IMPLEMENTATION.md`; driver
landed the smallest honest CLI retry-guidance patch for failed
`rig expand` recovery. **Remaining proof is the Section B disposable-rig
runtime matrix, blocked on operator posture** and owned by
`orch-lead@your-rig`.
## See also
- `openrig-user` skill — CLI surface for `rig expand / shrink / launch / remove / bind / adopt / attach`
- `seat-scaling-and-specialization` skill — when to add specialized capacity vs generic
- `seat-continuity-and-handover` skill — replacing an occupant on a stable seat (different shape than topology mutation)
- `cross-host-rig-commands` skill — cross-host topology mutation (deferred)
@@ -0,0 +1,125 @@
---
name: watchdog
description: Use when configuring `rig watchdog` policies, authoring wake/refocus/alignment-checkpoint messages, or choosing the right intervention level for a stale-owner situation. The 3-level continuity-check stack (wake / refocus / alignment-checkpoint), the discipline that prevents cadence pollution and bureaucracy theater, and the artifact-pool loop-edge pattern for evidence-aware waking.
metadata:
openrig:
stage: factory-approved
sibling_skills:
# Sibling sweep 2026-07-19 audit: superseded control-plane-* family
# dropped (control-plane-watchdog now redirects HERE); kept the
# genuinely adjacent set.
- queue-handoff
- workflow-runtime
- alignment-trace
- looping-workflows
- intake-routing
- human-in-the-loop
- status-not-chat-orchestrator
---
# Watchdog
Continuity checks are timed or evidence-triggered interventions that
keep an agent workflow from going idle, drifting, or entering needless
bureaucracy. They operationalize the alignment-trace doctrine.
## Use this when
- **Authoring a watchdog policy** for a long-running rig (artifact-pool
edges, stale-owner detection, periodic reminders).
- **Choosing the intervention level** for a stale-owner situation: is
this a wake, a refocus, or an alignment checkpoint?
- **Drafting wake/refocus/alignment-checkpoint message text** that
prevents cadence pollution and bureaucracy theater.
- **Deciding cadence** — scan vs wake intervals, conservative vs
aggressive nudging.
## Don't use this when
- The agent is actively working and closing artifacts. Prefer no-op.
- The intervention is masking bad startup or workflow design — fix the
underlying cause, don't compensate via watchdog.
- The work has a clear next-action handoff already in queue. Use queue
nudges instead of a watchdog policy.
## The 3-level intervention stack
| Level | Goal | When | What it does |
|---|---|---|---|
| **Wake** | Restart motion | Owner appears idle, stale, blocked, or missing a next handoff | Small liveness nudge — does NOT reframe the work |
| **Refocus** | Correct drift | Output shows mode drift, approval regression, weak stop-condition reasoning | Medium alignment nudge — re-centers on role, north star, current approved workstream, coordination mode, stop conditions; does NOT interrupt valid work |
| **Alignment checkpoint** | Rebuild shared map | Phase boundary, lifecycle mutation, product-intent decision, confusing contradiction | Larger deliberate pause — agent runs full alignment-trace before proceeding |
`cron`, timers, and `rig watchdog` are scheduling substrates. They
should NOT imply that every tick means the same semantic action. The
intervention level is chosen by evidence, not cadence.
## Current best practice for refocus message text
A well-shaped refocus message:
- Starts with: **finish current action first**.
- Names the intervention kind: wake, refocus, or alignment checkpoint.
- Names the current approved workstream or says none is known.
- Says what continuity means: continue, verify, hand off, or explicitly park.
- Names stop conditions: scope/risk/posture changes, failed gate, contradictory evidence, or no continuity chain naming a sensible next step.
- Does NOT convert itself into a fresh approval gate.
- Does NOT wake delivery seats unless an approved workflow exists and the owner is stale.
## Failure modes (7; verbatim)
1. Cadence is too frequent and pollutes the workstream.
2. Watchdog wakes the wrong seat instead of the stale owner.
3. Refocus text is too rule-shaped and creates brittle behavior.
4. Watchdog compensates for bad startup or workflow design instead of revealing it.
5. Refocus is misread as a new top-priority task and interrupts the current action.
6. Refocus becomes bureaucracy theater: an already-approved workflow stops for re-approval.
7. Repeated static nudges teach agents to answer the reminder instead of progressing the artifact.
## Artifact-pool loop edges (the first evidence-aware pattern)
The first evidence-aware watchdog use that should remain small and
explicit:
- **Consumer-pool wake**: if a ready artifact exists, wake the consumer loop head.
- **Producer-edge repair**: if upstream completion exists but the downstream artifact is missing, wake the producer loop head.
**Scan cadence and wake cadence are separate.** Worked example (from the
RSI v2 mission, now archived — the numbers are era-specific, the
scan-vs-wake separation is the durable rule): scan every 30 seconds, wake
at most every 600 seconds while work remains actionable.
This is not a generic workflow engine. It's a guardrail against cold
pools and missing edge artifacts.
## Two surfaces: rigx watchdog (config-layer) and rig watchdog (daemon-shipped)
| Surface | Status | Policies |
|---|---|---|
| `rigx watchdog` (config-layer dogfood) | Tmux-backed loops; coexists with daemon | Static periodic-reminder + artifact-pool-ready + edge-artifact-required (per-RSI-loop) |
| `rig watchdog` (daemon-shipped, v0.2.0 Phase C) | SQLite-backed scheduler; survives daemon restart | `periodic-reminder` / `artifact-pool-ready` / `edge-artifact-required` / `workflow-keepalive` (Phase D — reads workflow_instances directly) |
Daemon `rig watchdog` is the active host coordination surface for new
work. History records only loud evaluations (`sent` / `terminal`);
quiet skip reasons are NOT recorded — POC parity so agents are not
woken about scheduler polls.
## Future shape (current limit)
The mature primitive should be evidence-aware: inspect durable
queue/workflow state, pane activity, transcript/context growth, and
known workstream frontier; classify the intervention as no-op / wake /
refocus / alignment-checkpoint; prefer no-op for active owners; render
message text from the active orientation graph instead of hard-coding
static policy.
Until queue substrate, activity state, and lifecycle evidence are fully
productized at this level of granularity: keep config-layer use small
and explicit, prefer one workflow watchdog plus targeted exception
handling over many per-seat nag loops.
## See also
- `alignment-trace` skill — the doctrine this primitive operationalizes; full and light trace templates
- `queue-handoff` skill — durable handoff via queue items; watchdog is complementary (watchdog wakes; queue routes)
- `looping-workflows` skill — operating discipline for self-driving rig-shaped loops; uses watchdog policies for loop edges
@@ -10,9 +10,9 @@ You are part of the orchestration pod. Your job is to keep the team productive,
## Startup sequence
Before you summarize the rig or assign real work:
1. Load `using-superpowers`, `openrig-user`, `orchestration-team`, `systematic-debugging`, and `verification-before-completion`. Also load `mission-slice-sop` — the operating procedure for the canonical mission/slice files (you own PROGRESS.md `§1`; run `rig scope audit` at slice-close/mission-wrap).
1. Load `using-superpowers`, `openrig-user`, `orchestration-team`, `systematic-debugging`, and `verification-before-completion`.
2. Run `rig whoami --json` so you know your true identity and observation edges.
3. Run `rig ps --nodes -A --json` (v0.4.4: `--nodes` scopes to the current rig by default; `-A` for the fleet) and wait for the expected starter topology to settle.
3. Run `rig ps --nodes --json` and wait for the expected starter topology to settle.
4. Check recent chatroom history or direct startup messages so you know who is actually online and what they already reported.
5. Only then announce readiness or assign work.
@@ -34,7 +34,7 @@ The orchestration pod is responsible for:
**Principle:** monitoring intensity tracks **stakes × how likely you are to need to intervene, bounded to the window where that's true.** Spend tight attention only where it changes what you do, only as long as the risk lasts, then return to default. (Same evidence-not-cadence rule the `watchdog` skill applies to intervention *level*, applied to *intensity*.) **Self-test: "Can I name the stakes AND the condition that ends this close-watch?"** If not, you're hyper-monitoring.
**Default (almost always) — token-efficient.** Steady-state your job is the **idle-without-handoff exception**: the queue handles normal handoff; you catch the agent who finished + went idle without closing/handing off.
- **Status lives in the queue, not panes** (`status-not-chat-orchestrator`): `rig ps` (the consolidated map) / `rig ps --nodes -A --json` + `rig queue` are your status source; do NOT reconstruct fleet-state by capturing panes (pane `rig capture` is high-bandwidth *within your own pod* — that's fine; it is not how you track cross-pod/fleet state).
- **Status lives in the queue, not panes** (`status-not-chat-orchestrator`): `rig ps --nodes --json` + `rig queue` are your status source; do NOT reconstruct fleet-state by capturing panes (pane `rig capture` is high-bandwidth *within your own pod* — that's fine; it is not how you track cross-pod/fleet state).
- **The watchdog is your clock** (`watchdog`): configure `rig watchdog` to wake you (~3 min); between wakes, idle (zero tokens) — no self-run sleep-loop re-reading panes at steady-state. Prefer one workflow-watchdog + targeted exception handling over many per-seat nag loops.
- **On each wake — cheap sweep:** `rig queue` + a *filtered* `rig ps` (see "Read cheap" below) first; ONLY for a seat that looks idle/suspicious, `rig capture <session>` last few lines (never a full pane, never huge chunks); **active owner → no-op.**
- **Read cheap — every status command has a token cost; project to the question.** The queue-first rule is about *where* status lives; this is about *how much you pay to read it*. The token bomb is the broad unfiltered dump, not the pane capture: an unfiltered fleet-wide `rig ps --nodes --json` emits ~77k tokens — for a one-rig or one-qitem question that is almost all waste, and at watchdog cadence it burns the shared account fast.
@@ -45,7 +45,7 @@ The orchestration pod is responsible for:
- **Self-test:** "Does this read return more than the decision in front of me needs?" If yes, narrow it before running.
- **A watchdog turn is small:** tiny queue/frontier check → make exactly the needed durable transition or wake → park. Not a fleet-wide scan per wake.
**Close-monitoring — legitimate exception, deliberate + BOUNDED.** Some moments warrant tight/continuous attention — a seat doing something high-stakes, novel, or fragile where you may need to feed context, hand-hold, or intervene fast; a delicate gate; a recovery in flight. Switch in **on purpose** on a nameable trigger; **exit the instant the condition clears** (time- *and* event-bounded); don't let it bleed into steady-state. Worked example (slice-17): close through compaction-recovery / QA-runtime-proof / merge-gate; back off to queue+watchdog once the owner is active + the qitem in-progress. The anti-pattern is not tight monitoring — it's **unbounded** tight monitoring (an ambient sleep-loop with no nameable end-condition). That is what burns the shared account.
**Close-monitoring — legitimate exception, deliberate + BOUNDED.** Some moments warrant tight/continuous attention — a seat doing something high-stakes, novel, or fragile where you may need to feed context, hand-hold, or intervene fast; a delicate gate; a recovery in flight. Switch in **on purpose** on a nameable trigger; **exit the instant the condition clears** (time- *and* event-bounded); don't let it bleed into steady-state. Worked example: close through compaction-recovery / QA-runtime-proof / merge-gate; back off to queue+watchdog once the owner is active + the qitem in-progress. The anti-pattern is not tight monitoring — it's **unbounded** tight monitoring (an ambient sleep-loop with no nameable end-condition). That is what burns the shared account.
### B. Intervention — correct + re-teach, don't silently substitute
When you DO catch a dropped potato, your default is to **teach the agent the protocol, not do it for them.** Agents load the hot-potato / queue-handoff protocol and are supposed to hand off on their own; you are the **belt-and-suspenders** for when one doesn't (skill not loaded, fell out of context, or just got it wrong).
@@ -7,6 +7,9 @@ description: Complete operating manual for the review pod. Covers everyday revie
You are part of the review pod. Your value is fresh scrutiny that implementation and QA do not have.
## Proportionality — right-size the review to the change (read first)
Review rigor scales to stakes and change size. A small, low-stakes diff gets a fast, focused pass; the full deep protocol (context proof, confidence scores, independent → cross-exam → convergence → roundtable) is for architecture / security / high-blast-radius changes. Don't run the heavy machinery on a one-line fix — that's ceremony, and it delays the ship it exists to protect. Catch what matters, then let good work through. The point of review is **better product shipped, not review performed.**
## Startup sequence
Before you announce a review position:
@@ -21,13 +21,13 @@ openrig-relationship: vendored-modified
|---|---|---|
| Visual Companion offer step | Standalone step #2 in the flow — "offer Visual Companion in its own message before clarifying questions" | **Removed.** OpenRig agents typically operate without a separate visual-companion mode; visual design work routes through dedicated design-pod seats. |
| Spec self-review step | Step #7 — inline self-review for placeholders/contradictions/scope | **Removed.** Self-review is handled at the rig/orchestration layer (driver/guard pattern + review-lead). |
| User reviews written spec | Step #8 — pause for user to review the spec file | **Removed.** OpenRig's founder-walk and orchestration gates already cover this checkpoint at a higher level. |
| User reviews written spec | Step #8 — pause for user to review the spec file | **Removed.** OpenRig's the operator-walk and orchestration gates already cover this checkpoint at a higher level. |
| Spec save path | `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` | `docs/plans/YYYY-MM-DD-<topic>-design.md` (matches OpenRig's `docs/plans/` convention) |
| Process flow diagram | Includes Visual Companion + Spec self-review nodes | Simplified to remove those nodes; edges rewired |
## Why these modifications (inferred)
- **Multi-platform / multi-step gates removed**: OpenRig's rig-level orchestration (driver → guard → qa, founder-walks) already provides the checkpoint structure that the upstream skill builds inline. Keeping those steps inside the skill double-gates the work.
- **Multi-platform / multi-step gates removed**: OpenRig's rig-level orchestration (driver → guard → qa, the operator-walks) already provides the checkpoint structure that the upstream skill builds inline. Keeping those steps inside the skill double-gates the work.
- **`docs/plans/` path**: OpenRig's project structure uses `docs/plans/` as the canonical home for design + implementation plan documents (matches `writing-plans` modification — both are co-ordinated).
## Companion files
@@ -44,5 +44,5 @@ Watch upstream for:
When upstream changes:
1. Pull non-conflicting changes into the OpenRig copy.
2. Preserve the simplified 6-step flow and the `docs/plans/` save path unless founder direction reverses.
2. Preserve the simplified 6-step flow and the `docs/plans/` save path unless operator direction reverses.
3. Bump `last_upstream_check` in `SKILL.md` frontmatter.
@@ -50,7 +50,7 @@ Watch for upstream changes to:
When upstream changes:
1. Pull non-conflicting changes into the OpenRig copy.
2. Preserve the batch-with-checkpoint structure unless founder direction reverses.
2. Preserve the batch-with-checkpoint structure unless operator direction reverses.
3. Re-check that the subagent-alternative pointer hasn't crept back in.
4. Bump `last_upstream_check` in `SKILL.md` frontmatter.
5. Note any structural shape changes in `divergence_notes`.
@@ -4,9 +4,12 @@ description: Create distinctive, production-grade frontend interfaces with high
license: Complete terms in LICENSE.txt
metadata:
openrig:
vendored_from: "Anthropic skills (Apache 2.0; see LICENSE.txt sibling)"
vendoring_pattern: vendored-as-is
last_upstream_check: "2026-05-13 (diff against ~/.claude/skills/frontend-design = identical)"
stage: factory-approved
license_status: "see LICENSE.txt — vendor-derived; license terms apply"
vendored_from: "unknown vendor — LICENSE.txt present at copy time; quarterly license review"
sibling_skills:
- shadcn
- remotion-best-practices
---
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
@@ -16,7 +16,7 @@ Write the test first. Watch it fail. Write minimal code to pass.
**Core principle:** If you didn't watch the test fail, you don't know if it tests the right thing.
**Violating the letter of the rules is violating the spirit of the rules.**
**A strong default in service of shipping — not a law that outranks it.** TDD earns its keep where a failing test pins down behavior you'd otherwise get wrong: core logic, contracts, tricky edge cases. Match it to stakes — reach for it where test-first genuinely de-risks the change; throwaway prototypes, one-line copy tweaks, and obvious glue don't need the ceremony. Don't dodge it with synonyms; equally, don't let it block you from shipping the working thing.
## When to Use
@@ -44,5 +44,5 @@ Watch upstream for:
When upstream changes:
1. Pull non-conflicting changes into the OpenRig copy.
2. Do NOT re-introduce the multi-platform sections, SUBAGENT-STOP block, or Instruction Priority section unless founder direction reverses.
2. Do NOT re-introduce the multi-platform sections, SUBAGENT-STOP block, or Instruction Priority section unless operator direction reverses.
3. Bump `last_upstream_check` in `SKILL.md` frontmatter.
@@ -16,7 +16,7 @@ Claiming work is complete without verification is dishonesty, not efficiency.
**Core principle:** Evidence before claims, always.
**Violating the letter of this rule is violating the spirit of this rule.**
**This rule serves shipping — it is not a ritual that outranks it.** It governs one thing: *claims that a verifiable result holds* ("tests pass", "build succeeds", "bug fixed") — run the check before you assert it, and scale the check to the stakes (a one-line copy tweak is not a test-suite ceremony). Don't dodge it with synonyms; equally, don't inflate it into a tax on the word "done" or a reason to keep re-proving instead of shipping the working thing.
## The Iron Law
@@ -57,7 +57,7 @@ Skip any step = lying, not verifying
## Red Flags - STOP
- Using "should", "probably", "seems to"
- Expressing satisfaction before verification ("Great!", "Perfect!", "Done!", etc.)
- Claiming a specific result is *proven* ("tests pass", "it's fixed", "build's green") before running the check in this message — enthusiasm itself is fine; an unverified **result claim** is the flag
- About to commit/push/PR without verification
- Trusting agent success reports
- Relying on partial verification
@@ -110,6 +110,16 @@ Skip any step = lying, not verifying
❌ Trust agent report
```
## When the check itself lies — content over shape
Running a verification is necessary but not sufficient: a check can exit clean and still prove nothing. These are the named ways a green check lies — the failure siblings behind "evidence before claims." (Deeper treatment of *what* you verify against: `reference-first-verification`.)
- **Assert on CONTENT, never shape or count.** Output that *looks* like success — a non-zero count, a clean exit, no error text — can carry failure as its content. Before trusting a check, ask what its output looks like *when it fails*: if failure and success are indistinguishable at a glance, the check proves nothing. (`[1 lines]` and `No matches found` both read as "a match" to a line-count.)
- **Compare the returned value to the value you PASSED — never to a description of it.** A confident label (`evidenceRef NOW SET:` printed above the untouched original) is indistinguishable from a verification in a transcript. Diff the actual result against your actual input, not against a claim about it.
- **Find the untested axis.** Thorough coverage of ONE axis reads as thorough coverage overall. Ask what every one of your tests shares — a healthy manifest, a default option value, the happy path — and treat that shared assumption as the dimension you never tested. (A 15-case "exhaustive" harness whose only defect lived on the one axis every case held constant.)
- **A syntax check proves parseability and nothing else.** A clean `node --check` / lint / parse pass is the *covered* axis; boot and runtime are the untested one. Parseable ≠ sound.
- **A failure whose shape is a HANG reports nothing.** A bare `await` against a stated deadline that never re-checks cannot fail loudly. Race it against a timer so failure has a shape you can see.
## Why This Matters
From 24 failure memories:
@@ -47,6 +47,6 @@ Watch upstream for:
When upstream changes:
1. Pull non-conflicting changes into the OpenRig copy.
2. Preserve the `docs/plans/` save path and the absence of the Scope Check + File Structure sections unless founder direction reverses.
2. Preserve the `docs/plans/` save path and the absence of the Scope Check + File Structure sections unless operator direction reverses.
3. Re-check that the subagent-driven-development pointer hasn't crept back in.
4. Bump `last_upstream_check` in `SKILL.md` frontmatter.
@@ -11,10 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user, openrig-architect, brainstorming, requirements-writer]
skills: [openrig-architect, brainstorming, requirements-writer]
guidance: [role]
subagents: []
plugins: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -35,10 +35,11 @@ hand off.
Long advising sessions hit context limits. The discipline is
externalize-state-to-durable-substrate, not in-context recall:
recover identity via `rig whoami --json`; recover recent peer
context via `rig transcript <session> --tail` / `--grep`; recover
in-flight work via `rig queue list --as <me>`. Hand off load-bearing
decisions to the queue so a fresh-context advisor can pick them up.
recover identity via `rig whoami --json`; recover in-flight work from
restore maps, current `MISSION_NOTES.md`, and owned queue items. Use
`rig transcript <session> --tail` / `--grep` only as a secondary check;
little or no output does not prove the session was quiet. Hand off
load-bearing decisions to the queue so a fresh-context advisor can pick them up.
If the operator has installed a richer compaction-survival skill on
this host (substrate skill path or `~/.openrig/skills/`), load it
for more detail.
@@ -11,10 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user, openrig-operator, rig-lifecycle, systematic-debugging, verification-before-completion, openrig-installer]
skills: [rig-lifecycle, openrig-upgrade, systematic-debugging, verification-before-completion]
guidance: [role]
subagents: []
plugins: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -18,11 +18,9 @@ with them and escalate to them when ops decisions need human approval.
4. Confirm healthy via `rig ps --nodes --rig <name>`.
- Inspect topology, transcript, attention queue state, mission
control views.
- Shepherd install / upgrade / migration ceremonies. The
`openrig-installer` skill is your reference for the V0.3.1
upgrade flow (which includes the substrate-kernel → daemon-managed
kernel migration as a one-time ceremony — see openrig-installer
for the canonical steps).
- Shepherd current install and upgrade work. Use the `openrig-upgrade`
skill for the supported upgrade path and verify the resulting daemon
and rig health before declaring the operation complete.
## What you do NOT do
@@ -11,10 +11,10 @@ imports:
profiles:
default:
uses:
skills: [openrig-user]
skills: []
guidance: [role]
subagents: []
plugins: []
plugins: [shared:openrig-core]
runtime_resources: [shared:claude-default-settings, shared:claude-default-mcp, shared:codex-default-config]
resources:
@@ -46,10 +46,9 @@ machine and have things happen.
and surfaces a 3-part error (fact / reason / fix) per the
building-agent-software skill discipline. No best-effort
half-booted state.
- **Migration ceremony is part of the upgrade.** V0.3.1 ships the
kernel as a daemon-managed built-in; operators with a pre-existing
substrate-rooted kernel migrate as a one-time step during the
V0.3.1 install (openrig-installer skill walks this).
- **Use the current upgrade path.** The operator loads `openrig-upgrade`,
follows the supported migration guidance for the installed version,
and verifies daemon plus rig health before closing the operation.
- **Skills earn their slot.** Each agent loads a lean roster at
startup (per HOST-TOPOLOGY §4.10); the rest are reachable on demand
via find-skills.
@@ -102,6 +102,44 @@ export class PluginVendorService {
}
}
/** Project one plugin skill into the harness-global skill roots. */
ensureSkillGlobally(
pluginName: string,
skillName: string,
globalSkillRoots: string[],
): void {
const sourceDir = nodePath.join(
this.userPluginsDir,
pluginName,
"skills",
skillName,
);
if (!this.fs.exists(sourceDir)) {
throw new Error(
`Required global seed '${skillName}' is missing from plugin '${pluginName}'`,
);
}
const files = this.fs.listFiles(sourceDir);
for (const root of globalSkillRoots) {
const targetDir = nodePath.join(root, skillName);
this.fs.mkdirp(targetDir);
for (const relPath of files) {
const srcPath = nodePath.join(sourceDir, relPath);
const destPath = nodePath.join(targetDir, relPath);
const content = this.fs.readFile(srcPath);
if (
this.fs.exists(destPath) &&
hashContent(this.fs.readFile(destPath)) === hashContent(content)
) {
continue;
}
this.fs.mkdirp(nodePath.dirname(destPath));
this.fs.writeFile(destPath, content);
}
}
}
/**
* Attempt to fetch the latest plugin tree from
* github.com/mvschwarz/openrig-plugins. Tolerates 404, network errors,
+4
View File
@@ -625,6 +625,10 @@ export async function createDaemon(opts?: DaemonOptions): Promise<DaemonResult>
logger: (...args) => console.log("[openrig]", ...args),
});
await vendorService.ensureLatest("openrig-core");
vendorService.ensureSkillGlobally("openrig-core", "openrig-skills", [
nodePath.join(os.homedir(), ".claude", "skills"),
nodePath.join(os.homedir(), ".agents", "skills"),
]);
} catch (err) {
console.error(`[openrig] plugin vendor setup warning: ${(err as Error).message}`);
}
@@ -163,11 +163,56 @@ describe("control-plane JSON generator", () => {
});
expect(layout.skills["stale-only"]).toBeUndefined();
expect(layout.skills.future).toEqual({
edges: ["plugin", "spec"],
edges: ["canonical", "plugin", "spec"],
category: "process",
});
});
it("projects spec overrides onto the canonical mirror edge", async () => {
const generator = await loadGenerator();
const root = tempRoot();
seedEdges(root);
const layout = await generator.extractSkillEdgeLayout({
repoRoot: root,
config: {
version: 0,
owner: "skills-architect@example",
edges: edgeConfig(),
extract_from_committed_trees: true,
forward_overrides: {
future: { edges: ["spec"], category: "process" },
},
},
});
expect(layout.skills.future).toEqual({
edges: ["canonical", "spec"],
category: "process",
});
});
it("removes an empty-edge override from the generated product layout", async () => {
const generator = await loadGenerator();
const root = tempRoot();
seedEdges(root);
const layout = await generator.extractSkillEdgeLayout({
repoRoot: root,
config: {
version: 0,
owner: "skills-architect@example",
edges: edgeConfig(),
extract_from_committed_trees: true,
forward_overrides: {
alpha: { edges: [], category: null },
},
},
});
expect(layout.skills.alpha).toBeUndefined();
});
it("rejects malformed forward overrides with the source path and reason", async () => {
const generator = await loadGenerator();
const root = tempRoot();
@@ -1,10 +1,7 @@
// OPR.0.4.4.23 (arch S2) — the bundled openrig-core plugin's copy of
// mission-slice-sop must be MECHANICALLY pinned to the canonical product
// skill source: hand-sync without a guard is banned. This is the
// scope-audit-copies pattern (byte-parity CI test) applied to the skill —
// the mirror-skills script covers specs → skills/_canonical, and this test
// covers specs → the bundled plugin. Any edit to one copy fails here until
// the other copy is refreshed (cp, byte-for-byte).
// OPR.0.4.4.23 originally pinned duplicate spec/plugin copies. The vendoring
// placement ruling now makes mission-slice-sop and openrig-user plugin-only:
// universal delivery comes from openrig-core, so recreating a spec copy would
// reintroduce the drift this guard was meant to prevent.
import { describe, expect, it } from "vitest";
import fs from "node:fs";
@@ -14,61 +11,28 @@ import { fileURLToPath } from "node:url";
const here = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(here, "..", "..", "..");
const CANONICAL_SOURCE = path.join(
repoRoot,
"packages/daemon/specs/agents/shared/skills/core/mission-slice-sop/SKILL.md",
);
const PLUGIN_COPY = path.join(
repoRoot,
"packages/daemon/assets/plugins/openrig-core/skills/mission-slice-sop/SKILL.md",
);
// aa922842 — openrig-user is the SECOND skill whose canonical and bundled-plugin copies both
// carry the conventions pointer, so the dual-context rewrite edits both. Unlike
// mission-slice-sop it had NO byte-parity guard: mirror-skills covers specs → _canonical, and
// the S2 test above covered specs → plugin for exactly one skill. Verified by negative search
// over packages/*/test (openrig-core-plugin.test.ts asserts tree existence, not byte parity;
// skill-audit.test.ts has no equality assertion). Editing an unguarded pair is how the repo
// ends up correct while the shipped plugin ships stale — pin it before touching it.
const PARITY_PINNED_SKILLS = ["mission-slice-sop", "openrig-user"] as const;
function canonicalPath(skill: string): string {
return path.join(repoRoot, `packages/daemon/specs/agents/shared/skills/core/${skill}/SKILL.md`);
}
function pluginPath(skill: string): string {
return path.join(repoRoot, `packages/daemon/assets/plugins/openrig-core/skills/${skill}/SKILL.md`);
}
describe("OPR.0.4.4.23 mission-slice-sop plugin byte-parity (S2 drift guard)", () => {
it("both copies exist", () => {
expect(fs.existsSync(CANONICAL_SOURCE), `missing ${CANONICAL_SOURCE}`).toBe(true);
expect(fs.existsSync(PLUGIN_COPY), `missing ${PLUGIN_COPY}`).toBe(true);
});
it("the bundled plugin copy is byte-identical to the canonical skill source", () => {
const source = fs.readFileSync(CANONICAL_SOURCE);
const plugin = fs.readFileSync(PLUGIN_COPY);
expect(
source.equals(plugin),
"mission-slice-sop drifted between the canonical skill source and the bundled plugin — refresh the plugin copy byte-for-byte (cp source → plugin); hand-edited divergence is banned (OPR.0.4.4.23 S2)",
).toBe(true);
});
});
describe("aa922842 canonical→plugin byte-parity, extended to every conventions-carrying skill", () => {
for (const skill of PARITY_PINNED_SKILLS) {
it(`${skill}: canonical and bundled plugin copies both exist`, () => {
expect(fs.existsSync(canonicalPath(skill)), `missing ${canonicalPath(skill)}`).toBe(true);
expect(fs.existsSync(pluginPath(skill)), `missing ${pluginPath(skill)}`).toBe(true);
});
it(`${skill}: bundled plugin copy is byte-identical to canonical`, () => {
const source = fs.readFileSync(canonicalPath(skill));
const plugin = fs.readFileSync(pluginPath(skill));
expect(
source.equals(plugin),
`${skill} drifted between the canonical skill source and the bundled plugin — refresh the plugin copy byte-for-byte (cp source → plugin). mirror-skills does NOT cover this pair; hand-edited divergence is banned.`,
).toBe(true);
describe("OPR.0.4.7 vendoring — universal skills have one plugin home", () => {
for (const skill of ["mission-slice-sop", "openrig-user"] as const) {
it(`${skill}: ships from the plugin and has no spec/canonical duplicate`, () => {
const plugin = path.join(
repoRoot,
`packages/daemon/assets/plugins/openrig-core/skills/${skill}/SKILL.md`,
);
const spec = path.join(
repoRoot,
`packages/daemon/specs/agents/shared/skills/core/${skill}/SKILL.md`,
);
const canonical = path.join(
repoRoot,
`skills/_canonical/core/${skill}/SKILL.md`,
);
expect(fs.existsSync(plugin), `missing ${plugin}`).toBe(true);
expect(fs.existsSync(spec), `redundant spec copy ${spec}`).toBe(false);
expect(fs.existsSync(canonical), `redundant canonical copy ${canonical}`).toBe(false);
});
}
});
@@ -106,8 +70,8 @@ function readDescription(file: string): string {
}
describe("aa922842 mission-slice-sop description budget + trigger preservation", () => {
it(`the canonical description fits the ${DESCRIPTION_BUDGET_BYTES}-byte retrieval budget`, () => {
const description = readDescription(CANONICAL_SOURCE);
it(`the shipped description fits the ${DESCRIPTION_BUDGET_BYTES}-byte retrieval budget`, () => {
const description = readDescription(PLUGIN_COPY);
const bytes = Buffer.byteLength(description, "utf-8");
expect(
bytes,
@@ -116,7 +80,7 @@ describe("aa922842 mission-slice-sop description budget + trigger preservation",
});
it("every named trigger term survives the trim", () => {
const description = readDescription(CANONICAL_SOURCE).toLowerCase();
const description = readDescription(PLUGIN_COPY).toLowerCase();
const missing = REQUIRED_TRIGGERS.filter((t) => !description.includes(t.toLowerCase()));
expect(
missing,
@@ -124,9 +88,4 @@ describe("aa922842 mission-slice-sop description budget + trigger preservation",
).toEqual([]);
});
it("the bundled plugin copy carries the same description (budget survives the byte-copy)", () => {
// Byte-parity above already implies this, but asserting it directly means a future
// refactor that relaxes parity cannot silently ship an over-budget installed skill.
expect(readDescription(PLUGIN_COPY)).toBe(readDescription(CANONICAL_SOURCE));
});
});
@@ -18,25 +18,20 @@ import * as nodePath from "node:path";
const PLUGIN_ROOT = nodePath.resolve(import.meta.dirname, "../assets/plugins/openrig-core");
// Skills shipping in openrig-core v0. Slice 29 deleted 4 skills that were
// mis-imports or duplicates:
// - claude-compact-in-place (was a SPEC, not a skill)
// - session-compaction-and-restore (replaced by claude-compaction-restore)
// - permission-posture (internal-only doctrine, not operator-facing)
// - openrig-compaction-instructions (empty leftover from slice 27)
// Remaining: 11 operator-facing skills; slice 32 added mission-slice-sop.
// Tier A is the universal skill spine projected into every shipped/default
// agent CWD. Role-specific skills stay on the spec-selected edge; host-only
// skills do not enter the product edges.
const EXPECTED_SKILLS = [
"agent-startup-and-context-ingestion",
"claude-compaction-restore",
"forming-an-openrig-mental-model",
"messaging-the-human",
"mission-slice-sop",
"openrig-architect",
"openrig-cmux",
"openrig-herdr",
"openrig-operator",
"openrig-skills",
"openrig-user",
"queue-handoff",
"seat-continuity-and-handover",
"session-compaction-and-restore",
"software-for-agents",
];
describe("openrig-core plugin — vendored tree shape (HG-2.1)", () => {
@@ -117,7 +112,7 @@ describe("openrig-core plugin — skills (HG-2.1 skill content per agentskills.i
expect(desc.length).toBeLessThanOrEqual(1024);
});
it("ships exactly the 11 expected skills (no drift; no missing skills; slice 29 deleted 4, slice 32 added mission-slice-sop, OPR.0.4.6.02 added openrig-herdr/openrig-cmux)", () => {
it("ships exactly the Tier-A universal spine", () => {
const skillsDir = nodePath.join(PLUGIN_ROOT, "skills");
const actual = fs.readdirSync(skillsDir).filter((f) =>
fs.statSync(nodePath.join(skillsDir, f)).isDirectory()
@@ -126,9 +121,42 @@ describe("openrig-core plugin — skills (HG-2.1 skill content per agentskills.i
expect(actual.sort()).toEqual([...EXPECTED_SKILLS].sort());
});
it("routes openrig-user readers through the global skill index", () => {
const userSkill = fs.readFileSync(
nodePath.join(PLUGIN_ROOT, "skills", "openrig-user", "SKILL.md"),
"utf-8",
);
expect(userSkill).toContain("openrig-skills");
});
it("gives a bare installed agent a resolvable one-hop path for every shipped skill", () => {
const index = fs.readFileSync(
nodePath.join(PLUGIN_ROOT, "skills", "openrig-skills", "SKILL.md"),
"utf-8",
);
const layout = JSON.parse(fs.readFileSync(
nodePath.resolve(import.meta.dirname, "../../../scripts/skill-edge-layout.generated.json"),
"utf-8",
)) as {
skills: Record<string, { edges: string[]; category: string | null }>;
};
expect(index).toContain("OPENRIG_CLI_ROOT");
for (const [skillId, placement] of Object.entries(layout.skills)) {
if (placement.edges.includes("plugin")) {
expect(index).toContain(`~/.openrig/plugins/openrig-core/skills/${skillId}/SKILL.md`);
} else {
expect(placement.category).not.toBeNull();
expect(index).toContain(
`\${OPENRIG_CLI_ROOT}/daemon/specs/agents/shared/skills/${placement.category}/${skillId}/SKILL.md`,
);
}
}
});
it("routes rig authors through the advisory spec audit in the skill and startup guide", () => {
const architectSkill = fs.readFileSync(
nodePath.join(PLUGIN_ROOT, "skills", "openrig-architect", "SKILL.md"),
nodePath.resolve(import.meta.dirname, "../specs/agents/shared/skills/core/openrig-architect/SKILL.md"),
"utf-8",
);
const startupGuide = fs.readFileSync(
@@ -40,6 +40,7 @@ function mockFs(initialFiles?: Record<string, string>) {
const VENDORED_OPENRIG_CORE = {
"/asset-root/openrig-core/.claude-plugin/plugin.json": '{"name":"openrig-core","version":"0.1.0"}',
"/asset-root/openrig-core/.codex-plugin/plugin.json": '{"name":"openrig-core","version":"0.1.0","description":"v"}',
"/asset-root/openrig-core/skills/openrig-skills/SKILL.md": "# openrig-skills index",
"/asset-root/openrig-core/skills/openrig-user/SKILL.md": "# openrig-user vendored",
"/asset-root/openrig-core/hooks/claude.json": '{"hooks":{}}',
};
@@ -69,6 +70,7 @@ describe("PluginVendorService — vendoring (HG-2.3)", () => {
...VENDORED_OPENRIG_CORE,
"/home/test/.openrig/plugins/openrig-core/.claude-plugin/plugin.json": '{"name":"openrig-core","version":"0.1.0"}',
"/home/test/.openrig/plugins/openrig-core/.codex-plugin/plugin.json": '{"name":"openrig-core","version":"0.1.0","description":"v"}',
"/home/test/.openrig/plugins/openrig-core/skills/openrig-skills/SKILL.md": "# openrig-skills index",
"/home/test/.openrig/plugins/openrig-core/skills/openrig-user/SKILL.md": "# openrig-user vendored",
"/home/test/.openrig/plugins/openrig-core/hooks/claude.json": '{"hooks":{}}',
});
@@ -103,6 +105,45 @@ describe("PluginVendorService — vendoring (HG-2.3)", () => {
await expect(svc.ensureVendored("nonexistent-plugin")).resolves.not.toThrow();
expect(fs._store["/home/test/.openrig/plugins/nonexistent-plugin/anything"]).toBeUndefined();
});
it("projects a plugin seed skill into both harness-global skill roots", async () => {
const fs = mockFs(VENDORED_OPENRIG_CORE);
const svc = new PluginVendorService({
vendoredAssetsDir: "/asset-root",
userPluginsDir: "/home/test/.openrig/plugins",
fs,
httpClient: vi.fn().mockResolvedValue({ ok: false, status: 404 }),
logger: vi.fn(),
});
await svc.ensureVendored("openrig-core");
svc.ensureSkillGlobally("openrig-core", "openrig-skills", [
"/home/test/.claude/skills",
"/home/test/.agents/skills",
]);
expect(fs._store["/home/test/.claude/skills/openrig-skills/SKILL.md"]).toBe("# openrig-skills index");
expect(fs._store["/home/test/.agents/skills/openrig-skills/SKILL.md"]).toBe("# openrig-skills index");
});
it("fails loudly when the required global seed is missing from the vendored plugin", async () => {
const fs = mockFs(VENDORED_OPENRIG_CORE);
const svc = new PluginVendorService({
vendoredAssetsDir: "/asset-root",
userPluginsDir: "/home/test/.openrig/plugins",
fs,
httpClient: vi.fn().mockResolvedValue({ ok: false, status: 404 }),
logger: vi.fn(),
});
await svc.ensureVendored("openrig-core");
expect(() =>
svc.ensureSkillGlobally("openrig-core", "missing-seed", [
"/home/test/.claude/skills",
"/home/test/.agents/skills",
]),
).toThrow(/missing-seed/);
});
});
describe("PluginVendorService — auto-fetch (HG-2.4 + HG-2.5)", () => {
@@ -317,6 +317,9 @@ profiles:
expect(existsSync(assetPath)).toBe(true);
const content = readFileSync(assetPath, "utf8");
expect(content).toContain("thin bootstrap overlay");
expect(content).toContain("openrig-skills");
expect(content).toContain("~/.claude/skills/openrig-skills/SKILL.md");
expect(content).toContain("~/.agents/skills/openrig-skills/SKILL.md");
expect(content).toContain("openrig-user");
expect(content).toContain("current project or workspace");
expect(content).toContain("usually sees it under `.claude/skills/openrig-user/SKILL.md`");
@@ -48,6 +48,14 @@ const KERNEL_AGENT_SPECS = [
"rigs/launch/kernel/agents/queue/worker/agent.yaml",
];
const RUNNABLE_SHIPPED_AGENT_SPECS = [
...AGENT_SPECS,
"agents/factory-rsi/dogfood/agent.yaml",
"agents/factory-rsi/release-manager/agent.yaml",
"agents/product-management/pm/agent.yaml",
...KERNEL_AGENT_SPECS,
];
// bug-fix slice deprecation-check-keys-widening — IMPL-PRD §1.2 + §3.
// Allowlist of removed/deprecated KEY paths the spec library MUST NOT
// carry. Each entry uses dot-path notation with `*` as a profile-name
@@ -356,7 +364,7 @@ describe("Starter specs", () => {
});
it("openrig-user documents agent-managed apps and current cwd/env operation", () => {
const content = readFileSync(join(SPECS_ROOT, "agents/shared/skills/core/openrig-user/SKILL.md"), "utf-8");
const content = readFileSync(join(import.meta.dirname, "../assets/plugins/openrig-core/skills/openrig-user/SKILL.md"), "utf-8");
expect(content).toContain("agent-managed app");
expect(content).toContain("rig up secrets-manager");
@@ -382,7 +390,6 @@ describe("Starter specs", () => {
"dogfood",
"executing-plans",
"frontend-design",
"openrig-user",
"orchestration-team",
"development-team",
"review-team",
@@ -400,6 +407,15 @@ describe("Starter specs", () => {
}
const deprecatedHaSkill = ["mental", "model", "ha"].join("-");
expect(sharedSkills.map((entry) => entry.id)).not.toContain(deprecatedHaSkill);
expect(sharedSkills.map((entry) => entry.id)).not.toContain("openrig-operator");
expect(sharedSkills.map((entry) => entry.id)).not.toContain("openrig-user");
expect(sharedSkills.map((entry) => entry.id)).not.toContain("mission-slice-sop");
for (const skill of sharedSkills) {
expect(
existsSync(join(SPECS_ROOT, "agents/shared", skill.path, "SKILL.md")),
`missing shared skill resource ${skill.id} at ${skill.path}`,
).toBe(true);
}
const sharedRuntimeResources = (sharedResources["runtime_resources"] as Array<{ id: string; path: string; type: string }>) ?? [];
for (const resourceId of ["claude-default-settings", "claude-default-mcp", "codex-default-config"]) {
@@ -438,39 +454,39 @@ describe("Starter specs", () => {
const expectedAgentSkills = new Map<string, string[]>([
[
"agents/conveyor/lead/agent.yaml",
["openrig-user", "orchestration-team", "backlog-capture", "writing-plans", "executing-plans", "verification-before-completion", "brainstorming"],
["orchestration-team", "backlog-capture", "writing-plans", "executing-plans", "verification-before-completion", "brainstorming"],
],
[
"agents/conveyor/planner/agent.yaml",
["openrig-user", "requirements-writer", "context-builder", "writing-plans", "verification-before-completion"],
["requirements-writer", "context-builder", "writing-plans", "verification-before-completion"],
],
[
"agents/conveyor/builder/agent.yaml",
["openrig-user", "development-team", "test-driven-development", "systematic-debugging", "executing-plans", "verification-before-completion"],
["development-team", "test-driven-development", "systematic-debugging", "executing-plans", "verification-before-completion"],
],
[
"agents/conveyor/reviewer/agent.yaml",
["openrig-user", "review-team", "plan-review", "systematic-debugging", "verification-before-completion"],
["review-team", "plan-review", "systematic-debugging", "verification-before-completion"],
],
[
"agents/design/product-designer/agent.yaml",
["using-superpowers", "openrig-user", "development-team", "frontend-design", "brainstorming", "writing-plans", "verification-before-completion"],
["using-superpowers", "development-team", "frontend-design", "brainstorming", "writing-plans", "verification-before-completion"],
],
[
"agents/development/implementer/agent.yaml",
["using-superpowers", "openrig-user", "development-team", "test-driven-development", "systematic-debugging", "writing-plans", "executing-plans", "verification-before-completion"],
["using-superpowers", "development-team", "test-driven-development", "systematic-debugging", "writing-plans", "executing-plans", "verification-before-completion"],
],
[
"agents/development/qa/agent.yaml",
["using-superpowers", "openrig-user", "development-team", "systematic-debugging", "agent-browser", "dogfood", "writing-plans", "executing-plans", "verification-before-completion"],
["using-superpowers", "development-team", "systematic-debugging", "agent-browser", "dogfood", "writing-plans", "executing-plans", "verification-before-completion"],
],
[
"agents/review/independent-reviewer/agent.yaml",
["using-superpowers", "openrig-user", "review-team", "systematic-debugging", "brainstorming", "writing-plans", "verification-before-completion"],
["using-superpowers", "review-team", "systematic-debugging", "brainstorming", "writing-plans", "verification-before-completion"],
],
[
"agents/orchestration/orchestrator/agent.yaml",
["using-superpowers", "openrig-user", "orchestration-team", "systematic-debugging", "brainstorming", "writing-plans", "executing-plans", "verification-before-completion"],
["using-superpowers", "orchestration-team", "systematic-debugging", "brainstorming", "writing-plans", "executing-plans", "verification-before-completion"],
],
]);
@@ -484,12 +500,48 @@ describe("Starter specs", () => {
const defaultProfile = profiles["default"] ?? {};
const uses = (defaultProfile["uses"] as Record<string, unknown> | undefined) ?? {};
const skills = (uses["skills"] as string[] | undefined) ?? [];
for (const skillId of expectedAgentSkills.get(file) ?? ["openrig-user"]) {
for (const skillId of expectedAgentSkills.get(file) ?? []) {
expect(skills).toContain(skillId);
}
}
});
it("declares the vendored openrig-core plugin once in the shared resource pool", () => {
const shared = parseYaml(
readFileSync(join(SPECS_ROOT, SHARED_AGENT_SPEC), "utf-8"),
) as {
resources?: {
plugins?: Array<{
id: string;
source: { kind: string; path: string };
}>;
};
};
expect(shared.resources?.plugins ?? []).toContainEqual({
id: "openrig-core",
source: {
kind: "local",
path: "~/.openrig/plugins/openrig-core",
},
});
});
it("all 18 runnable shipped default profiles explicitly select openrig-core", () => {
expect(RUNNABLE_SHIPPED_AGENT_SPECS).toHaveLength(18);
const missing = RUNNABLE_SHIPPED_AGENT_SPECS.filter((file) => {
const raw = parseYaml(readFileSync(join(SPECS_ROOT, file), "utf-8")) as {
profiles?: Record<string, { uses?: { plugins?: string[] } }>;
};
return !raw.profiles?.default?.uses?.plugins?.includes(
"shared:openrig-core",
);
});
expect(missing).toEqual([]);
});
it("starter role guidance explicitly names every packaged default skill it expects agents to load", () => {
for (const file of STARTER_AGENT_SPECS) {
const yaml = readFileSync(join(SPECS_ROOT, file), "utf-8");
+1 -4
View File
@@ -1,9 +1,7 @@
#!/usr/bin/env bash
# OPR.0.4.4.13 FR-3 — product-factory VPS bootstrap (runs ON the VPS).
#
# Fresh Ubuntu -> factory-ready: the 2026-06-23 OVH smoke test's manual
# sequence, productized. Pairs with docs/reference/product-factory-vps-runbook.md
# (read it first: Tailscale tag/ACL setup and the home-base steps live there).
# Fresh Ubuntu -> factory-ready: the smoke-tested manual sequence, productized.
#
# Usage (as root on a fresh Ubuntu 22.04/24.04 VPS):
# ./bootstrap-product-factory-vps.sh --artifact <@openrig/[email protected] | /path/to/openrig-cli.tgz> \
@@ -110,5 +108,4 @@ VPS side complete. From the HOME BASE now:
3. rig host doctor <id> --posture product-factory-vps [--public-addr <public-ip>]
4. Remove the public-SSH escape hatch once the tailnet path is verified:
sudo ufw delete allow OpenSSH # on the VPS
Runbook: docs/reference/product-factory-vps-runbook.md
EOF
+23
View File
@@ -17,6 +17,29 @@ test("npm pack of @openrig/cli includes scripts/check-abi.mjs in tarball", () =>
);
});
test("the private product-factory VPS runbook and its pointers do not ship", () => {
const privateRunbook = "docs/reference/product-factory-vps-runbook.md";
assert.equal(
existsSync(privateRunbook),
false,
`${privateRunbook} is private operator canon and must not ship in the public repo or package`,
);
const publicPointerSources = [
"CHANGELOG.md",
"scripts/bootstrap-product-factory-vps.sh",
"docs/as-built/cli-reference.md",
"packages/daemon/assets/plugins/openrig-core/skills/openrig-user/SKILL.md",
];
for (const source of publicPointerSources) {
assert.doesNotMatch(
readFileSync(source, "utf8"),
/product-factory-vps-runbook/,
`${source} still points public readers at the private VPS runbook`,
);
}
});
// aa922842 — the conventions doc reaches agents through a THREE-path model:
// repo source docs/reference/sdlc-conventions.md (what repo readers cite)
// packed INTERNAL daemon/docs/reference/sdlc-conventions.md (assembly input only —
+5 -2
View File
@@ -6,7 +6,11 @@
"/Users/wrandom/",
"~/code/substrate/",
"code/substrate/shared-docs/",
".openrig/"
".openrig/artifacts/",
".openrig/compaction/",
".openrig/backups/",
".openrig/agent-images/",
".openrig/secrets/"
],
"seat_and_rig_patterns": [
"@skill-library",
@@ -31,7 +35,6 @@
"vm-claude-test"
],
"charged_terms": [
"dogfood",
"founder",
"founder-owned host",
"one open trust domain",
+16 -2
View File
@@ -6,7 +6,20 @@
"clean": [
"mission-slice-sop",
"openrig-cmux",
"openrig-herdr"
"openrig-herdr",
"messaging-the-human",
"software-for-agents",
"openrig-skills",
"orchestration-team",
"development-team",
"review-team",
"office-hours",
"context-builder",
"requirements-writer",
"ui-mockup",
"plan-review",
"exec-summary",
"backlog-capture"
],
"ship_after_fix": [
"openrig-user",
@@ -14,7 +27,8 @@
"queue-handoff",
"seat-continuity-and-handover",
"claude-compaction-restore",
"openrig-architect"
"openrig-architect",
"agent-startup-and-context-ingestion"
],
"ship_misses_add": [
"topology-mutation-and-seat-management",
+59 -48
View File
@@ -2,15 +2,21 @@
"version": 1,
"edges": {
"canonical": {
"core/mission-slice-sop/SKILL.md": "d195ef466ddd09944ad4ddb073fa1c5e5f809c8167ac72d1a3b3277314321930",
"core/openrig-architect/SKILL.md": "12c3ddb129cd82b304b24eb7330970c6008ce00e42badfe2961967424f2ca45e",
"core/openrig-cmux/SKILL.md": "f54d9b0a0cf42fc9617ab26bb1a45d8b28b982091dbb4332d68b2ebda7d09208",
"core/openrig-herdr/SKILL.md": "9301cdff9734dfaffe400c11733168a82154814023e6e021550fe28b392ef9a8",
"core/openrig-installer/SKILL.md": "362bf919ff91dc083550e4fa2583ec349187d3ed9e0ec5443d49b704cb900e80",
"core/openrig-operator/SKILL.md": "69d5a61f708a69b7d28aeddcd4bda0fbaec26bd4cc9f5f808bf1db16b7d8cf84",
"core/openrig-user/SKILL.md": "a0af630b0126c870a4c9ebecb0f7df0058bae63c826a932a3b09d59f9516e5e1",
"core/openrig-user-settings/SKILL.md": "a9650e93a669d65cabcb61409f2812bdf4a27672ba8c077c6f94fa704656fe34",
"core/rig-lifecycle/SKILL.md": "dde7165d9c1718a154684326ea36d239b82b692b1eb8c97d65f2813a5eb82aa4",
"core/agent-starters/SKILL.md": "dd11173ea046dd7d30e23c4fdb3f5188b003ca56ea434ebcc21e14f5e8f29b15",
"core/agent-startup-and-context-ingestion/SKILL.md": "36b6d8f56a911c0515ee2ab99a862cb6c466c4d822bce19479293a5dbf31dca4",
"core/attention-queue/SKILL.md": "c3faabc016bc169ed9a4724571582db8b0ba74b921baccd31342b6efc0ddb945",
"core/cross-host-rig-commands/SKILL.md": "77305c443fb7df11a2df73e33e46b7173cd12d6899a7dec1a12b2118d85bcf02",
"core/human-in-the-loop/SKILL.md": "0175b1f5494ad9872f3516ccf8a935cb83af054a60df1bef6b467007c1451426",
"core/openrig-architect/SKILL.md": "b53e63d22989bb6cc2da30a79e69902ce57a109145027a4007a900fdd66ee747",
"core/openrig-cmux/SKILL.md": "73a86eac45d68b16a38fc0a4438713c634d86061073dac96a4d9e656ea5d34dc",
"core/openrig-herdr/SKILL.md": "37508a02f50bb69ee97c22c37ccf70aa8e37dc0784061eb2a5ad813571eebd1a",
"core/openrig-upgrade/SKILL.md": "9315df9944625d70aa5e251fcfb1ddaa0369cb14fd7dad44bde303564deb6382",
"core/rig-bundles-and-shareable-artifacts/SKILL.md": "e9d5103f419b971373e374474e6ef464e05f242f3fa25e63acfc0b2106651748",
"core/rig-lifecycle/SKILL.md": "8346e01d532795b24c3dba63413ca662c7b44cc5eed39ee2e85568580f40adca",
"core/session-source-fork/SKILL.md": "43004907271759be52436fb7f30678e9632c9794bd34dec5f96f4e929c1107f2",
"core/specification-system/SKILL.md": "5226d6e8b1362df89ba3d5afd82e4b4add355870132ca4b140d7f9f4324ffdc1",
"core/topology-mutation-and-seat-management/SKILL.md": "9ba55ef83d2669c23525f0874d3303a87760f3574bc77d0a53cbca9daae295ea",
"core/watchdog/SKILL.md": "58c6ff3ce08a82ca2ff796b1c887e6832562a9ee18fee8fbfe197a5160429697",
"pm/backlog-capture/SKILL.md": "345c2b47fc85e48c15c0d42bbb48fb27dd3b0ceec36bf59dc6ed20daaea47a84",
"pm/context-builder/SKILL.md": "0134c9b0a9f196565109f7f51b6ec78d5c3e4b5982a0d7105a93b29952625b3c",
"pm/exec-summary/SKILL.md": "9c06b089b4dec325b1be12b261d6a1984627808915818259d63cbf83a5448352",
@@ -19,20 +25,20 @@
"pm/requirements-writer/SKILL.md": "01e84e3b1fd6eb37754e45d7ba72488458c427961ec1c35a4fba4c07adc8c80d",
"pm/ui-mockup/SKILL.md": "b527c72c73c926c3d2a61e1264279486737d429aa85d3624c4adc364c577afc8",
"pods/development-team/SKILL.md": "8bec17cadc8bd4f06ff3593bd802e4103f08124c118c41cb1eb066e58e71ebd7",
"pods/orchestration-team/SKILL.md": "08b87a6f73a1f163dcbefadc39adbf0c42d391b68a693e1de44ce08ac69fa312",
"pods/review-team/SKILL.md": "1f8ad4dc3960350c373faf77e3ea90d22970766b6aa634dbbfaa765feeafe063",
"pods/orchestration-team/SKILL.md": "eca2c8ef8df04aaae8f3094192b964235fd31b00753ad8752614127b5921b784",
"pods/review-team/SKILL.md": "97da8b474c289f76a2c48f9d46191f3adc4e3231ae8a49ff23452e1f852e0474",
"process/agent-browser/LOCAL-INSIGHTS.md": "e793e30464517bfe0eee3485fb03206292338552cf7ccaadb1713e39bf21b043",
"process/agent-browser/OPENRIG.md": "d15123689824c934b51ba572bc7c4d995651e2f606e0e53697263f4ecde108c9",
"process/agent-browser/SKILL.md": "f2709bae71a8c60f6a4b80a6873560cdea9632000ed4b28d082dfae58801199b",
"process/brainstorming/OPENRIG.md": "608f4b913e482dc12a4d201ece1d265dff1d2bfc7d609c2f11f71cb06d5cfbbe",
"process/brainstorming/OPENRIG.md": "583e9bfbfb01392922afbb59c178c91d8db92a1340ae218c048f251886bd04d9",
"process/brainstorming/SKILL.md": "f65187f40745b2016332f426a44db5884687d71e53ea0883c5da992e6e66b802",
"process/dogfood/SKILL.md": "8addc5d22813193649e8286b354ae2282975d75f1dda6d5d4b33d6ace47f438b",
"process/dogfood/references/issue-taxonomy.md": "dee7e925f7fe001903de6cc14f9656bcda90d069bbf65a2273f22202efebba09",
"process/dogfood/templates/dogfood-report-template.md": "55eef9286e32e595dcfca30db76352e9f1d149a78b60b54644eb701072364f35",
"process/executing-plans/OPENRIG.md": "351f388447a01a27fbc35f08d278da635a922b54d7fded9859aaebbb0eb3eec1",
"process/executing-plans/OPENRIG.md": "4a52d0ecdd44078be51794f0083d606ce41cdb71c4dfa6dba6146161db1743ba",
"process/executing-plans/SKILL.md": "c73eca0a0f7101b6923c87c8bb1a85c06a9714927e5b8d0b5cf0afbbd8ccc529",
"process/frontend-design/LICENSE.txt": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"process/frontend-design/SKILL.md": "cec3b51520db90c76b044e9bb7645ba6676157dc7b60786a81a97d82dc9395b4",
"process/frontend-design/SKILL.md": "3897488693335f3b350292abe067e9f4a39a64af5ac6b1feb82074a36930273d",
"process/systematic-debugging/CREATION-LOG.md": "b482ef9a918fbfc6c369729e8160633ddfa2332466dd362ee73f1527c239ef8b",
"process/systematic-debugging/SKILL.md": "b2adbca870df5232f018a43f6715c7a97c3ddd9429aefa11f9248a859280c2c5",
"process/systematic-debugging/condition-based-waiting-example.ts": "40ae5ebe497fdf310200e43fe986552546d0a22837c0d39e855db1cfd33eb88e",
@@ -44,41 +50,46 @@
"process/systematic-debugging/test-pressure-1.md": "0b6a915db0054577819834c79be9eb614e97bddba10d73768e1fbe91cfed048a",
"process/systematic-debugging/test-pressure-2.md": "b2030aeffba07050e8ad573ddf87486457c4a016a786bb326235bebd856f2016",
"process/systematic-debugging/test-pressure-3.md": "96b50a52e2c7989c9cf20fb752c47c1e9a3a70dc362f8f7989f8f5b64dac7708",
"process/test-driven-development/SKILL.md": "4ad2e041879cb2708791de1997c9d8e491fef66f29773bb3bd7bc7412b239e8f",
"process/test-driven-development/SKILL.md": "9a46b5891604ba0d6d39d2247bc63fc0c1766da7627b2dfbe0eb263c8e057810",
"process/test-driven-development/testing-anti-patterns.md": "bde453bc258f06543987477c837939afaa774ea2acbd9f308d702fc452bc4283",
"process/using-superpowers/OPENRIG.md": "3af62c62fcab2ff962a5cdf398da3031c9bd4a8fbed6bd8ffc4bf52a0205b403",
"process/using-superpowers/OPENRIG.md": "029812750481653a862f6e17f1c7159c80999e0263956e697a4179e7e7b8fa98",
"process/using-superpowers/SKILL.md": "df82c78ef649dee45f4b3fd3e99bcd48d716411230dbe593902b395abdaa1a6e",
"process/verification-before-completion/SKILL.md": "ecec3b8358b9c4aa95e9331bc68758c81b2ddd6a3f37046436925290eb206bb6",
"process/writing-plans/OPENRIG.md": "cf4d50311b02841938343bb1c25ae38bca24e489396acd52cc987f6b435e26ad",
"process/verification-before-completion/SKILL.md": "65691874228b4d4148b3c0463aa96bb93d9c75c69041a085847a91f2f89df3f0",
"process/writing-plans/OPENRIG.md": "95a1a40dbabe7c364f0e91c0fdedfc8225cfb9677ac98f1fa528c515d92831c6",
"process/writing-plans/SKILL.md": "ab71f8b300a16a7d6eaf6e3c54c97019919199d519d34b4a149c2d8866fbd507"
},
"plugin": {
"agent-startup-and-context-ingestion/SKILL.md": "c1d759ff3ef7edf689706fc1976f1695d1af21421ee4bf4707622a4b28f15f08",
"claude-compaction-restore/SKILL.md": "58602493348d405af3501fe410289b28e12ba54efdebc4a98ce9d818a07aa71b",
"claude-compaction-restore/scripts/precompact-hook.mjs": "be1161c8528f81dcecc7b3f88c17622496e6d8b7c4f376347bf4eb3b37e4d311",
"claude-compaction-restore/SKILL.md": "16e0a2e0ef711872ede33aeacd92e22f8e1b7c851112aecd4133a9004e376722",
"claude-compaction-restore/scripts/precompact-hook.mjs": "3b739a39210985e6aa2da493bfcda58a1587b258440444188e65133b9450ebac",
"claude-compaction-restore/scripts/restore-from-jsonl.mjs": "9de164582eed8270d8e257860d156fade3b1295ca952c23b10d3db8569dd964c",
"claude-compaction-restore/templates/compact-instruction.md": "682c778464517b831902ddc2678c055545899b4751a1d32391ce965d5eb7061d",
"claude-compaction-restore/templates/post-compact-restore-instruction.md": "10a5a7e5e052f3aa000a4209f386dc4eb90a3c2bba449ca685f124714f59e47a",
"forming-an-openrig-mental-model/SKILL.md": "ebadef30569ea07fd27e4cac87104a1ce02fe7a17838e4591c35a9a186e2e7f9",
"mission-slice-sop/SKILL.md": "d195ef466ddd09944ad4ddb073fa1c5e5f809c8167ac72d1a3b3277314321930",
"openrig-architect/SKILL.md": "12c3ddb129cd82b304b24eb7330970c6008ce00e42badfe2961967424f2ca45e",
"openrig-cmux/SKILL.md": "f54d9b0a0cf42fc9617ab26bb1a45d8b28b982091dbb4332d68b2ebda7d09208",
"openrig-herdr/SKILL.md": "9301cdff9734dfaffe400c11733168a82154814023e6e021550fe28b392ef9a8",
"openrig-operator/SKILL.md": "5fa5223914b7242455dec8c47f4c88b2c408257b5be60cd8bfb5f340a819d948",
"openrig-user/SKILL.md": "a0af630b0126c870a4c9ebecb0f7df0058bae63c826a932a3b09d59f9516e5e1",
"queue-handoff/SKILL.md": "d4d5d37fb88c885ea40eb2f06ccdde2584d4b471f04fa0f9ed3059cf5446c3ee",
"seat-continuity-and-handover/SKILL.md": "bd34b87a320cd43eb1bfaea341ce5a78b3178afe07dcbca7fd524066d61212fc"
"forming-an-openrig-mental-model/SKILL.md": "a2767351ca4100f055182320ab413e5ad2d2c5681c6068e42a45481c07ab632c",
"messaging-the-human/SKILL.md": "95484b323586a229d05cc2298a93a1000601dba3d47f0258c245e123fef10a53",
"mission-slice-sop/SKILL.md": "37f0b5918a49722203058f7fa06fd5b21197be055d869c6cc6a7beee855c2e4e",
"openrig-skills/SKILL.md": "f1c3044ff7b9e8930469980acf883bbfaa093bd8c3af0cbb184a98bcf554b44f",
"openrig-user/SKILL.md": "4cf898bd9926132e0426da753bc2caea49644e5e86ff277bf8e20d86f53d94cb",
"queue-handoff/SKILL.md": "9413dd28597beb4f4d4e0c1c195625bf39e559bce963e43ca3797ca448a9f2b9",
"seat-continuity-and-handover/SKILL.md": "4ccf8535e92ce1f282af9b85a630fd6bebebd4750cae53f257818833d306e500",
"session-compaction-and-restore/SKILL.md": "20783614bc278285743f007347ffec4fe40d5d7f28ed5fd4ef0438534785bc06",
"software-for-agents/SKILL.md": "352e0e46a85c4ff74c6c805692de8386281030c8681c7dbd21923bd72bcfa9f8"
},
"spec": {
"core/mission-slice-sop/SKILL.md": "d195ef466ddd09944ad4ddb073fa1c5e5f809c8167ac72d1a3b3277314321930",
"core/openrig-architect/SKILL.md": "12c3ddb129cd82b304b24eb7330970c6008ce00e42badfe2961967424f2ca45e",
"core/openrig-cmux/SKILL.md": "f54d9b0a0cf42fc9617ab26bb1a45d8b28b982091dbb4332d68b2ebda7d09208",
"core/openrig-herdr/SKILL.md": "9301cdff9734dfaffe400c11733168a82154814023e6e021550fe28b392ef9a8",
"core/openrig-installer/SKILL.md": "362bf919ff91dc083550e4fa2583ec349187d3ed9e0ec5443d49b704cb900e80",
"core/openrig-operator/SKILL.md": "69d5a61f708a69b7d28aeddcd4bda0fbaec26bd4cc9f5f808bf1db16b7d8cf84",
"core/openrig-user/SKILL.md": "a0af630b0126c870a4c9ebecb0f7df0058bae63c826a932a3b09d59f9516e5e1",
"core/openrig-user-settings/SKILL.md": "a9650e93a669d65cabcb61409f2812bdf4a27672ba8c077c6f94fa704656fe34",
"core/rig-lifecycle/SKILL.md": "dde7165d9c1718a154684326ea36d239b82b692b1eb8c97d65f2813a5eb82aa4",
"core/agent-starters/SKILL.md": "dd11173ea046dd7d30e23c4fdb3f5188b003ca56ea434ebcc21e14f5e8f29b15",
"core/agent-startup-and-context-ingestion/SKILL.md": "36b6d8f56a911c0515ee2ab99a862cb6c466c4d822bce19479293a5dbf31dca4",
"core/attention-queue/SKILL.md": "c3faabc016bc169ed9a4724571582db8b0ba74b921baccd31342b6efc0ddb945",
"core/cross-host-rig-commands/SKILL.md": "77305c443fb7df11a2df73e33e46b7173cd12d6899a7dec1a12b2118d85bcf02",
"core/human-in-the-loop/SKILL.md": "0175b1f5494ad9872f3516ccf8a935cb83af054a60df1bef6b467007c1451426",
"core/openrig-architect/SKILL.md": "b53e63d22989bb6cc2da30a79e69902ce57a109145027a4007a900fdd66ee747",
"core/openrig-cmux/SKILL.md": "73a86eac45d68b16a38fc0a4438713c634d86061073dac96a4d9e656ea5d34dc",
"core/openrig-herdr/SKILL.md": "37508a02f50bb69ee97c22c37ccf70aa8e37dc0784061eb2a5ad813571eebd1a",
"core/openrig-upgrade/SKILL.md": "9315df9944625d70aa5e251fcfb1ddaa0369cb14fd7dad44bde303564deb6382",
"core/rig-bundles-and-shareable-artifacts/SKILL.md": "e9d5103f419b971373e374474e6ef464e05f242f3fa25e63acfc0b2106651748",
"core/rig-lifecycle/SKILL.md": "8346e01d532795b24c3dba63413ca662c7b44cc5eed39ee2e85568580f40adca",
"core/session-source-fork/SKILL.md": "43004907271759be52436fb7f30678e9632c9794bd34dec5f96f4e929c1107f2",
"core/specification-system/SKILL.md": "5226d6e8b1362df89ba3d5afd82e4b4add355870132ca4b140d7f9f4324ffdc1",
"core/topology-mutation-and-seat-management/SKILL.md": "9ba55ef83d2669c23525f0874d3303a87760f3574bc77d0a53cbca9daae295ea",
"core/watchdog/SKILL.md": "58c6ff3ce08a82ca2ff796b1c887e6832562a9ee18fee8fbfe197a5160429697",
"pm/backlog-capture/SKILL.md": "345c2b47fc85e48c15c0d42bbb48fb27dd3b0ceec36bf59dc6ed20daaea47a84",
"pm/context-builder/SKILL.md": "0134c9b0a9f196565109f7f51b6ec78d5c3e4b5982a0d7105a93b29952625b3c",
"pm/exec-summary/SKILL.md": "9c06b089b4dec325b1be12b261d6a1984627808915818259d63cbf83a5448352",
@@ -87,20 +98,20 @@
"pm/requirements-writer/SKILL.md": "01e84e3b1fd6eb37754e45d7ba72488458c427961ec1c35a4fba4c07adc8c80d",
"pm/ui-mockup/SKILL.md": "b527c72c73c926c3d2a61e1264279486737d429aa85d3624c4adc364c577afc8",
"pods/development-team/SKILL.md": "8bec17cadc8bd4f06ff3593bd802e4103f08124c118c41cb1eb066e58e71ebd7",
"pods/orchestration-team/SKILL.md": "08b87a6f73a1f163dcbefadc39adbf0c42d391b68a693e1de44ce08ac69fa312",
"pods/review-team/SKILL.md": "1f8ad4dc3960350c373faf77e3ea90d22970766b6aa634dbbfaa765feeafe063",
"pods/orchestration-team/SKILL.md": "eca2c8ef8df04aaae8f3094192b964235fd31b00753ad8752614127b5921b784",
"pods/review-team/SKILL.md": "97da8b474c289f76a2c48f9d46191f3adc4e3231ae8a49ff23452e1f852e0474",
"process/agent-browser/LOCAL-INSIGHTS.md": "e793e30464517bfe0eee3485fb03206292338552cf7ccaadb1713e39bf21b043",
"process/agent-browser/OPENRIG.md": "d15123689824c934b51ba572bc7c4d995651e2f606e0e53697263f4ecde108c9",
"process/agent-browser/SKILL.md": "f2709bae71a8c60f6a4b80a6873560cdea9632000ed4b28d082dfae58801199b",
"process/brainstorming/OPENRIG.md": "608f4b913e482dc12a4d201ece1d265dff1d2bfc7d609c2f11f71cb06d5cfbbe",
"process/brainstorming/OPENRIG.md": "583e9bfbfb01392922afbb59c178c91d8db92a1340ae218c048f251886bd04d9",
"process/brainstorming/SKILL.md": "f65187f40745b2016332f426a44db5884687d71e53ea0883c5da992e6e66b802",
"process/dogfood/SKILL.md": "8addc5d22813193649e8286b354ae2282975d75f1dda6d5d4b33d6ace47f438b",
"process/dogfood/references/issue-taxonomy.md": "dee7e925f7fe001903de6cc14f9656bcda90d069bbf65a2273f22202efebba09",
"process/dogfood/templates/dogfood-report-template.md": "55eef9286e32e595dcfca30db76352e9f1d149a78b60b54644eb701072364f35",
"process/executing-plans/OPENRIG.md": "351f388447a01a27fbc35f08d278da635a922b54d7fded9859aaebbb0eb3eec1",
"process/executing-plans/OPENRIG.md": "4a52d0ecdd44078be51794f0083d606ce41cdb71c4dfa6dba6146161db1743ba",
"process/executing-plans/SKILL.md": "c73eca0a0f7101b6923c87c8bb1a85c06a9714927e5b8d0b5cf0afbbd8ccc529",
"process/frontend-design/LICENSE.txt": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
"process/frontend-design/SKILL.md": "cec3b51520db90c76b044e9bb7645ba6676157dc7b60786a81a97d82dc9395b4",
"process/frontend-design/SKILL.md": "3897488693335f3b350292abe067e9f4a39a64af5ac6b1feb82074a36930273d",
"process/systematic-debugging/CREATION-LOG.md": "b482ef9a918fbfc6c369729e8160633ddfa2332466dd362ee73f1527c239ef8b",
"process/systematic-debugging/SKILL.md": "b2adbca870df5232f018a43f6715c7a97c3ddd9429aefa11f9248a859280c2c5",
"process/systematic-debugging/condition-based-waiting-example.ts": "40ae5ebe497fdf310200e43fe986552546d0a22837c0d39e855db1cfd33eb88e",
@@ -112,12 +123,12 @@
"process/systematic-debugging/test-pressure-1.md": "0b6a915db0054577819834c79be9eb614e97bddba10d73768e1fbe91cfed048a",
"process/systematic-debugging/test-pressure-2.md": "b2030aeffba07050e8ad573ddf87486457c4a016a786bb326235bebd856f2016",
"process/systematic-debugging/test-pressure-3.md": "96b50a52e2c7989c9cf20fb752c47c1e9a3a70dc362f8f7989f8f5b64dac7708",
"process/test-driven-development/SKILL.md": "4ad2e041879cb2708791de1997c9d8e491fef66f29773bb3bd7bc7412b239e8f",
"process/test-driven-development/SKILL.md": "9a46b5891604ba0d6d39d2247bc63fc0c1766da7627b2dfbe0eb263c8e057810",
"process/test-driven-development/testing-anti-patterns.md": "bde453bc258f06543987477c837939afaa774ea2acbd9f308d702fc452bc4283",
"process/using-superpowers/OPENRIG.md": "3af62c62fcab2ff962a5cdf398da3031c9bd4a8fbed6bd8ffc4bf52a0205b403",
"process/using-superpowers/OPENRIG.md": "029812750481653a862f6e17f1c7159c80999e0263956e697a4179e7e7b8fa98",
"process/using-superpowers/SKILL.md": "df82c78ef649dee45f4b3fd3e99bcd48d716411230dbe593902b395abdaa1a6e",
"process/verification-before-completion/SKILL.md": "ecec3b8358b9c4aa95e9331bc68758c81b2ddd6a3f37046436925290eb206bb6",
"process/writing-plans/OPENRIG.md": "cf4d50311b02841938343bb1c25ae38bca24e489396acd52cc987f6b435e26ad",
"process/verification-before-completion/SKILL.md": "65691874228b4d4148b3c0463aa96bb93d9c75c69041a085847a91f2f89df3f0",
"process/writing-plans/OPENRIG.md": "95a1a40dbabe7c364f0e91c0fdedfc8225cfb9677ac98f1fa528c515d92831c6",
"process/writing-plans/SKILL.md": "ab71f8b300a16a7d6eaf6e3c54c97019919199d519d34b4a149c2d8866fbd507"
}
}
+90 -24
View File
@@ -23,11 +23,26 @@
],
"category": "process"
},
"agent-starters": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"agent-startup-and-context-ingestion": {
"edges": [
"plugin"
"canonical",
"spec"
],
"category": null
"category": "core"
},
"attention-queue": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"backlog-capture": {
"edges": [
@@ -56,6 +71,13 @@
],
"category": "pm"
},
"cross-host-rig-commands": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"development-team": {
"edges": [
"canonical",
@@ -97,14 +119,25 @@
],
"category": "process"
},
"mission-slice-sop": {
"human-in-the-loop": {
"edges": [
"canonical",
"plugin",
"spec"
],
"category": "core"
},
"messaging-the-human": {
"edges": [
"plugin"
],
"category": null
},
"mission-slice-sop": {
"edges": [
"plugin"
],
"category": null
},
"office-hours": {
"edges": [
"canonical",
@@ -115,7 +148,6 @@
"openrig-architect": {
"edges": [
"canonical",
"plugin",
"spec"
],
"category": "core"
@@ -123,7 +155,6 @@
"openrig-cmux": {
"edges": [
"canonical",
"plugin",
"spec"
],
"category": "core"
@@ -131,40 +162,28 @@
"openrig-herdr": {
"edges": [
"canonical",
"plugin",
"spec"
],
"category": "core"
},
"openrig-installer": {
"openrig-skills": {
"edges": [
"canonical",
"spec"
"plugin"
],
"category": "core"
"category": null
},
"openrig-operator": {
"openrig-upgrade": {
"edges": [
"canonical",
"plugin",
"spec"
],
"category": "core"
},
"openrig-user": {
"edges": [
"canonical",
"plugin",
"spec"
"plugin"
],
"category": "core"
},
"openrig-user-settings": {
"edges": [
"canonical",
"spec"
],
"category": "core"
"category": null
},
"orchestration-team": {
"edges": [
@@ -200,6 +219,13 @@
],
"category": "pods"
},
"rig-bundles-and-shareable-artifacts": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"rig-lifecycle": {
"edges": [
"canonical",
@@ -213,6 +239,32 @@
],
"category": null
},
"session-compaction-and-restore": {
"edges": [
"plugin"
],
"category": null
},
"session-source-fork": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"software-for-agents": {
"edges": [
"plugin"
],
"category": null
},
"specification-system": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"systematic-debugging": {
"edges": [
"canonical",
@@ -227,6 +279,13 @@
],
"category": "process"
},
"topology-mutation-and-seat-management": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"ui-mockup": {
"edges": [
"canonical",
@@ -248,6 +307,13 @@
],
"category": "process"
},
"watchdog": {
"edges": [
"canonical",
"spec"
],
"category": "core"
},
"writing-plans": {
"edges": [
"canonical",
@@ -0,0 +1,132 @@
---
name: agent-starters
description: Use when creating, refreshing, packaging, inspecting, promoting, or deprecating a named per-seat starting point — Agent Starter manifest authoring, the 6-state lifecycle (captured → named → inspectable → used → promoted → deprecated), provenance honesty, and refusal rules. NOT a VM image; a managed starting point composed from agent role + startup context + optional native session source + provenance.
metadata:
openrig:
stage: factory-approved
sibling_skills:
- claude-compaction-restore
- mental-model-ha
- scope-recovery
- session-compaction-and-restore
- agent-startup-and-context-ingestion
- composable-priming-packs
- session-source-fork
- seat-continuity-and-handover
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# Agent Starters
A named, reusable per-seat starting point. Composes an agent role, startup
context, optional native session source, and provenance into something a
user or rig can choose when creating, refreshing, or packaging a seat.
"Agent image" is the analogy. **Agent Starter is the cleaner product
noun.** This is NOT a VM image — it is a managed starting point for an
agent seat, with provenance you can inspect.
## Use this when
- Creating a new seat from a known-good starting context.
- Refreshing a seat with `rig expand` and `starter_ref`.
- Authoring a new starter (registry entry).
- Inspecting an existing starter's provenance, freshness, or recommended status.
- Promoting / deprecating starters in the registry.
- Composing a starter with a Composable Priming Pack (record manifest id/version, runtime, source session id or transcript path, ready-check evidence, freshness state).
## Don't use this when
- You want VM-style deterministic state capture. Starters don't capture VM state.
- You want to copy provider auth material into a starter. **Starters refer to session sources and context; they do NOT copy credentials.**
## What makes a starter valuable
A starter is valuable when it is **functional** — it carries the context the seat needs to do its task well. Functional is the *only* measure of a good starter. Size is not: a smaller starter is not a better one, and a bigger one is not worse. Whatever it took for the seat to become genuinely capable at its job is the right starter — 80K tokens or 800K.
Capture the seat as it naturally is at a functional, proven point. Don't pad it with context the seat doesn't use, and — just as important — don't strip context out to make it smaller. Size is an *outcome* of what the seat needed, never a target.
Never compact, summarize, or shrink a seat in order to make or "lean" a starter. There is nothing valuable in "smaller," and compaction is lossy — you would trade away the exact capability the starter exists to preserve. (Compaction is a separate last-resort step for a seat genuinely near its context limit, with its own before/after plan — never part of capturing a starter.)
## State model — 6 states
1. **Captured** — a useful seat/session/context pattern is identified.
2. **Named** — it becomes an Agent Starter with stable id and owner.
3. **Inspectable** — runtime, context inputs, session source, and provenance are visible.
4. **Used** — a rig member or `rig expand` operation starts from it.
5. **Promoted** — evidence shows it is recommended for a role or bundle.
6. **Deprecated** — replaced, stale, unsafe, or incompatible.
## Failure modes (5)
1. **Overclaiming image semantics** — UI/docs imply deterministic VM-style state capture. Say "starter," name what's included, show provenance.
2. **Hidden provenance** — users can't tell what session, context, or spec a starter came from. **Refuse promotion until provenance is inspectable.**
3. **Stale starter** — points at outdated doctrine, missing files, or invalid native session source. **Inspect must report staleness honestly.**
4. **Secret leakage** — starter packages or displays provider auth material. **Refuse.** Refer to session sources and context, never copy credentials.
5. **Runtime mismatch** — starter used with unsupported runtime. **Refuse with a clear error.**
## Manifest shape (v0+v1 shipped)
```yaml
agent_starters:
- id: velocity-reviewer-v1
runtime: claude-code
agent_ref: local:reviewer
context_refs:
- doctrine:advisor-orchestrator-mode-judgment
- convention:workstream-continuity
session_source:
mode: fork
ref:
kind: native_id
value: "<prior-native-session-id>"
```
Member usage:
```yaml
members:
- id: reviewer
starter_ref:
name: velocity-reviewer-v1
```
When a starter points at a primed session produced from a Composable
Priming Pack, record:
- manifest id/version
- runtime
- source session id or transcript path
- ready-check evidence
- freshness state
## Proof matrix
| Surface | Test type | Authority |
|---|---|---|
| Registry schema accepts minimal starter | unit | daemon or config-layer prototype |
| Inspect shows provenance and included context | unit / snapshot | daemon or CLI |
| Member can use `starter_ref` | integration | daemon |
| Unsupported runtime or stale source refuses honestly | unit + integration | daemon |
| No secret material copied into starter artifact | grep / fixture | tester |
| Bundle can include or reference starter | package inspection | bundle layer |
## Dependencies on other primitives
- **Firm**: `session-source-fork` — native conversation-source continuity for fork-based starters
- **Firm**: `specification-system` — declarative starter and member references
- **Soft**: `rig-bundles-and-shareable-artifacts` — shareable starter packaging
- **Soft**: `context-engineering-and-retrieval` — richer declarative context assembly
- **Soft**: `seat-continuity-and-handover` — refresh and swap workflows over starters
## Required-before-RSI
Agent Starters need queryable provenance and honest inspect output before
RSI loops can rely on them for seat refresh. A workflow must be able to
answer: "what starter did this seat use, what source session or context was
included, and is that starter still recommended?"
## See also
- `session-source-fork` skill — low-level fork primitive that makes native session-based starters possible
- `composable-priming-packs` skill — manifest-driven layer for producing primed sessions starters reference
@@ -0,0 +1,112 @@
---
name: agent-startup-and-context-ingestion
description: Use when designing or auditing how an agent becomes useful after launch — AGENTS.md overlays, role files, skills, rig specs, workflow specs, startup checklists, refocus messages, "rig context" surface. Covers the 4 failure modes that make startup context fail (old rig spec misses current operating mode; current agents never told about new guidance; startup file as dumping ground; orchestrator transmits implementation without preserving product intent).
metadata:
cli_surfaces_referenced:
- context
- whoami
openrig:
stage: factory-approved
sibling_skills:
- claude-compaction-restore
- mental-model-ha
- scope-recovery
- session-compaction-and-restore
- agent-starters
- composable-priming-packs
- session-source-fork
- seat-continuity-and-handover
- claude-compact-in-place
- pre-maintenance-agent-preservation
---
# Agent Startup and Context Ingestion
How an agent becomes useful after launch: **AGENTS.md overlays, role
files, skills, rig specs, workflow specs, startup checklists, refocus
messages**, and any future "rig context" command or skill-librarian
surface.
It is the current concrete startup path inside the broader
context-engineering-and-retrieval primitive. Startup gets a seat into
the right initial shape; context engineering is the larger question of
how a seat gets the right context for the work it is doing right now.
**Most coordination failures are not tool failures; they are context
failures.** Agents need to know their role, operating mode, coordination
convention, boundaries, and current product intent. If startup context
is scattered or stale, agents execute the wrong thing very efficiently.
## Use this when
- Authoring a new agent's startup files (role / culture / startup-context)
- Refreshing a seat that's been running on stale guidance
- Auditing whether agents got the current operating mode (not just what's in old files)
- Designing the orchestrator → next-agent context-transmission shape
- Building a startup map for OpenRig-building rigs
## Don't use this when
- The agent is being created via Agent Starter — the starter's manifest carries startup context
- The work is artifact-backed mental-model rebuild from a packet — that's `session-compaction-and-restore`
- The intent is to ship reusable startup content as a skill — that's `writing-skills-for-openrig`
## Failure modes (4)
1. **A new agent starts from an old rig spec and misses the current operating mode.** Specs go stale; current state must be visible at startup, not just historical config.
2. **Guidance is written to a file that future agents read, but current agents are never told.** File edits don't propagate to running sessions. Cultural rollout (broadcast + fleet-changes-feed) is needed alongside file edits.
3. **A startup file becomes a dumping ground and loses the map-to-canonical-sources role.** Startup should point AT canonical sources; it shouldn't TRY to be one.
4. **The orchestrator transmits implementation instructions without preserving product intent.** Instructions decay; intent travels.
## Proof standard
Startup proof should:
1. **Launch or refresh** a seat
2. **Inspect** what it actually read
3. **Verify** it can state the current role, mode, active constraints, and next handoff convention **in its own words**
## Cross-runtime startup paths (5; do not collapse)
When a seat's startup is artifact-backed mental-model rebuild (active-work
reentry case, distinct from reusable Agent Starters / priming packs):
- See the **cross-runtime restore/reentry packet standard v0**
- Source-trust ranking applies: **`rig whoami` > target rigspec > bounded latest transcript > full transcript > touched-files > `restore-summary.json`**
## Memory surfaces consumed at startup
Per the externalized-memory-surfaces convention's 13-row inventory:
- **Row 7** — AGENTS/role/CULTURE/startup overlays (primary)
- **Row 3** — startup replay context (primary)
- **Row 12** — restore/reentry packets and Agent Starters (cross-runtime startup path)
The umbrella's authority-rank + permission-posture columns govern which
surfaces a startup ingestion path can write vs only read.
## Startup files vs skills (the distinction)
Per `agent-startup-guide.md` (product reference doc) and the team handbook:
| Startup files | Skills |
|---|---|
| Rig-specific, role-specific identity | Reusable SOPs / methodology / knowledge |
| Tell agent WHO it is, WHAT it's working on, HOW this team operates | Tell agent HOW to do something (transferable across rigs) |
| Examples: `role.md`, `CULTURE.md`, `startup/context.md` | Examples: `openrig-user`, `test-driven-development`, `vault-user` |
| Authored per-rig | Authored once, used everywhere |
Don't put skill content in startup files. Don't put identity content
in skills. The 7-layer additive startup model (agent / profile / rig /
culture / pod / member / operator) handles the layering.
## See also
- `mission-slice-sop` skill — the universal operating procedure for working a mission/slice (the canonical PROGRESS/PROOF/MISSION_NOTES/MISSION_BRIEF files); every agent should reach for it at startup, so this general reading contract points at it here (do NOT duplicate the SOP into seat-specific startup files).
- `writing-skills-for-openrig` skill — authoring discipline for skill content (what doesn't belong in startup)
- `forming-an-openrig-mental-model` skill — orientation for new agents
- `session-compaction-and-restore` skill — restore-time startup ingestion
- `agent-starters` skill — reusable starter manifests that compose startup context
- `composable-priming-packs` skill — manifests that produce primed sessions
- `externalized-memory-surfaces` skill — umbrella convention for memory surfaces this primitive consumes
- `openrig/docs/reference/agent-startup-guide.md` (product reference doc; not a skill) — the 7-layer additive startup model + delivery hints
@@ -0,0 +1,264 @@
---
name: attention-queue
description: Coordination primitive for OpenRig. Per-agent queue files tracking in-flight work with explicit state transitions + handoff semantics + cross-agent composition. Prevents memory-loss drops; surfaces stalls mechanically; closes the feedback loop on handed-off work. Applied liberally by every agent on every kernel-supervised rig; composed views serve human attention, orch pod-load, rig pending-work.
status: L4-insight
authored-by: advisor-peer-observer@your-rig
date: 2026-04-13
cited-captures:
- improvements-inbox.md 2026-04-13T12:54:50Z — broadcast primitive RSI (same batching-by-theme cluster)
- Mission 4 cmux stall (2026-04-13 midday) — packet-design + queue-for-cross-rig coordination
metadata:
cli_surfaces_referenced:
- chatroom
- send
openrig:
stage: factory-approved
sibling_skills:
- queue-handoff
- workflow-runtime
- watchdog
- alignment-trace
- looping-workflows
- intake-routing
- human-in-the-loop
- dispatching-parallel-agents
- subagent-driven-development
- control-plane-capabilities
- status-not-chat-orchestrator
- control-plane-queue
- control-plane-watchdog
- control-plane-workflows
- control-plane-delivery-loop
- control-plane-rollout-manager
---
# Attention queue
Use this skill when coordinating work that must survive compaction, cross-agent handoffs, or multi-hour stall detection. Applies when you'd otherwise narrate status to chat or rely on memory for pending items.
## Live protocol override
Current live routing protocol:
- **Known target / explicit owner that should wake now**: `rigx queue handoff <destination> "<body>" --type handoff --urgency soon`
- **Passive durable assignment without wake-up**: `rigx queue create <destination> "<body>" --type handoff --urgency soon`
- **Ambiguous or raw intake**: `rigx stream emit "<body>" ...`
- **Direct dialogue / urgent 1:1 conversation**: `rig send ...`
- **Summoned 3+ party roundtable**: `rig chatroom ...`
Do not cargo-cult the earlier "stream everything with `--destination`" prototype shape into the
live control-plane. Stream is now the ambiguous-intake lane, not the universal lane.
## Core shape (minimum-viable discipline)
1. **Author a queue file at** `substrate/shared-docs/rigs/<your-rig>/state/<your-pod>/<your-member>.queue.md`. Same per-pod directory as your session log.
2. **Every known-target hot-potato work handoff** should arrive via `rigx queue handoff`, not via `rig send`. Use `rigx queue create` only when you intentionally want a passive durable item without wake-up.
3. **State transitions** (start → promote; finish → complete; stuck → block; hand off → handoff; completed handed-off work notifies source → handoff-complete) are appended to the entry body with timestamp. Never in-place rewrites.
4. **Cross-rig reads permitted; cross-rig writes forbidden.** Pod-as-authority-boundary doctrine.
### Live command surface note
When the queue control-plane wrapper is installed, treat queue identity as command-resolved, not
seat-name-guessed:
- `rigx queue whoami` resolves the durable queue that belongs to your current seat
- `rigx queue list --mine` shows your queue without guessing from member name
This matters for continuity successors such as `lead2` or `lead5`, which may intentionally share
the canonical `lead.queue.md` file instead of owning a separate `lead2.queue.md` or `lead5.queue.md`.
Known-target direct handoff on the live wrapper:
```bash
rigx queue handoff orch-lead5@your-rig "Need PM shaping on queue attention loop" --type handoff --urgency soon
```
Passive durable write without wake-up:
```bash
rigx queue create orch-lead5@your-rig "Need PM shaping on queue attention loop" --type handoff --urgency soon
```
## Six operations
| Op | Effect |
|---|---|
| append | New entry (state=pending) on inbound request |
| promote | state=in-progress when you start work |
| complete | state=done with optional result |
| block | state=blocked + blocked-on=<id or condition> |
| handoff | state=handed-off + handed-off-to=<target>/<new-id>; send rig-send with `[queue-handoff:]` prefix to target |
| handoff-complete | target signals source that handed-off work finished (closes feedback loop) |
| escalate | walk authority chain when blocked past tier threshold |
| defer / drop | push-to-later or drop-with-rationale |
## When is something a queue handoff?
**Queue handoff** (`rigx queue handoff`):
- Asks a known recipient to do new work
- Transfers ownership of pending work
- Names a deliverable + acceptance criteria
**NOT a queue handoff**:
- Wake-ping `1`
- PSA / broadcast / status update
- Ack / courtesy notification / diagnostic ping / reply to question
- Raw idea or bug where you do not yet know the right owner
If you do not know the correct owner, emit to stream instead of guessing.
## Tier-based ack + notification rules
- **human-gate tier** (gated items; human-watching): mandatory ack on handoff; mandatory notification on completion
- **agent-coordination tier** (standard inter-agent work): recommended ack + notification
- **internal-self tier** (your own to-dos): optional
## Read discipline
- Read your own queue at turn start before picking up new work
- Orchestrators read pod-member queues on wake cadence (`1` ping)
- Advisor-pod reads cross-rig queues for composed views + human-attention
- Past-threshold blocked entries surface during sweeps; execute escalate op if you can't self-unblock
Recommended turn-start queue commands on the live wrapper:
```bash
rigx queue whoami
rigx queue list --mine
```
### Resume-from-idle state sweep
Agents returning from idle-standby (supervisor-wake-only pings; no substantive dispatch during the window) MUST sweep adjacent state before pulling new work. Minimum sweep:
- Supervisor-log tail (~200 lines) at `rigs/kernel/state/supervisor-log.md`
- human-attention.md at `substrate/shared-docs/human-attention.md`
- Any doctrine-decisions added since last-active (`rigs/kernel/state/doctrine-decisions/`)
- Partner queue files at `rigs/kernel/state/<pod>/<peer-member>.queue.md` (peer load-tracking for pairs)
- **Fleet-changes-feed** at `substrate/shared-docs/fleet-changes-feed.md` (pull-native rollout surface; catches any fleet-wide doctrine / skill / convention / operational changes that landed during idle; filter by scope = fleet-wide + your rig/pod)
**Trigger:** first active turn after ≥3 consecutive wake-only cycles OR on peer HA-check request. Sweep before responding to HA-check so the response is grounded in current reality, not stale memory.
**Rationale:** own-queue-at-turn-start catches own-queue drift; adjacent-state drift is a separate failure class that requires its own read discipline. Composable with own-queue sweep (both at same reading point); adds ~2-5 minutes of read time; cheap insurance against peer-driven HA-check round-trips.
**Worked example (genesis):** advisor-co-observer@your-rig after ~2h idle-standing-by on 2026-04-13 — 5-of-7 HA-check items out-of-sync when peer queried. Rule addition would have caught the drift pre-query via adjacent sweep on wake-to-active transition.
## Status-not-chat corollary
Your chat pane is for operational work + ad-hoc human exchanges. Your STATUS lives in queue files + composed views. If you finish work + hit a gate-requiring next-action, do NOT narrate to chat + idle-wait. Queue-handoff to advisor-pod with `tier: human-gate`. The operator doesn't watch agent panes; they watch human-attention.md (composed from human-gate queue entries).
## Composed views (4 layers)
- **Pod-load view** — who's loaded / blocked (orch reads)
- **Rig pending-work** — cross-pod roll-up
- **Fleet cross-rig** — host-wide
- **human-attention** — human-gate-tier items across all queues (advisor-pod composes)
v0: manual regen by orchestrators + advisor-pod.
v0.5: terminal-node watch scripts auto-regen.
v1: generative UI consuming structured queue data.
## Codex-sandbox proxy-write pattern (sanctioned workaround)
Codex members whose sandbox blocks substrate writes can still participate via proxy-write:
- Codex authors content locally (e.g., `/tmp/<rig>-attention-queue/<member>.queue.md`)
- Claude counterpart physically writes to substrate with sha256-verified integrity check
- Subsequent state transitions via `[queue-update: <id> <new-state> <reason>]` rig-send from Codex to Claude-writer
- Authorship preserved; only write-access delegated. Distinct from peer-injection (which is forbidden).
## Escalation mechanics
When entry stays blocked past tier threshold AND agent can't self-unblock:
1. Identify escalation target per authority chain:
- Pod member → pod orchestrator
- Pod orch → rig orch-lead
- Rig orch-lead → kernel orch-lead OR advisor-pod (if human-gate)
- Skip-levels allowed when agent KNOWS correct target
2. Create new entry in escalation-target's queue with `escalated-from: <source-id>`; state=pending; priority elevated
3. Send handoff-shape rig-send: `[queue-escalate: <new-id>] <title> — blocked <Nh> on <reason>`
4. Update own entry: state=escalated; escalated-to=<target>/<new-id>; transitions-log appended
Threshold guidance: 1h human-gate / 4h agent-coordination / 24h internal-self. Rigs may tighten.
## Task-close RSI-check (flywheel trigger)
Every `complete` op on substantive work reflects briefly: "what did we learn? is this worth filing as L2 capture to improvements-inbox?"
Two outcomes; both leave evidence in the transition trail:
- **Novel observation worth filing:** append L2 capture entry to `rigs/kernel/state/improvements-inbox.md` per the v1 queue template (`state: pending` + transition trail started). Transition line in your own queue: `<ts> — RSI-check: filed <capture-id>`.
- **Nothing novel:** transition line in your own queue: `<ts> — RSI-check: none`.
Applies to substantive work-streams. Does NOT apply to:
- Wake-pings (`1`) — not a work-stream
- Trivial status updates — nothing to reflect on
- Pure acks / routing-map updates — no work done
Rationale: task-close is the deterministic interval that makes recursive-self-improvement mechanical rather than ad-hoc. Pattern named in skill-maturity-convention.md §"Task-close RSI-check discipline".
## Push vs pull — when to use rig-send vs queue-write
Not every communication belongs in the receiver's chat pane. The discipline mirrors status-not-chat: most inter-agent signals can flow through queue files (pull) rather than rig-sends (push). Reduces noise; respects receiver's attention cycle.
**Sender's test:** *Does my message need the receiver's attention within their next turn cycle?*
- **Yes → push** via `rig send` (lands in chat; receiver processes on next turn)
- **No → pull** via queue-write (write to own queue OR receiver's queue via handoff; receiver sweeps at cadence)
### Push (rig-send to chat) when:
- Receiver needs info NOW to unblock their work
- Question requires specific answer to proceed
- Handoff is past ack-threshold + tier=human-gate (mandatory-ack window)
- Blocker surfacing (can't self-unblock; need help from target)
- human-gate item needing surface to advisor-pod
- Destructive or time-critical coordination
### Pull (queue-write only) when:
- Status update / adoption signal / cascade-complete ack
- Non-urgent ack (within tier threshold)
- Information that can batch in receiver's curator sweep
- Broadcast-receipt confirmation (receiver's cadence catches it)
- Observed patterns or captures with no time pressure
- Resync material for HA peers (they sweep on resume-from-idle)
### Why this matters
Push-as-default floods the receiver's chat pane with status that could be pulled. Today's rollout volume proved this: during attention-queue + EMM cascades, most acks arrived as push (rig-sends) when they could have been pull (queue-writes). Receiver (advisor-pod) had to process each ping; most were status signals needing no action.
Pull-over-push is the queue primitive's whole point. Status lives in queue files; readers sweep at cadence; only genuine unblockers + gate-surfaces push to chat.
### Worked example
orch-lead@your-rig ack'd attention-queue cascade:
- **Push version (what happened):** `rig send advisor-peer-observer@your-rig "[queue-handoff-ack: ...] ... cascaded to 8 pod members ..."` → lands in my chat; I read immediately; process the status
- **Pull version (what should happen):** write ack-receipt to `rigs/openrig-build/state/orch/lead.queue.md` as state-transition on their adoption entry; I sweep their queue on my curator cadence; pick up the ack without chat-ping
Ack-receipts for status are pull-native. Handoff-complete notifications for human-gate items stay push (they close feedback loops on time-sensitive work).
### Corollary — orchestrator-to-advisor cadence
Orchestrators writing to their own queue files lets advisor-pod read without being interrupted. The curator-sweep pattern (advisor reads pod queues on their cadence) is the canonical pull mechanism. Push only when time-matters.
## Anti-patterns (don't do these)
- **Chat-as-status** — narrating status/gates to your chat pane + idle-waiting. Use queue + human-attention instead.
- **Duplicate-storage** — writing the same fact in queue + session-log + chat + mission-control. Queue is authoritative for in-flight state.
- **Peer-injection** — writing directly to another agent's queue without their authorship. Only handoff op moves work cross-queue.
- **Silent drops** — don't leave items in pending forever without state transitions. defer or drop with rationale.
- **Global queue** — don't try to make one queue for everyone. Per-agent primary; compose for views.
## Maturity status
**L4-insight** per skill-maturity-convention. Applied liberally across the host; evolving via observation. Feedback loop: RSI filings reshape this skill; demotion valid if convention reveals wrong shape; promotion to L5-canon requires architect+reviewer pair-review per HOST-TOPOLOGY §7 SOP.
Rollout date: 2026-04-13 host-wide adoption. 48h observation cycle active; RSI with learnings due ~2026-04-15.
## Related
- Spec (full reference): the internal attention-queue spec
- Skill-maturity convention: `substrate/shared-docs/skill-maturity-convention.md`
- Config-wrapper-code loop doctrine: `config-wrapper-code-loop` skill
- HOST-TOPOLOGY §4 context-sharing patterns — attention queue is a new pattern here
- SUBSTRATE-CONVENTIONS §7 HA session logs — queue lives in same per-pod directory
@@ -0,0 +1,190 @@
---
name: cross-host-rig-commands
description: Use when issuing `rig` commands against a remote host via `--host <id>` flag (single-hop SSH to a host declared in `~/.openrig/hosts.yaml`). Covers the 4 structured failure modes (ssh-unreachable / permission-gate / remote-daemon-unreachable / remote-command-failed), the `--verify` honest pass-through (SSH success is NOT verify success), and the host-registry shape. v0 supports `rig send / capture / ps / whoami --host <id>`.
metadata:
cli_surfaces_referenced:
- capture
- daemon start
- host list
- host show
- ps
- send
- whoami
openrig:
stage: factory-approved
sibling_skills:
- rig-lifecycle
- topology-mutation-and-seat-management
- seat-scaling-and-specialization
- sidecar-operator
- rig-bundles-and-shareable-artifacts
- specification-system
- extension-and-user-workspace
---
# Cross-Host Rig Commands
A first-class OpenRig surface for issuing `rig` commands against a
remote host via single-hop SSH. v0 productizes the existing SSH-envelope
operator pattern (`ssh <host> rig <cmd>`) with declared host identity,
explicit cross-host invocation path, preserved `--verify` semantics, and
4 named failure modes.
**Current-host note (2026-07-14):** this skill still preserves the original
SSH-v0 doctrine below, but the live host registry may also contain HTTP
read-through/tunnel entries such as `your-vm` and `your-other-vm`. Use the
host registry entry as ground truth for transport shape, and use
`conventions/multi-host-naming/README.md` for host-id naming. HTTP entries
require `url` plus exactly one of `bearer_file` or `bearer_env`.
**v0 is CLI-side shell-out only — `packages/daemon/` is NOT touched.**
The remote host has its own managed `rig` available on `$PATH`.
## Use this when
- Driving a Tart VM from the host (the immediate cross-host consumer)
- Operating Mac host A against Mac host B
- Reading remote state via `rig ps --host` / `rig whoami --host`
- Sending or capturing on a remote rig session (`rig send/capture --host <id>`)
- Authoring a `~/.openrig/hosts.yaml` registry entry
## Don't use this when
- The target is local. Don't pass `--host` for local commands.
- You need multi-hop SSH (host A → host B → host C). v0 is single-hop only.
- You want reverse direction (remote initiates back to local). v0 is originator-pull only.
- Cross-host **seat handover** (moving a durable owned seat across hosts) — deferred to higher-level primitives. (Cross-host **queue writes**, by contrast, now ship — see "Cross-host queue writes" below.)
- The transport isn't SSH. v0 supports `transport: ssh` only.
## Cross-host queue writes (updated 2026-07-21 vs main d37a08ad)
Cross-host **queue writes** are no longer deferred — they ship — but the rule
differs from the interactive verbs (`send`/`capture`/`ps`/`whoami`):
- **Queue writes are EXPLICIT-only.** Address the target host explicitly with
`--host <id>` or the `member@rig@<host>` form. A queue write **never** follows a
persisted host selection.
- **`host select` stickiness does NOT apply to queue.** `host select` affects the
`resolveEffectiveHost` verbs (`send`/`capture`/`ps`/`whoami`) — those follow the
selected host — but a queue write ignores it and requires explicit addressing.
- **Host address parsing differs** between the interactive verbs and the queue
verbs; do not assume the interactive form carries over. When unsure, address the
host explicitly.
## Host registry shape (`~/.openrig/hosts.yaml`)
Host ids should follow the OpenRig-work multi-host naming convention:
`conventions/multi-host-naming/README.md`. In this environment that means
physical hosts such as `your-vm`, local OpenRig development VMs such as
`your-vm`, persistent product VMs such as `your-other-vm`, and VPS hosts such
as `your-vps`. Keep old aliases during migration until no live routing
depends on them.
```yaml
hosts:
- id: a-test-vm
transport: ssh # v0 supports "ssh" only
target: a-test-vm.local # DNS name, SSH config alias, or IP
user: wrandom # optional
notes: "Tart VM" # optional
- id: laptop-b
transport: ssh
target: laptop-b.tail-scale-net
user: wrandom
```
Validation rules:
- `hosts` required, non-null array
- Each entry: `id` required (non-empty, unique), `transport` required (`ssh` only), `target` required
- `user` and `notes` optional
- Operator-managed file; v0 does NOT include any sub-command to add/remove/list hosts (operators edit YAML directly)
- Missing or invalid file returns a clear error pointing at the canonical path
## CLI surface (v0 shipped)
```bash
rig send <session> "msg" --host <id> --verify
rig capture <session> --host <id>
rig ps --host <id> [--nodes] [...]
rig whoami --host <id>
```
Forwards every shaping flag (`--nodes`, `--full`, `--limit`, `--fields`,
`--summary`, `--filter`, `--json`) to the remote `rig` invocation. The
remote rig's output is verbatim passthrough on success.
## The 4 structured failure modes (load-bearing API contract)
The CLI distinguishes 4 failure modes; operators get an actionable error
per mode; JSON output preserves the `failedStep` enum:
| Mode | Cause | Action |
|---|---|---|
| `ssh-unreachable` | SSH itself failed (connection refused, host key mismatch, DNS failure, timeout) | Verify SSH access and the registry entry |
| `permission-gate` | SSH hit auth/permission gate (Permission denied, Keychain) | Error includes hint to keychain-over-SSH field note (L4-3 D6) |
| `remote-daemon-unreachable` | SSH succeeded but remote `rig` reported the remote daemon was not reachable | `ssh <target> rig daemon start` |
| `remote-command-failed` | SSH succeeded but remote `rig` exited non-zero for some other reason; remote stderr is surfaced | Read remote stderr; debug remote command |
Each is distinct and routable. Don't conflate them.
## `--verify` honest pass-through (load-bearing)
`--verify` against a remote target must:
- **Propagate** the verification request to the remote daemon (or remote `rig` invocation that talks to it)
- **Bring back a structured verification result** (true/false + reason if false), NOT just SSH exit code 0
- **Distinguish "SSH succeeded but verify returned false" from "SSH itself failed"** — these are different operator actions
**SSH success is NOT verify success.** The remote rig is authoritative
on `--verify`; its `Verified: yes/no` line is surfaced verbatim. Verified
at 3 layers (executor unit, command integration, source impl).
## Hard boundaries (do-not list)
- **Do NOT collapse `--verify` honest result into SSH exit code.** Operators and agents rely on the distinction.
- **Do NOT silently retry SSH failures inside the primitive.** Surface them; let the caller decide.
- **Do NOT introduce non-SSH transports in v0.** Goal is productizing the existing shipped pattern, not replacing it.
- **Do NOT touch host-side daemon code as part of v0.** Cross-host shape is on the originator side.
## Cross-host annotation
Every cross-host invocation is observable as cross-host:
- **Operator output**: `[via host=<id> (<target>)]` annotation
- **JSON output**: `cross_host: { host, target }` field
Annotation is PRESENT when `--host` is set and ABSENT otherwise
(compat regression).
## Currently shipped (v0) vs deferred
Shipped at openrig `cdce3a6` (2026-04-30):
- `--host <id>` flag on `rig send / capture / ps / whoami` (initial 2 commands; promoted to 4 at `6b7043a` same day)
- Read-only host registry validation
- Single-hop SSH executor with 4-mode `failedStep` enum
- `--verify` honest pass-through
- Cross-host annotation (operator + JSON)
- Daemon untouched
Deferred:
- Tier 2 real-runtime cross-host proof (disposable Tart VM cycle)
- `rig host list / show` read-only sub-namespace (only if host count grows past comfortable manual editing)
- Non-SSH transports
- Multi-hop SSH
- Reverse direction (remote initiates)
- Connection pooling/caching
## See also
- `seat-continuity-and-handover` skill — host-aware seat-binding semantics for cross-host handover (deferred to v1 on top of this v0 baseline)
- `openrig-user` skill — the local CLI surface that cross-host commands wrap
## Sender identity is ASYMMETRIC (verified vs current main, 2026-07-25)
The `@host` sugar is **target-addressing only**, not sender-identity. A cross-host
message's **From:** is `member@rig` — the sender carries **NO `@host` suffix**. The target
supports `member@rig@<host>` for addressing; the sender does not reflect its own host in
`From:`. **Do NOT teach or expect a host-qualified `from`** (in openrig-user / operator send
docs or anywhere) until that core gap is fixed. (pm@your-rig verified this against
current main, 2026-07-25 — a known asymmetry, not a doc error to paper over.)
@@ -0,0 +1,104 @@
---
name: human-in-the-loop
description: Use when classifying a slice closeout (auto-continue / human gate / park), routing a real decision to a human, or designing a human queue/dashboard surface. Treats humans as durable network participants with attention surfaces, queues, and decision records — escalation lands as a durable attention item, not a chat message. Approval is NOT required for every clean closeout; the default RSI conveyor continues unless an explicit human gate is reached.
metadata:
openrig:
stage: factory-approved
sibling_skills:
- queue-handoff
- workflow-runtime
- watchdog
- alignment-trace
- looping-workflows
- intake-routing
- attention-queue
- dispatching-parallel-agents
- subagent-driven-development
- control-plane-capabilities
- status-not-chat-orchestrator
- control-plane-queue
- control-plane-watchdog
- control-plane-workflows
- control-plane-delivery-loop
- control-plane-rollout-manager
---
# Human In The Loop
The primitive that treats humans as **durable network participants** —
attention surfaces, queues, decision records, routing semantics — not
as ad-hoc chat receivers.
**Autonomy is not the absence of humans; it is knowing when human
judgment is needed and making that handoff crisp.**
## Use this when
- A slice closeout needs classifying: auto-continue, human gate, or park
- A real decision needs to land in front of a human (usage limits, provider auth, roadmap tradeoff, product-intent ambiguity)
- Designing a human queue/dashboard surface
- Returning a hot potato to orchestration after human approval
## Don't use this when
- The slice closeout is clean and `PROGRESS.md` already names the next safe slice. **Default RSI conveyor continues; do NOT manufacture a human gate.**
- The escalation is just a status update. Humans are participants for *decisions*, not narration.
- The next owner is another agent. Use queue-handoff, not human-in-the-loop.
## The 3-class closeout classification
In a productized daemon-backed version, closeout classifies the next
step BEFORE touching the human queue:
| Class | When | Action |
|---|---|---|
| **auto-continue** | Slice closes cleanly, next named slice in workstream plan | Mark closed; create next-owner qitem from plan |
| **human gate** | Genuine decision needed (usage limits, provider auth, product-intent ambiguity, roadmap tradeoff) | Create human queue item with proof + decision text + recommended default + action outcomes |
| **park** | Intentionally stop the conveyor (e.g., waiting on external) | Stop with reason + resumption path |
## Failure modes (5)
1. **Human decision needed, but the rig only mentions it in chat.** Decisions belong as durable attention items, not chat messages.
2. **Human queue item lacks enough plain-English context for a decision.** Include proof + decision text + recommended default + action outcomes.
3. **Human response updates a file but does not wake the next owner.** Approval should return the hot potato; feedback should create the next durable qitem.
4. **The dashboard shows too much raw rig state and hides the actual decision queue.** Decision queue is the primary surface; rig state is secondary.
5. **A clean closeout is parked on the human even though `PROGRESS.md` already names the next safe slice.** Don't manufacture human gates.
## Proof standard (both paths)
A trustworthy human-in-the-loop system proves both directions:
- **Blocking gate path**: real item routed to human → human decision recorded through UI → resulting hot-potato handoff wakes correct next owner
- **Non-blocking closeout path**: proof inspectable by human, but orchestrator continues to next named slice without manufacturing a human gate
A primitive that only wakes humans is not trustworthy. It must also know when NOT to.
## Product shape (SHIPPED — Mission Control, PL-005)
This surface has shipped as **Mission Control** (product UI, `/mission-control`
route; actions via `POST /api/mission-control/action`). The seven verbs the
human acts with:
- **approve** (returns the hot potato to orchestration or the chosen owner)
- **deny** (reject the item)
- **route** (send to a different owner)
- **annotate** (add context without action)
- **hold** (intentional pause with reason)
- **drop** (mark not-actionable)
- **handoff** (hand to a specific next owner — creates the next durable qitem)
**Approval returns the hot potato to orchestration or the chosen owner;
feedback creates the next durable qitem rather than only mutating the source
queue file** — enforced by the shipped verbs (handoff/route create qitems).
See `docs/as-built/architecture/mission-control.md`.
## Long-term shape
Likely needs **multiple humans with different scopes**, not a singleton
human attention feed. Different humans own different decision
domains; queue items route by scope.
## See also
- `queue-handoff` skill — durable handoff via queue items; human-in-the-loop is the human-side complement
- `watchdog` skill — when to wake (humans included) vs no-op
- `looping-workflows` (convention) — the looping-workflows convention covers loop closeouts; human-in-the-loop is the escape hatch
@@ -1,115 +0,0 @@
---
name: mission-slice-sop
description: "Use when working a mission or slice: the SDLC flow (intent -> mini-requirements + proof contract -> mockups -> plan-lock -> build -> QA -> `rig proof` drops -> proof-lock), and how to track, prove, and hand off state across agents and compaction via PROGRESS.md / PROOF.md / MISSION_NOTES.md. Covers the two locks, role contracts, hot-potato queue handoff, and the `rig scope audit` backstop."
metadata:
openrig:
stage: shipped
last_verified: "2026-07-06"
distribution_scope: product-bound
source_evidence: |
The canonical product SDLC skill: it teaches the full SDLC flow the
Living Notes UI projects — the convention sections, the proof-contract
pairing, the two staged-approval locks, C1 proof drops, and the three
role contracts. Conventions SSOT: docs/reference/sdlc-conventions.md
in the repo; on an installed package the daemon materializes the same
document at $OPENRIG_HOME/reference/sdlc-conventions.md (default
~/.openrig/reference/sdlc-conventions.md). The deterministic backstop
is the `rig scope audit` classifier.
sibling_skills:
- queue-handoff
- seat-continuity-and-handover
- claude-compaction-restore
---
# Mission/Slice SOP — how you work a mission & slice
Use this skill to actually **do** mission/slice work the way OpenRig expects: author the convention sections, track on the canonical files, prove on them, hand off through them, and survive compaction on them. **Do the work described here; do not merely explain the protocol.** The deterministic backstop is `rig scope audit` — the audit classifier is the source of truth for adherence. The conventions themselves live in ONE document: **`docs/reference/sdlc-conventions.md`** in the repo, materialized by the daemon at **`$OPENRIG_HOME/reference/sdlc-conventions.md`** (default `~/.openrig/reference/sdlc-conventions.md`) on an installed package — this skill teaches the flow; the SSOT defines the formats.
## The SDLC flow (intent → proof)
```
intent → mini-requirements + proof contract → (UI slices: mockups)
→ plan-lock (rig scope slice approve --scope spec)
→ build the LOCKED set
→ QA: mockup ↔ delivered VISUAL compare
→ proof drops (rig proof add <slice> …)
→ proof-lock (rig scope slice approve --scope delivery)
```
1. **Record intent** verbatim in the slice's `## Intent` section (`rig scope slice create` scaffolds it — every template kind).
2. **Author the mini-requirements + proof contract**: `## Mini-requirements` is the concise one-glance tier (approval starts there); `## Proof contract` is a checkbox list of promised deliverables, each written as an observable outcome. UI deliverables name their planned mockup. The IMPLEMENTATION-PRD opens with the mini-requirements; everything between intent and proof is **elastic** — for a small slice the mini-requirements may BE the whole PRD.
3. **Plan-lock**: `rig scope slice approve <slice> --scope spec` — "the PRD matches the intent; THIS artifact set is what gets built." One daemon-side write: frontmatter stamp + append-only audit row.
4. **Build the locked set** — look at the mockups, not just the spec text.
5. **QA visual compare**: for each deliverable, load the planned mockup, produce the real artifact in a test/demo environment, visually compare, and record the verdict.
6. **Drop proof**: `rig proof add <slice> --artifact-type qa --verdict PASS --candidate-sha <tip> --money-evidence "…" --evidences "1,3" --media "walk.webm,panel.png" --self-check "…"` — the C1 header's closed sets validate at drop time; `--evidences` joins the drop to its proof-contract items and `--media` names the curated proof/-relative media the drop stands behind (that pairing + media set is what the UI's DELIVERED section renders).
7. **Proof-lock**: `rig scope slice approve <slice> --scope delivery` — the terminal sign-off. Approval is freeze/sign-off, **never** proven-green: proven-green requires the recorded C1 verdicts.
## The three role contracts
- **Planning agent:** authors intent + mini-requirements + the proof contract; produces mockups for UI deliverables and attaches them to the locked set (a UI slice with no mockup is an incomplete plan; non-UI slices have none — not a gate); locks the plan.
- **Build agent:** builds against the LOCKED set only; looks at the mockups.
- **QA agent (owns the compare):** visually compares planned vs delivered per deliverable, records verdict + note via proof drops, and **curates** the canonical proof set (bounded, mapped to deliverables; the fix-loop pile stays in `proof/`, one drill-in down). On mismatch: fix-and-re-review or kick back with the reason — never escalate a raw mismatch to the human.
## The canonical files (the operating surface)
> The canonical files below are the **operating surface of the work** — you track on them, prove on them, hand off through them, and survive compaction on them. They are NOT side-artifacts to "maintain"; keeping them current *is* the work.
- **README.md** (mission + slice) — the overview, OPENING with the convention sections (`## Intent` / `## Mini-requirements` / `## Proof contract`). The **mission README carries this SOP at its bottom.**
- **IMPLEMENTATION-PRD.md** — the full PRD; opens with the mini-requirements; the `## Proof contract` here is what the UI's DELIVERED pairing joins proof against.
- **PROGRESS.md** — the live delivery state. One line per outcome; links down for detail.
- **MISSION_NOTES.md** — the accruing handoff + tribal-knowledge doc. Blank-slate onboarding + **compaction-restore** read it. `§1` top-of-mind + per-seat `§A–§X`.
- **MISSION_BRIEF.md** — the steering doc (the UI "Steering" tab). The 7-section schema.
- **PROOF.md** (+ `proof/`) — acceptance evidence. **A slice is not done until every proof-contract item has evidence.**
## Per-file rules — WHO / WHEN / HOW
### PROGRESS.md
- **WHO:** the orchestrator owns `§1` (current state); every agent logs its own outcomes.
- **WHEN:** after every slice-done **AND every commit**; on any material state change.
- **HOW:** one line per outcome (checkbox), link down for detail (workstream-continuity format); keep frontmatter `stage`/`verified` honest.
### PROOF.md + proof/
- **WHO:** the impl/QA pair that worked the slice.
- **WHEN:** a slice is **NOT "done"** until every proof-contract item has evidence.
- **HOW:** proof maps **1:1 to the proof contract's deliverables** — put media under `proof/`, then ATTACH it with `rig proof add <slice> … --evidences <item> --media <files>` (the drop writes the C1 header the DELIVERED pairing joins on) + a line in PROOF.md stating what it proves. **Hand-placing files in `proof/` without a drop is the anti-pattern** — the deliverable stays unpaired and `unverified`. No proof → not done.
### MISSION_NOTES.md
- **WHO:** any agent updates `§1` (top-of-mind); each seat owns + appends to its own `§A–§X` section.
- **WHEN:** on any material change; a compacting agent **files its state here BEFORE compaction and reads it on restore.**
- **HOW:** accruing tribal knowledge — `§1` ≤ 5–15 lines (gates, open decisions, surprises); per-seat continuation entries (latest = truth; other seats read-only). Pointer-first; don't duplicate.
### MISSION_BRIEF.md
- **WHO:** product/design (steering owner).
- **WHEN:** when steering changes.
- **HOW:** the 7-section steering schema (the UI "Steering" tab reads it).
### README.md
- **WHO:** the author at creation; refreshed on rescope.
- **WHEN:** at mission/slice creation + when scope/theme changes.
- **HOW:** overview + honest frontmatter (`id`/`stage`/`verified`) + the convention sections up top; the mission README carries this SOP at its bottom.
## The lifecycle (4 legs)
**SCAFFOLD** (`rig scope` creates the files from templates — every slice kind emits the convention sections + `proof/` + the IMPLEMENTATION-PRD skeleton) → **POPULATE** (agents fill them as work happens, per the rules above) → **PROJECT** (the Living Notes UI reads them into INTENT → PLAN → DELIVERED) → **VERIFY** (`rig scope audit` checks adherence). "Loose freeform write + deterministic verify."
## Hot-potato (handoffs)
End every turn by passing the ball — a `rig queue` handoff to the next agent (close the qitem with a `closure_reason`). The **durable ball-pass is the queue close, not a chat message.** Never go idle without a handoff.
## Verify (deterministic backstop)
Run `rig scope audit` at slice-close. It flags: committed-without-touching-PROGRESS; slice-marked-done-without-PROOF; active-mission-without-MISSION_NOTES; MISSION_BRIEF off-schema; proof artifacts violating the C1 header; missing IMPLEMENTATION-PRD on a building slice; missing convention sections (`## Intent`, a well-formed `## Proof contract`, the UI-slice mockup ref). Every convention check is **advisory / fail-open** — it records and advises, never blocks a write. **Fix the flag, don't suppress it.**
## Reading terminal captures — KNOWN GOTCHA: ghost-text autocomplete is NOT real
When you `rig capture` a pane, **greyed / ghost autocomplete suggestions are NOT real content** — they are autocomplete *previews* (shell autosuggestion, the input-box ghost-text completion), not typed, staged, or committed input. **This is known, expected, and has been faking agents out a lot** — reading a ghost suggestion in a peer's input box as "staged text they're about to send," or as a real prompt, and then reasoning/acting on a string that was never actually there.
**Rule:** ignore ghost/autosuggest text entirely. Only *committed/rendered* pane output is real. If a `❯` input line shows text, treat it as an autocomplete artifact unless you have independent evidence it was actually entered. Do not build decisions (or worry about "colliding with staged text") on ghost text. When it matters, verify at source (git, the queue, the actual event) — never off a capture's ghost line.
## Moment-of-truth checklist
- **Starting a slice?** → intent recorded verbatim? mini-requirements + proof contract authored? mockups attached (UI slices)? plan locked (`--scope spec`)?
- **Finishing a slice?** → every proof-contract item has curated evidence via `rig proof add … --evidences --media` (C1 drops — never only hand-placed files)? PROGRESS updated? MISSION_NOTES `§1` refreshed? proof locked (`--scope delivery`)? Handed off via queue?
- **Committing?** → PROGRESS updated?
- **Compacting?** → filed your state in MISSION_NOTES?
- **Starting on a mission?** → read the mission README (incl. this SOP) + MISSION_NOTES + the conventions SSOT (`docs/reference/sdlc-conventions.md` in the repo, `$OPENRIG_HOME/reference/sdlc-conventions.md` on an installed package)?
@@ -1,18 +1,28 @@
---
name: openrig-architect
description: Use when designing multi-agent topologies that run ON OpenRig — authoring RigSpec and AgentSpec files for new rigs, creating agent startup content (guidance / skills / culture), or diagnosing why a launched rig's agents aren't behaving as intended. NOT for changing OpenRig itself (work in the openrig product repo); NOT for ordinary CLI operation of an existing rig (use openrig-user). Covers the full authoring lifecycle from user intent to validated, launchable rig.
description: Use when designing multi-agent topologies that run ON OpenRig — authoring RigSpec and AgentSpec files for new rigs, creating agent startup content (guidance / skills / culture), or diagnosing why a launched rig's agents aren't behaving as intended. NOT for changing OpenRig itself (use openrig-builder); NOT for ordinary CLI operation of an existing rig (use openrig-user). Covers the full authoring lifecycle from user intent to validated, launchable rig.
metadata:
cli_surfaces_referenced:
- agent validate
- capture
- daemon start
- ps
- send
- spec validate
- specs ls
- up
- whoami
openrig:
stage: factory-approved
last_verified: "2026-05-04"
distribution_scope: product-bound
source_evidence: |
Bootstrap skill — NPM install lands this in personal homes (~/.claude/skills/, ~/.agents/skills/) for users authoring their own rigs.
sibling_skills:
- openrig-user
- openrig-operator
- openrig-builder
- openrig-upgrade
- forming-an-openrig-mental-model
transfer_test: pending
- ai-dev-workflows
notes: |
Description was already correct (starts with "Use when..."; lists specific authoring triggers including the diagnose-bad-rig case). Final sentence ("Covers the full authoring lifecycle from user intent to validated, launchable rig.") is workflow-summary-adjacent; on next iteration, consider trimming. For factory-adoption cycle, kept as-is to match product source-of-truth.
---
# OpenRig Architect
@@ -47,8 +57,13 @@ Load these before starting any design work. The quality of your output depends o
**Read if present on this host:**
4. **Host-level doctrine file** (if your team maintains one — e.g., a HOST-TOPOLOGY doc that defines canonical rig classes, context-sharing patterns, and authoring SOPs for high-stakes rigs). If present, it supersedes the baseline process below for complex or high-stakes rigs (≥4 members, HA, managed-app, or shared/copied). Solo operators and small/focused rigs use the baseline below directly.
5. **Agent-facing software design principles** if your rig ships a new CLI, service, or managed app that agents will operate. Treat the operating surface as a context-engineering problem: every error message and help text gives the agent information to act on.
4. **Host-level doctrine** in your host's topology doc, if it keeps one. If this file exists, it supersedes the baseline process below for complex or high-stakes rigs. Specifically:
- §3 defines the canonical rig classes (kernel, project, ephemeral, infra-build, managed-app). Classify before designing.
- §4 defines context-sharing patterns (pods as context domains, pair pattern, HA via mental-model-ha skill + substrate session logs, terminal nodes as common-room, chatroom/substrate/transcripts/Corpus).
- **§7 is the canonical 12-step rig-spec authoring SOP for high-stakes rigs — use it instead of the baseline "Design Process" below when the rig is ≥4 members, uses HA, is a managed-app, or will be shared/copied.** The baseline below still applies to small/focused rigs.
- §10 contains the host's bootstrap sequence so you know where your new rig fits.
- §12 has the naming canon and vocabulary mapping to shipped terms.
5. **`building-agent-software` skill** if available in your skill catalog. Design principles for agent-facing tools and surfaces. Relevant when your rig ships a new CLI, service, or managed app.
**Load as needed:**
- Domain-specific skills when designing specialist agents — find shipped skills inside the OpenRig installation under the `specs/agents/` tree
@@ -218,10 +233,9 @@ For rigs that reuse builtin agents, the agents directory is often unnecessary
4. **Write role guidance** for each custom agent — who they are, what they do
5. **Write startup context** for agents that need environment grounding
6. **Validate:** `rig spec validate rig.yaml` and `rig agent validate agents/*/agent.yaml`
7. **Audit authoring completeness:** `rig spec audit rig.yaml` — advisory findings identify missing culture or startup context without blocking launch.
8. **Confirm the runtime cwd** — do not assume agents should work from the directory where the rig spec is stored. The spec root controls file resolution; the runtime cwd controls trust, project guidance, permissions, and repo context.
9. **Launch:** `rig up rig.yaml --cwd /path/to/project`
10. **Verify:** `rig ps --nodes` — all agents ready? Check `rig capture` on each agent.
7. **Confirm the runtime cwd** — do not assume agents should work from the directory where the rig spec is stored. The spec root controls file resolution; the runtime cwd controls trust, project guidance, permissions, and repo context.
8. **Launch:** `rig up rig.yaml --cwd /path/to/project`
9. **Verify:** `rig ps --nodes` — all agents ready? Check `rig capture` on each agent.
### Validation Is Non-Negotiable
@@ -229,10 +243,11 @@ Always validate before launching:
```bash
rig spec validate rig.yaml
rig spec audit rig.yaml
rig agent validate agents/my-agent/agent.yaml
```
Then run `rig spec audit rig.yaml` for advisory checks such as stale seat references and other cross-file drift that schema validation cannot detect.
If validation fails, fix the errors. Do not try to launch an invalid spec — it will fail with a less helpful error.
## Diagnosis: When Things Go Wrong
@@ -9,11 +9,6 @@ description: >
metadata:
openrig:
stage: candidate
distribution_scope: product-bound
source_evidence: |
cmux is OpenRig's shipped terminal provider generalized onto `rig terminal <provider>` —
best-effort, not proof-gated. Authored clean-room.
transfer_test: pending
sibling_skills:
- openrig-herdr
- openrig-user
@@ -10,11 +10,6 @@ description: >
metadata:
openrig:
stage: candidate
distribution_scope: product-bound
source_evidence: |
Empirical herdr 0.7.1 hands-on findings + the ratified implementation PRD. Authored
clean-room (patterns only, no herdr source text; AGPL arm's-length).
transfer_test: pending
sibling_skills:
- openrig-cmux
- openrig-user
@@ -51,7 +46,7 @@ An agent asked "open all my rigs plus a mission as views" runs one `open` per ta
```bash
rig terminal open acme-web # a whole rig, live agents as tiles
rig terminal open mission:site-relaunch # exactly the agents working the mission
rig terminal open slice:02-search-filters # the agents working one slice
rig terminal open slice:search-filters # the agents working one slice
```
No hand-listing of seats: the mission/slice membership is derived from live topology at open time.
@@ -1,142 +0,0 @@
---
name: openrig-installer
description: Use when installing or upgrading OpenRig on a host, especially the V0.3.1 upgrade flow which includes the substrate-kernel → daemon-managed-kernel migration ceremony. Covers npm install, rig setup, rig daemon start (auto-boots kernel), and the canonical verification commands. NOT for ordinary kernel operation post-install — use openrig-operator skill for that.
metadata:
openrig:
maturity: L2
distribution_scope: shipped
source_evidence: V0.3.1 slice 05-kernel-rig-as-default IMPLEMENTATION-PRD §8 + OQ-A=B migration-ceremony decision
---
# OpenRig Installer
This skill teaches the operator agent how to install + upgrade
OpenRig cleanly. The V0.3.1 upgrade is the one with the migration
ceremony (substrate kernel → daemon-managed kernel); other upgrades
follow the same install / setup / start shape with no migration.
## Fresh install
```bash
npm install -g @openrig/cli
rig setup
```
`rig setup` is idempotent — safe to re-run if a step fails. It probes
host prereqs (tmux present, Node version, writable state path,
optional cmux), then invokes `rig daemon start` per the L2 factoring
(OQ-B). The daemon's start path auto-boots the kernel rig per the
V0.3.1 slice 05 kernel-rig-as-default logic.
## Verification after install
```bash
rig ps --nodes --rig kernel --json
```
Should report 4 members (advisor.lead + operator.agent +
operator.human + queue.worker) all ready. If a runtime is unavailable
the daemon picks the matching variant (`rig-claude-only.yaml` or
`rig-codex-only.yaml`); the topology stays the same shape with the
unavailable runtime omitted from the agent membership.
Entry point for chatting with the rig:
```bash
rig capture advisor-lead@kernel
```
Or click the CMUX button on the topology graph in the UI at
`/topology`.
## V0.3.1 upgrade ceremony (one-time migration)
Operators with a kernel spec stored outside the daemon-managed
location (any pre-V0.3.1 layout, typically wherever you kept your
own `rigs/kernel/` directory) must migrate to
`~/.openrig/specs/rigs/kernel/` as a one-time step during the V0.3.1
upgrade. The V0.3.1 upgrade IS the migration moment; it's not a
separate ceremony.
### Migration steps
1. **Snapshot first.** Take a snapshot of the running substrate
kernel so the migration is reversible:
```bash
rig snapshot kernel
```
2. **Stop the substrate kernel** (so the migration doesn't race a
running rig):
```bash
rig down kernel --snapshot
```
3. **Copy your existing kernel spec** into the daemon-managed
location:
```bash
mkdir -p ~/.openrig/specs/rigs/kernel
cp -r /path/to/old/kernel-spec/* ~/.openrig/specs/rigs/kernel/
```
4. **Upgrade the CLI + daemon**:
```bash
npm install -g @openrig/[email protected]
rig daemon stop
rig daemon start
```
At this point the new daemon detects `~/.openrig/specs/rigs/kernel.yaml`
exists and skips the V0.3.1 builtin-kernel boot (the
already-managed-rig branch). The substrate-rooted topology
continues to run under daemon management.
5. **Verify** the migrated kernel matches expectations:
```bash
rig ps --nodes --rig kernel --json
```
6. **Decommission the old copy** (only after verifying the
daemon-managed copy works):
```bash
rm -rf /path/to/old/kernel-spec
```
### If migration fails
The pre-step snapshot is the rollback. `rig restore <snapshot-id>
--rig kernel` revives the prior topology. Then `npm install -g
@openrig/cli@0.3.0` rolls the CLI back and you can retry later.
## Operator agent's role in install + upgrade
The operator agent shepherds operators through these steps when the
user asks "how do I upgrade?" or "what's the V0.3.1 ceremony?". The
agent reads this skill on demand via `find-skills` — it does not
need to memorize the steps; it consults the canonical reference
(this file) and walks the operator through.
## 3-part error remediation
| What failed | Why it matters | Fix |
|---|---|---|
| `npm install -g @openrig/cli` permission denied | Global install needs writable npm prefix; macOS Homebrew default is usually writable; some custom Node installs aren't | Either fix the npm prefix permissions or use `sudo npm install -g`; check `npm config get prefix` |
| `rig setup` host prereq fail | tmux, Node version, or writable state path missing | `rig doctor` lists each missing piece + the install command; run those, retry `rig setup` |
| `rig daemon start` auth-block error | Neither Claude Code nor Codex authenticated; kernel rig requires at least one | Run `claude auth login` OR `codex login`; then retry `rig daemon start` |
| `rig daemon start` "kernel already managed" | An existing managed rig named `kernel` exists; the daemon skips builtin-boot per design | This is the expected path after migration — no action needed |
| `rig ps --rig kernel --json` returns empty | Daemon healthy but no kernel rig managed; likely the migration step copied content but did not boot | `rig up kernel` from inside `~/.openrig/specs/rigs/kernel/`; or invoke the daemon's cold-boot path explicitly |
## What this skill is NOT
- Not the canonical OpenRig command surface; that lives in the
`openrig-user` skill.
- Not the kernel-operating-procedure for post-install daily use;
that's `openrig-operator`.
- Not for project rigs; project rigs install themselves via `rig
up <spec>` after the kernel is in place.
@@ -1,110 +0,0 @@
---
name: openrig-operator
description: Use when operating or debugging host-side OpenRig runtime issues including daemon reachability, partial identity, unified-exec warnings, stale helper-process cleanup, or when distinguishing harness/process issues from live topology health.
---
# OpenRig Operator
## Overview
This skill covers host/runtime/operator triage around OpenRig itself.
Use it when the problem may be the daemon, the shell/runtime surface, or stale helper processes rather than the product workflow you are trying to run.
## When to Use
Use this skill when you see:
- `rig whoami --json` returning partial identity
- `rig ps --nodes -A --json` failing while some other `rig` commands still work
- `Sent to ...` plus `Verified: no`
- repeated unified-exec-process warnings
- suspicion that stale helper processes are accumulating
Do not use this skill for normal product workflow routing, queue handling, or ordinary peer communication. Use `openrig-user` for that.
## First Checks
Start with the minimum truthful operator read:
```bash
rig whoami --json
rig daemon status
rig ps --nodes -A --json
```
Interpret them together, not in isolation:
- partial `whoami` can mean identity is inferable while daemon-backed surfaces are degraded
- `daemon status` tells you whether the host daemon is up, not whether every seat can reach it cleanly
- `ps --nodes -A --json` is the best machine-readable fleet topology check when it works (v0.4.4: `--nodes` needs an explicit scope outside a managed session — `-A` for fleet, `--rig <name>` for one rig; the bare `rig ps` map is the cheap first glance)
## Verification Drift Vs Send Failure
For `rig send`:
- `Sent to ...` + `Verified: yes` = strong positive delivery evidence
- `Sent to ...` + `Verified: no` = ambiguous delivery, not automatic failure
- no `Sent to ...` line or a hard error = send failure
When verification is ambiguous, check:
- direct reply
- `rig capture <session>`
- transcript evidence
- queue/outbox state if the message asked for a durable handoff
Do not blindly retry until you have checked one of those.
## Unified Exec Warning
If you see:
- `Warning: The maximum number of unified exec processes you can keep open is 60 ...`
treat it first as a host/tooling-layer warning, not as automatic proof that the OpenRig topology is unhealthy.
This warning can coexist with a healthy live topology.
## Safe Process Triage
Inspect the process surface first:
```bash
ps -axo pid,ppid,command | rg 'tmux send-keys|rig queue create|tmux attach|codex|claude'
```
Think in layers:
- host/tooling layer: stale one-shot wrappers, session bookkeeping, helper shells
- topology layer: live `tmux attach` seats, live `codex` / `claude` runtimes, daemon health
Do not diagnose topology failure from tooling-layer warnings alone.
## Safe Cleanup Boundary
Usually safe to reap when clearly orphaned / one-shot:
- `tmux send-keys ...`
- short-lived shell wrappers created only to enqueue or send one message
Do not mass-kill:
- `tmux attach ...`
- `codex ...`
- `claude ...`
- other long-lived daemon/runtime processes
The point is to remove garbage, not workers.
## Common Mistakes
- treating `Verified: no` as if it proves the message did not land
- treating the unified-exec warning as if it proves the rig is overloaded
- killing live seats when only stale helper wrappers needed cleanup
- concluding "daemon down" from one seat's failure without checking host-level daemon status
## Practical Rule
Clean the smallest safe surface that matches the evidence.
If the warning or failure remains after stale-wrapper cleanup, re-check:
```bash
rig daemon status
rig ps --nodes -A --json
```
If those remain healthy, the residual issue may still be in the host/tool/session layer rather than in OpenRig topology state.
@@ -0,0 +1,460 @@
---
name: openrig-upgrade
description: Use when upgrading the OpenRig CLI/daemon on a host with running rigs, especially when preserving tmux-backed agent sessions through a daemon restart or documenting hot-upgrade SOP evidence.
metadata:
cli_surfaces_referenced:
- capture
- daemon adopt-state
- daemon start
- daemon status
- daemon stop
- down
- ps
- restore-check
- snapshot
- up
- upgrade backup
- upgrade preflight
- upgrade promote-runtime
- upgrade verify
- version
openrig:
stage: factory-approved
sibling_skills:
- openrig-user
- openrig-operator
- openrig-builder
- openrig-architect
- forming-an-openrig-mental-model
- ai-dev-workflows
---
# OpenRig Upgrade
## Core Principle
OpenRig has two different failure domains:
- **Agent process plane:** Claude/Codex/terminal seats running inside tmux.
- **Management plane:** the OpenRig daemon, CLI, SQLite DB, transcripts, node inventory,
send/capture APIs, restore metadata, and migrations.
A hot daemon upgrade is possible when the continuity seats remain alive in tmux and
the new daemon restarts against the same DB and transcript root. Do not run
`rig down` on continuity rigs unless the goal is a disruptive restore test; `rig down`
kills OpenRig-launched tmux sessions.
## Preferred Live-Cutover Operator Mode
For live production daemon cutovers, prefer an **out-of-band upgrade operator**:
a temporary host-local tmux seat outside the managed OpenRig topology, spawned
from the lifecycle/runtime-upgrade agent's current mental model.
Why: the managed rig stays in the agent process plane while a disposable sidecar
mutates the management plane. The sidecar inherits enough context to avoid a
cold handoff, but it is not inside the failure domain it is modifying.
Use this when all are true:
- the upgrade mutates the live daemon, CLI wrapper, DB, runtime worktree, tmux
lifecycle, or active control-plane truth;
- continuity seats should keep working during the upgrade;
- a lifecycle/runtime-upgrade seat has already prepared the packet or owns the
needed context;
- the human has granted an `operator auto window`.
In this SOP, `operator auto window` means a bounded operator-authorized upgrade lane. It does not
mean standing Codex `auto_review`, `--full-auto`, or approval-bypass mode. Use
`security-and-consequence-boundary-policy` skill for the current
security and consequence-boundary policy.
Do not use this pattern as a standing orchestration seat. The sidecar exists for
one cutover and then closes after handback.
### Sidecar Contract
The in-rig lifecycle/runtime-upgrade seat owns packet preparation and final
interpretation. The out-of-band sidecar owns only execution inside the approved
window.
Sidecar starter prompt shape:
```text
You are the host-local OpenRig runtime upgrade operator, outside the managed rig
topology. Execute the approved daemon-only cutover only after explicit human
approval. First read the upgrade preflight artifact and runtime-upgrade
decision. Prove you are outside the topology before mutation. Never run rig
down. Preserve tmux topology. Stop/start only the daemon, verify protected rigs,
write cutover evidence, unblock downstream artifacts only when the blocker is
truly closed, and rollback to <previous-wrapper-or-commit> if needed.
```
Required handback:
- write the live cutover evidence under the lifecycle evidence shelf;
- include proof that the sidecar was outside the topology/failure domain it
mutated;
- update any blocked downstream dogfood/runtime task only when the blocking
condition is truly closed;
- preserve caveats as downstream material instead of using them to reopen a
closed cutover gate;
- report back to the in-rig lifecycle/runtime-upgrade seat or orch surface with
daemon provenance, topology verification, caveats, rollback state, and one
compact paragraph of operator judgment about ambiguous choices;
- close the sidecar after the original lifecycle owner has absorbed the result.
Stop conditions for the sidecar:
- preflight or runtime-upgrade decision is missing;
- human approval is absent or narrower than the requested cutover;
- protected topology is already degraded beyond the packet's expected caveats;
- target runtime cannot be verified by process path, port listener, and command
evidence;
- any step would require `rig down` or destructive DB restore without a new
explicit human decision.
Generic primitive: this upgrade specialization composes over the
`sidecar-operator` skill (the underlying out-of-band-operator pattern;
this skill is the upgrade-specific specialization).
## What Changed On 2026-04-27
Initial belief:
- All rigs had to be down before daemon restart.
- Live upgrade was research-gated because DB migrations might break session/node
state while sessions were running.
- A parallel isolated daemon/adoption path looked necessary before production use.
Observed result:
- A daemon-only hot cutover preserved the live `example-seat` tmux
sessions.
- The old daemon was stopped without running `rig down`.
- The new source-pinned daemon started against the same production DB.
- `rig ps --nodes --json`, `rig capture`, and `rig restore-check` could inspect the
still-running Velocity seats after restart.
The simpler model is now preferred for tmux-backed continuity rigs: snapshot and
back up state, stop only the daemon, start the new daemon, then verify that live
sessions are still observable and manageable.
## Proven Hot Path
Use this as the canonical first-choice workflow for a host where continuity rigs
are tmux-backed and the operator wants non-disruptive daemon upgrade.
0. **Spawn the out-of-band operator when live cutover is required.**
The sidecar must be host-local and outside the managed topology being
upgraded. Keep the lifecycle/runtime-upgrade owner inside the rig so it can
continue to observe, ask questions, and absorb the handback.
1. **Choose continuity targets.**
Name the exact rigs that must remain live. Everything else is source material.
Do not let "nice to resume later" rigs expand the success criteria.
2. **Freeze active work.**
Get continuity seats to a stable/idle checkpoint. Record resume commands if
available.
3. **Inventory with filters.**
Do not dump full `rig ps` output on this host. Use filtered JSON:
```bash
rig ps --nodes --json \
| jq -r 'map(select(.rigName=="<rig>")) | sort_by(.canonicalSessionName)[] | "\(.canonicalSessionName) \(.sessionStatus) \(.startupStatus) \(.resumeToken // "none")"'
```
4. **Take a non-destructive snapshot of each continuity rig.**
This records rollback/recovery metadata without killing tmux sessions:
```bash
rig snapshot <rigId>
```
Verify the snapshot payload in SQLite has the expected nodes, sessions,
checkpoints, and resume tokens.
5. **Create a post-snapshot SQLite backup.**
Use SQLite's online backup API while the daemon is live. Then run
`PRAGMA integrity_check` on the backup and verify it contains the continuity
snapshot.
6. **Prepare a clean runtime artifact.**
Prefer a dedicated clean source worktree pinned to a commit:
```bash
git worktree add --detach /path/to/openrig-runtime-<shortsha> <commit>
cd /path/to/openrig-runtime-<shortsha>
PATH=/path/to/node22/bin:$PATH npm ci
PATH=/path/to/node22/bin:$PATH npm run build
```
Use even/LTS Node. The 2026-04-27 upgrade used Node `v22.22.1`.
7. **Stop only the daemon.**
First try:
```bash
rig daemon stop
```
If the daemon state file is missing but the PID is known and verified as the
OpenRig daemon, gracefully terminate that PID:
```bash
kill -TERM <daemonPid>
```
Do not use `kill -9` unless recovering from a wedged process with human
approval. Do not run `rig down` on continuity rigs.
8. **Start the pinned daemon against the same production DB.**
```bash
PATH=/path/to/node22/bin:$PATH \
node packages/cli/dist/index.js daemon start \
--port 7433 \
--host 127.0.0.1 \
--db ~/.openrig/openrig.sqlite
```
9. **Verify management continuity.**
Required checks:
```bash
rig daemon status
lsof -nP -iTCP:7433 -sTCP:LISTEN
rig ps --nodes --json | jq -r 'map(select(.rigName=="<rig>")) | ...'
rig capture --rig <rig> --lines 1 --json
rig restore-check --rig <rig>
```
Success means the daemon is healthy, continuity sessions remain running/ready,
capture works, transcripts are present, and `restore-check` reports no red
blockers.
10. **Align the default CLI with the new daemon.**
If `rig` is a wrapper, make sure it delegates to the new CLI. On the
2026-04-27 host this meant repointing the rigx real CLI via
`~/.openrig/bin/rig-real-17812d5`.
11. **Write evidence and hand back.**
The sidecar writes a cutover evidence packet with daemon provenance,
protected topology counts, representative capture/restore checks, smoke
results, caveats, and rollback state. Then it notifies the original in-rig
lifecycle/runtime-upgrade owner. Do not rely on chat as the only proof.
## 2026-04-27 Proof Point
Continuity target:
- `example-seat`
Pinned daemon:
- commit `17812d5d3bfe53dfdc5e202b1da3e8c91e2f4e54`
- subject `feat(agents): make runtime config spec-driven`
- committed `2026-04-26T18:30:08-07:00`
- runtime worktree `~/code/projects/openrig-runtime-17812d5`
Evidence:
- Velocity snapshot `01KQ84D3AF9YW6FQCM9SVSM5EG`
- post-snapshot DB backup
`db-backup/openrig-post-velocity-snapshot-20260427T185003Z.sqlite`
- backup integrity `ok`
- old daemon PID `62828`, Node 25 global npm install
- new daemon PID `39708`, Node 22 source runtime
- post-cutover `example-seat`: 4/4 seats `running` / `ready`
- `rig restore-check --rig example-seat`: `RESTORABLE WITH CAVEATS`,
`20 green | 9 yellow | 0 red`, `RECOVERY: NOT NEEDED`
Important caveat: this proves hot daemon cutover for tmux-backed Claude seats on
this host and commit range. It does not prove that arbitrary migrations,
non-tmux runtimes, service-backed rigs, or dead sessions can be recovered without
separate testing.
## 2026-05-02 Proof Point
Continuity targets:
- `kernel`
- `openrig-discovery`
- `openrig-dogfood`
- `openrig-lifecycle`
- `openrig-maintenance`
- `openrig-product-lab`
- `example-rig`
- `example-seat`
Pinned daemon:
- commit `6af2754824a07291562622ac019b68615fc41abe`
- runtime worktree `~/code/projects/openrig-runtime-6af2754`
- wrapper `~/.openrig/bin/rig-real-6af2754`
Pattern proven:
- lifecycle/runtime-upgrade prepared the decision and preflight artifacts;
- a host-local tmux sidecar (`host-upgrade-operator-6af2754`) was spawned
outside the managed topology with the current operator context;
- the sidecar stopped only the daemon, using verified PID fallback after
`rig daemon stop` refused due to missing daemon state;
- the sidecar started the target daemon on port `7433`, repointed the
config-layer wrapper default, verified protected topology, ran targeted
Agent Starter smoke/tests, wrote evidence, and unblocked Dogfood;
- Velocity delivery continued working throughout the cutover.
Evidence:
- preflight:
(internal upgrade-preflight evidence, 2026-05-01)
- live cutover:
(internal live-cutover evidence, 2026-05-02)
Important caveat: live `rig up --plan --json` accepted valid `starter_ref`
specs and rejected forbidden compositions, but plan-mode output did not emit the
`resolve_starter.detail.starterContent` stage expected by the Dogfood proof bar.
This is a product/dogfood caveat, not an upgrade failure.
## Brittle Edges Observed On 2026-04-27
Detailed field note:
(internal upgrade-brittleness field note, 2026-04-27)
Operator lessons from the daemon upgrade:
- `rig down` kills OpenRig-launched tmux sessions. Do not use it as a snapshot
primitive when resumability depends on keeping sessions alive.
- Old daemon/CLI combinations can be partially functional even when newer health
checks fail. A `/healthz` mismatch blocked `rig down --snapshot` even though
other daemon APIs still worked.
- `rig daemon stop` can fail when the daemon state file is missing. Operators
need a verified PID fallback, but the product should reconcile daemon state
automatically.
- If the sidecar has an operator auto window and `rig daemon stop` refuses only
because state is stale, a verified graceful PID termination is acceptable:
identify the daemon PID, verify its runtime path, send graceful `TERM`, and
verify the port is gone before starting the target daemon.
- CLI and daemon provenance can drift. Repointing or verifying the default
`rig` wrapper is part of the upgrade, not an afterthought.
- Raw `rig ps` is too noisy on this host. Use filtered JSON until the product
has compact first-class inventory views.
- Snapshot and backup verification is too manual. The SOP currently depends on
checking snapshot rows, resume tokens, SQLite backups, and integrity by hand.
Separate follow-on note, not part of the daemon-upgrade SOP:
(internal add-node-brittleness field note, 2026-04-27)
## Disruptive Restore Path
Use disruptive restore when the goal is to test recovery from killed sessions, or
when hot upgrade is blocked by incompatible migrations or corrupted management
state.
```bash
rig snapshot <rigId>
rig down <rigId>
# upgrade daemon/CLI
rig up <rigName>
rig restore-check --rig <rigName>
```
Expected restore results:
| Result | Meaning | Action |
|---|---|---|
| `fully_restored` | All nodes resumed or rebuilt | Resume normal work |
| `partially_restored` | Some nodes succeeded, some failed | Inspect failed nodes and relaunch manually |
| `failed` | Zero nodes restored | Check daemon logs, snapshot integrity, provider tokens |
| `not_attempted` | Pre-restore blockers | Fix blockers before retrying |
Do not confuse this path with hot upgrade. `rig down` is intentionally
disruptive.
## Stop Conditions
Do not proceed with hot upgrade if:
- continuity targets are mid-task and cannot checkpoint;
- continuity target tmux sessions are missing before upgrade;
- no verified DB backup exists after continuity snapshots;
- the target runtime cannot build under an even/LTS Node version;
- the daemon migration plan is known to rewrite session/binding semantics in a
way that has not been tested;
- disk space or DB integrity checks fail;
- the operator cannot identify the current daemon PID and runtime source.
## Rollback
Rollback means restoring the previous daemon runtime and, if necessary, the DB
backup.
For source runtime:
1. Stop the new daemon.
2. Start the previous runtime or npm/global daemon.
3. Verify `/healthz`, filtered continuity inventory, and `rig capture`.
4. Restore the DB backup only if migration or DB corruption is confirmed. Do not
replace the DB just because continuity sessions are still live but management
projection is degraded.
For npm runtime:
```bash
npm install -g @openrig/cli@<previous-version>
rig daemon stop
rig daemon start
```
## Roadmap: Better Hot Upgrades
The product should make the proven manual path boring and explicit.
Needed product surfaces:
- `rig upgrade preflight`:
daemon PID/runtime source, CLI source, DB path, migration plan, active rigs,
continuity targets, tmux liveness, disk space, DB integrity, backup target,
and rollback runtime.
- `rig daemon adopt-state` or equivalent:
recover a healthy daemon on a port when `daemon.json` is missing.
- `rig upgrade backup`:
online SQLite backup plus integrity and snapshot-presence verification.
- `rig upgrade promote-runtime <commit|artifact>`:
start from a clean worktree or packaged artifact under an even/LTS Node.
- `rig upgrade verify --rig <name>`:
filtered inventory, capture, transcript, restore-check, and honest continuity
classification.
- CLI/daemon provenance:
`rig version --json` should report CLI path, daemon path, commit/package
version, Node version, DB path, and started-at.
- Wrapper alignment:
rigx/default `rig` should clearly show which real CLI it delegates to.
- Compact inventory:
first-class `rig ps --rig <name> --nodes --compact` or equivalent, so
operators do not need ad hoc `jq` for routine safety checks.
Research still needed:
1. Migration-bearing hot upgrade on a throwaway rig.
2. Hot upgrade with non-critical live Codex seats.
3. Hot upgrade with service-backed rigs.
4. Adoption/reconciliation when daemon DB says sessions are running but tmux has
partially drifted.
5. Automated rollback on daemon startup failure or migration failure.
## Operator Summary
Hot upgrade rule:
**Snapshot continuity rigs, back up the DB, stop only the daemon, start the new
daemon against the same DB, then verify live tmux sessions through filtered
management surfaces.**
Disruptive restore rule:
**Use `rig down` only when testing or accepting session teardown.**
@@ -1,153 +0,0 @@
---
name: openrig-user-settings
description: Use when the user asks an OpenRig agent to read or change OpenRig configuration settings — workspace paths, file allowlists, progress scan roots, daemon port/host, transcripts, or anything stored in ~/.openrig/config.json
---
# OpenRig User Settings
OpenRig settings live in `~/.openrig/config.json` and are managed via the
`rig config` CLI family. The agent-editable surface is **CLI shell-out**;
do NOT write the JSON file directly unless the operator specifically asks
for raw-text editing (which is handled by the UI Files browser, not by you).
## Read
```bash
rig config # all keys, value + source
rig config --json # JSON: full RiggedConfig
rig config --json --with-source # JSON: {key: {value, source, default}}
rig config get <key> # single value
rig config get <key> --show-source # value + source on one line
rig config get <key> --json # {value, source, default}
```
Resolution order: **env var > config file > default**. Always use
`--show-source` (or `--json`) when reporting back to the operator so they
see *where* the value came from.
## Write
```bash
rig config set <key> <value> # set a key
rig config reset <key> # clear one override (revert to default)
rig config reset # delete the whole file
```
## Initialize a default workspace
```bash
rig config init-workspace # scaffold ~/.openrig/workspace/ with missions + slices
rig config init-workspace --dry-run # show what would be created
rig config init-workspace --root /path # use a custom root
rig config init-workspace --force # overwrite scaffolded files (NOT operator content)
```
This creates a file-backed Project workspace under the workspace root:
```text
README.md
STEERING.md
missions/<mission-id>/README.md
missions/<mission-id>/PROGRESS.md
missions/<mission-id>/slices/<slice-id>/README.md
progress/
field-notes/
specs/
```
It seeds two starter missions with multiple slices so the Project UI has a
real mission/slice map out of the box. It is operator-explicit; do NOT run it
on your own initiative unless the operator asks for workspace initialization
or repair.
## Common keys
| Key | Type | Purpose |
|---|---|---|
| `daemon.port` | number | OpenRig daemon HTTP port (default 7433) |
| `daemon.host` | string | Daemon bind host (default 127.0.0.1) |
| `db.path` | string | SQLite DB path (default ~/.openrig/openrig.sqlite) |
| `transcripts.enabled` | boolean | Whether the daemon writes transcripts |
| `transcripts.path` | string | Transcripts dir (default ~/.openrig/transcripts) |
| `workspace.root` | string | Single-root override (default ~/.openrig/workspace) |
| `workspace.slices_root` | string | Slice discovery root; default `<root>/missions` |
| `workspace.steering_path` | string | STEERING.md path; default `<root>/STEERING.md` |
| `workspace.field_notes_root` | string | Field notes dir; default `<root>/field-notes` |
| `workspace.specs_root` | string | Specs dir; default `<root>/specs` |
| `files.allowlist` | string | `name:/abs/path,name:/abs/path` — UI Files browser roots |
| `progress.scan_roots` | string | `name:/abs/path,name:/abs/path` — Progress browse roots |
Resolution order for workspace per-subdir keys: per-subdir override >
`workspace.root` cascade > built-in default.
## Common operator requests → canonical commands
> **"Make the UI work against an existing workspace layout"**:
> set the per-subdir workspace overrides explicitly:
>
> ```bash
> rig config set workspace.slices_root /path/to/your/workspace/missions
> rig config set workspace.steering_path /path/to/your/workspace/STEERING.md
> rig config set workspace.progress_scan_roots 'work:/path/to/your/workspace,missions:/path/to/your/workspace/missions'
> rig config set workspace.field_notes_root /path/to/your/workspace/field-notes
> ```
>
> No restart needed for the CLI; for the daemon's reads to pick up
> changes affecting startup-time wiring (`files.allowlist`,
> `progress.scan_roots`), restart with `rig daemon restart`.
> **"Initialize a default workspace"**:
>
> ```bash
> rig config init-workspace
> ```
After initialization, the Project UI expects this mapping:
- `workspace.root` maps to the Project workspace.
- `workspace.root/missions/<mission-id>` maps to a Project mission.
- `workspace.root/missions/<mission-id>/slices/<slice-id>` maps to a Project slice.
Queue item bodies or tags should mention the mission id and slice id when the
work belongs to a slice. That lets the Project Story, Queue, Tests, and
Topology tabs attach runtime work to the filesystem slice.
> **"Allow the file browser to see X directory"**:
>
> ```bash
> # Append to existing list (operator decides the name token):
> rig config get files.allowlist --show-source # check current
> rig config set files.allowlist 'workspace:/path/to/ws,docs:/path/to/docs'
> rig daemon restart # picks up new roots
> ```
> **"What's my current setting for X and where does it come from?"**:
>
> ```bash
> rig config get <key> --show-source
> ```
## When NOT to use this skill
- **Per-rig config** — settings are host-global at v0; per-rig is v0+1.
- **Secrets / credentials** — the `vault.specialist` managed-app handles
secrets. Don't put API keys or tokens in `~/.openrig/config.json`.
- **Settings sync across hosts** — out of scope at v0.
## Errors you might see
- `Unknown config key "<x>". Valid keys: …` — the key name is wrong.
Check the table above; suggest the correct key.
- `Config file at <path> is malformed. Fix the JSON or reset with: rig config reset` —
hand-edit broke the JSON. Operator can `rig config reset` (deletes the
whole file) or fix the syntax in the Files browser.
- `Invalid value for <key>: expected a number/true-false, got "<x>"` —
wrong type for a typed key. Reach for the key's type in the table.
## Provenance + safety
- Never write to `~/.openrig/config.json` directly. Use `rig config set`.
- Don't run `rig config init-workspace` on your own initiative — wait for
an operator request.
- Always cite the resolved source (env / file / default) when reporting
values back, so the operator knows whether their change actually took.
Loaded 100 of 116 files, more files were not shown because too many files have changed in this diff. Show more