diff --git a/package.json b/package.json index 770fb088c..87405f774 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,12 @@ "scripts": { "build": "npm run build --workspaces", "test": "npm run test:repo && npm run test:workspaces", - "test:repo": "node --test scripts/*.test.mjs && node scripts/check-docs-guard.mjs", + "test:repo": "node --test scripts/*.test.mjs && node scripts/check-docs-guard.mjs && node scripts/mirror-skills.mjs --check", "test:workspaces": "npm run test --workspaces", "lint": "tsc --noEmit --project packages/daemon/tsconfig.json && tsc --noEmit --project packages/ui/tsconfig.json && tsc --noEmit --project packages/cli/tsconfig.json", - "build:package": "bash scripts/build-package.sh" + "build:package": "bash scripts/build-package.sh", + "mirror-skills": "node scripts/mirror-skills.mjs", + "mirror-skills:check": "node scripts/mirror-skills.mjs --check" }, "engines": { "node": "^20 || ^22 || ^24" diff --git a/scripts/mirror-skills.mjs b/scripts/mirror-skills.mjs new file mode 100644 index 000000000..eb97cdfc5 --- /dev/null +++ b/scripts/mirror-skills.mjs @@ -0,0 +1,118 @@ +import { execFileSync } from "node:child_process"; +import { existsSync, mkdirSync } from "node:fs"; +import { resolve } from "node:path"; + +// Mirror canonical skills from packages/daemon/specs/agents/shared/skills/ +// to /skills/_canonical/. Hand-authored files at /skills/ +// (README, CHANGELOG, LICENSE, plugin manifests) live alongside _canonical/ +// and are NEVER touched by the mirror — strict-ownership lets us add new +// top-level files without coupling the script to the destination shape. + +export const SOURCE_DIR = "packages/daemon/specs/agents/shared/skills/"; +export const TARGET_DIR = "skills/_canonical/"; + +export const EXCLUDES = [ + "feedback.md", + "evals/", + ".DS_Store", + "*.local.md", +]; + +function rsyncArgs({ dryRun }) { + // --checksum compares file contents via hash instead of mtime+size. + // Used in --check (dry-run) mode so the drift-detect is content-stable + // — a `git checkout` or `cp` updating mtimes does NOT register as drift + // when the bytes match. In apply mode we keep the default (mtime+size) + // for speed; rsync's archive flag preserves mtime so subsequent checks + // stay clean. + return [ + "-a", + "--delete", + "--delete-excluded", + "--itemize-changes", + ...(dryRun ? ["-n", "--checksum"] : []), + ...EXCLUDES.map((p) => `--exclude=${p}`), + SOURCE_DIR, + TARGET_DIR, + ]; +} + +// Parse rsync --itemize-changes output for content-meaningful changes. +// First-column codes per rsync(1): +// `<` / `>` — file transferred (content change) +// `c` — created entry (file/dir/symlink/device) +// `h` — hardlink redirected +// `.` — item exists with NO update OR metadata-only update +// (we want to ignore these — content is stable) +// `*` — message line; we only care about `*deleting ` +// In --check mode the script invokes rsync with `--checksum`, so a `.` +// leading line means the bytes match even if mtime drifts (e.g., after +// `git checkout` or `cp`); we deliberately skip those to keep the +// drift-detect content-stable. +export function parseChanges(output) { + const lines = output.split("\n").filter(Boolean); + return lines.filter( + (line) => + /^[<>ch][fdLDS]/.test(line.slice(0, 2)) || + line.startsWith("*deleting "), + ); +} + +export function buildStaleMessage(changes) { + return [ + "Skills mirror is stale at skills/_canonical/. Run: npm run mirror-skills", + "Changes that would land:", + ...changes.map((c) => ` ${c}`), + ].join("\n"); +} + +function runRsync({ dryRun }, exec = execFileSync) { + return exec("rsync", rsyncArgs({ dryRun }), { + encoding: "utf8", + stdio: ["ignore", "pipe", "inherit"], + }); +} + +function ensureTargetExists() { + if (!existsSync(TARGET_DIR)) { + mkdirSync(TARGET_DIR, { recursive: true }); + } +} + +export function checkMode(exec = execFileSync) { + ensureTargetExists(); + const output = runRsync({ dryRun: true }, exec); + const changes = parseChanges(output); + return { stale: changes.length > 0, changes, output }; +} + +export function applyMode(exec = execFileSync) { + ensureTargetExists(); + return runRsync({ dryRun: false }, exec); +} + +export function main(argv = process.argv.slice(2)) { + const isCheck = argv.includes("--check"); + + if (isCheck) { + const { stale, changes } = checkMode(); + if (stale) { + console.error(buildStaleMessage(changes)); + process.exitCode = 1; + } + return; + } + + const output = applyMode(); + const changes = parseChanges(output); + if (changes.length === 0) { + console.log("Skills mirror already in sync; no changes."); + } else { + console.log(`Skills mirror updated. ${changes.length} change(s):`); + for (const c of changes) console.log(` ${c}`); + } +} + +if (import.meta.url === `file://${resolve(process.argv[1])}`) { + main(); +} diff --git a/scripts/mirror-skills.test.mjs b/scripts/mirror-skills.test.mjs new file mode 100644 index 000000000..4180d4c2f --- /dev/null +++ b/scripts/mirror-skills.test.mjs @@ -0,0 +1,140 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { execFileSync } from "node:child_process"; +import { existsSync, readdirSync, statSync } from "node:fs"; +import { join } from "node:path"; +import { + SOURCE_DIR, + TARGET_DIR, + EXCLUDES, + parseChanges, + buildStaleMessage, + checkMode, +} from "./mirror-skills.mjs"; + +test("parseChanges extracts file-change and deletion lines from itemize-changes output", () => { + const output = [ + "sending incremental file list", + ">f+++++++++ core/openrig-user/SKILL.md", + ">f.st...... pm/plan-review/SKILL.md", + "cd+++++++++ pods/", + "*deleting old/skill-that-was-removed/SKILL.md", + "", + "sent 1234 bytes received 56 bytes 2580.00 bytes/sec", + "total size is 100 speedup is 0.08", + ].join("\n"); + + const changes = parseChanges(output); + assert.deepEqual(changes, [ + ">f+++++++++ core/openrig-user/SKILL.md", + ">f.st...... pm/plan-review/SKILL.md", + "cd+++++++++ pods/", + "*deleting old/skill-that-was-removed/SKILL.md", + ]); +}); + +test("parseChanges returns empty array on a clean (already-mirrored) run", () => { + const output = [ + "sending incremental file list", + "", + "sent 100 bytes received 50 bytes 300.00 bytes/sec", + "total size is 100 speedup is 0.67", + ].join("\n"); + + assert.deepEqual(parseChanges(output), []); +}); + +test("buildStaleMessage names the npm script and lists the pending changes", () => { + const message = buildStaleMessage([ + ">f+++++++++ core/openrig-user/SKILL.md", + "*deleting removed/SKILL.md", + ]); + + assert.match(message, /Skills mirror is stale/); + assert.match(message, /npm run mirror-skills/); + assert.match(message, /core\/openrig-user\/SKILL\.md/); + assert.match(message, /removed\/SKILL\.md/); +}); + +test("EXCLUDES bars curation-cycle bookkeeping and runtime artifacts from public surface", () => { + // These exclusions are load-bearing — see SOP rule "feedback.md is + // curation-cycle bookkeeping; runtime mirrors are for agent-loaded + // skill content" (Cycle 2 retro). evals/ is per-skill eval-pilot + // infrastructure (cases.yaml + harnesses + outcomes); it can leak + // nested .agents/skills/ test fixtures that confuse skill inventory + // tooling (Cycle 9 fixup retro 2026-05-09). + assert.ok(EXCLUDES.includes("feedback.md")); + assert.ok(EXCLUDES.includes("evals/")); +}); + +test("source SKILL.md inventory is non-empty (sanity check)", () => { + // If this fails, either the source path moved or the package layout + // changed; fix the SOURCE_DIR constant in mirror-skills.mjs. + assert.ok(existsSync(SOURCE_DIR), `expected ${SOURCE_DIR} to exist`); + const skills = walkSkillFiles(SOURCE_DIR); + assert.ok( + skills.length > 0, + `expected at least one SKILL.md under ${SOURCE_DIR}`, + ); +}); + +test("mirror is in sync with source (drift-detect via --check)", () => { + // The load-bearing assertion: skills/_canonical/ must not drift from + // packages/daemon/specs/agents/shared/skills/. Failing this means + // someone edited the source without running `npm run mirror-skills`. + // Fix: run the script and re-commit. + if (!existsSync(TARGET_DIR)) { + // First-time bootstrap: target doesn't exist yet. The check would + // report every source file as a pending change. Skip in that case + // and let the operator run the initial mirror. + return; + } + const { stale, changes } = checkMode(execFileSync); + assert.equal( + stale, + false, + stale + ? `mirror drift detected (${changes.length} change(s)). Run: npm run mirror-skills` + : "", + ); +}); + +test("excluded patterns are absent in the mirror target", () => { + if (!existsSync(TARGET_DIR)) return; + // Walk the target and assert nothing matches feedback.md / evals/ / + // .DS_Store / *.local.md. The rsync exclusions should keep these + // absent; this catches the case where the script was bypassed and + // someone hand-copied content into _canonical/. + const offenders = []; + walk(TARGET_DIR, (path) => { + const base = path.split("/").pop(); + if (base === "feedback.md") offenders.push(path); + if (base === ".DS_Store") offenders.push(path); + if (/\.local\.md$/.test(base)) offenders.push(path); + if (path.includes("/evals/")) offenders.push(path); + }); + assert.deepEqual( + offenders, + [], + `excluded patterns leaked into mirror: ${offenders.join(", ")}`, + ); +}); + +// --- helpers (test-only) --- + +function walkSkillFiles(root) { + const out = []; + walk(root, (path) => { + if (path.endsWith("/SKILL.md")) out.push(path); + }); + return out; +} + +function walk(root, visit) { + for (const entry of readdirSync(root)) { + const path = join(root, entry); + const s = statSync(path); + if (s.isDirectory()) walk(path, visit); + else visit(path); + } +} diff --git a/skills/CHANGELOG.md b/skills/CHANGELOG.md new file mode 100644 index 000000000..919a8a0eb --- /dev/null +++ b/skills/CHANGELOG.md @@ -0,0 +1,35 @@ +# Skills Changelog + +Append-only log of changes to the canonical skill set, kept per curation +cycle close per `operating-the-skill-library/SKILL.md` v1.9 §8 rule on +`skills/CHANGELOG.md`. New entries land at the top. + +Each entry names: cycle date, what changed, which skills affected. Lets +users tracking the skill set pull in updates independently of the daemon +binary version. + +--- + +## 2026-05-09 — Initial publish: skills hub bootstrap + +First mirror of canonical skills from +`packages/daemon/specs/agents/shared/skills/` to `/skills/_canonical/`. +27 skills published across 4 categories (`core/`, `pm/`, `pods/`, +`process/`) plus 3 uncategorized at the top level +(`claude-compact-in-place/`, `mental-model-ha/`, `rig-architect/`). + +Mechanism: `npm run mirror-skills` (a node script at +`scripts/mirror-skills.mjs` invoking rsync), with `npm run mirror-skills:check` +wired into `npm run test:repo` for drift-detect. + +Why: surfaces the skill set at the repo root so the public-facing skill +library is discoverable without spelunking through `packages/daemon/specs/`. +Structure follows `_canonical/` strict-ownership convention so +hand-authored top-level files (this CHANGELOG, README, LICENSE, future +plugin manifests) survive every mirror run. + +References: +- `operating-the-skill-library/SKILL.md` v1.9 §8 rule "In-repo skills hub" + + rule "skills/CHANGELOG.md". +- Mechanism comparison: + `substrate/shared-docs/openrig-work/lab/skill-authoring-techniques/findings/skills-hub-mirror-mechanism-comparison.md`. diff --git a/skills/LICENSE b/skills/LICENSE new file mode 100644 index 000000000..e0e69a6ed --- /dev/null +++ b/skills/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to the Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by the Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding any notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2026 Mike Schwarz + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/skills/README.md b/skills/README.md new file mode 100644 index 000000000..1f9e11bd4 --- /dev/null +++ b/skills/README.md @@ -0,0 +1,78 @@ +# OpenRig Skills + +This folder is the **publicly-visible mirror** of the canonical skills that +ship with OpenRig — the set of progressive-disclosure context manifests +that OpenRig agents load on demand to do their work well. + +The skills are **mirrored** from the daemon's bundled-skills folder at +`packages/daemon/specs/agents/shared/skills/` into `_canonical/` here, so +that anyone reading the openrig repo can find the skills at the repo root +without spelunking through `packages/daemon/specs/`. + +## What you'll find + +| Path | Contents | +|---|---| +| `_canonical/` | The mirrored skills, organized by category (`core/`, `pm/`, `pods/`, `process/`) plus a few uncategorized at the root. Do not edit files here directly — see "Authoring" below. | +| `CHANGELOG.md` | Append-only log of skill changes per curation cycle close. Hand-authored. | +| `LICENSE` | Apache-2.0, matching the parent project. | + +## What a skill is + +A skill in OpenRig is a **primitive for progressive-disclosure context +injection**, not a unit of capability in the dictionary sense. Frontmatter +sits in the agent's hot tier (cheap pattern-matching against the trigger +description); body loads on activation; references in the folder load on +demand. Read a few `_canonical/*/SKILL.md` files to see the shape — the +frontmatter `description` is the trigger, and the body is what the agent +loads when the trigger matches. + +OpenRig agents discover skills automatically; you generally don't invoke a +skill explicitly. Authoring a skill is about naming a recurring need with +a precise enough trigger that the agent reaches for it at the right moment. + +## Using these skills + +If you're running OpenRig (`npm install -g @openrig/cli` or via tarball), +these skills are already installed for any rig you launch — they ship +inside the daemon. You don't have to do anything. + +If you're reading this folder for reference (without OpenRig installed), +the SKILL.md files are pure markdown with YAML frontmatter; they're +human-readable and self-describing. Each `description` field in the +frontmatter says when to reach for the skill. + +## Authoring + +Skills live in two places during their lifecycle: + +1. **Substrate factory** at `substrate/shared-docs/openrig-work/skills/` + — where new skills are authored, audited, and refined through curation + cycles. Includes `feedback.md` per skill (curation bookkeeping) and + `evals/` per skill (eval-pilot infrastructure). This is the source of + truth for the skill team's ongoing work. + +2. **Product source** at `packages/daemon/specs/agents/shared/skills/` + — the subset of skills that ship with the daemon. Once a skill graduates + to product source, that's what gets bundled into the npm package. + +`/skills/_canonical/` (this folder's `_canonical/`) is mirrored +**from** product source via `npm run mirror-skills`. The mirror is +strictly a copy — never edit `_canonical/` directly; edits in product +source must be propagated by re-running the mirror script before commit. + +## Drift detection + +`npm run test:repo` runs `mirror-skills --check` to detect drift between +product source and `_canonical/`. If you edit a skill in product source +without re-running the mirror, the test fails with a clear message naming +the script to run. CI may also enforce this gate when GitHub Actions +arrives. + +## Future-state + +This folder is structured **as if it were already its own repo** so that a +future `git subtree split --prefix=skills HEAD` is mechanical when growth +warrants. Until then, the in-repo mirror is the right scope: skill changes +ship atomically with the daemon binary that loads them; no version-skew +risk; one PR for both halves. diff --git a/skills/_canonical/claude-compact-in-place/SKILL.md b/skills/_canonical/claude-compact-in-place/SKILL.md new file mode 100644 index 000000000..c13e5bd96 --- /dev/null +++ b/skills/_canonical/claude-compact-in-place/SKILL.md @@ -0,0 +1,100 @@ +--- +name: claude-compact-in-place +description: Use when a Claude Code seat in an OpenRig topology needs compact-in-place recovery or marshal verification after compaction. +--- + +# Claude Compact In Place + +## Purpose + +Use this skill when a Claude Code seat keeps the same OpenRig seat/session after `/compact` and must rebuild enough working context to continue safely. This is not succession, not seat handover, and not a generic memory note. + +Keep two layers separate: + +- **Restore mechanism:** seed from PreCompact output when present, Claude JSONL, touched-files inventory, active queue/session transcript or logs, root docs, and relevant source docs. +- **Acceptance mechanism:** a marshal or peer audits the rebuilt mental model and gives explicit marshal acceptance before the seat resumes real work. + +Do not collapse these layers. A compacted Claude can sound coherent while important files were only injected, grepped, partially read, or not read. + +## Runtime Boundary + +This protocol is for Claude Code compact-in-place. It is not for Codex by default. Codex context management is different; do not intervene on Codex context percentage unless there are behavioral failure signals. + +## Policy Boundary + +The 400k token threshold is a policy target for considering preemptive Claude compaction on a 1M-context session. It is not an automatic action. Unattended compaction requires installed and dogfooded hooks, an audit path, and explicit policy or human authorization. + +Compact one Claude seat at a time unless a human or policy explicitly confirms spare marshal capacity. Do not compact multiple Claude seats at once as a convenience move. + +## Preflight + +Before restoring or auditing, recover canonical identity: + +```bash +rig whoami --json +rig whoami --session --json +``` + +The marshal verifies the target identity, seat name, runtime, active queue state, and transcript path before accepting any restore proof. + +## Required Evidence + +The target Claude should rebuild from concrete evidence, not just the compaction summary: + +- Claude JSONL transcript for the session. +- Generated restore packet or PreCompact output, if present. +- Touched-files inventory and recent git state. +- Active queue file, queue packet body, session transcript, or session logs. +- Rig bootstrap files such as `AGENTS.md`, `CLAUDE.md`, `CULTURE.md`, role guidance, and startup skills. +- Relevant source docs, as-built docs, codemaps, and workstream trackers. + +If a required surface is absent, record it as `NOT-PRESENT`. If it exists but was skipped, record it as `NOT-READ`. + +## Required Proof + +The target must return an asked-vs-read-depth table before claiming readiness: + +| Surface | Source Of Ask | Read Depth | Evidence | +|---|---|---|---| +| `rig whoami --json` | marshal | FULL | canonical seat verified | +| `` | hook/marshal/touched-files | FULL / TARGETED / GREP / INJECTED / NOT-READ / NOT-PRESENT | lines, chunks, command, or reason | + +Allowed depth labels: + +- `FULL`: the whole surface was read after compaction. +- `TARGETED`: selected ranges, head/tail, or named sections were read. +- `GREP`: search excerpts were read. +- `INJECTED`: content was present from hook, system, summary, or prior context, but not freshly read from disk. +- `NOT-READ`: the surface exists but was not read. +- `NOT-PRESENT`: the requested surface does not exist. + +The proof must also include canonical identity, JSONL or restore packet path, active queue items, selected touched files, skipped files with rationale, blockers, and exact next action. + +## Acceptance Rule + +The target may say `awaiting marshal acceptance` or `blocked`. It must not claim `RESTORED`, resume implementation, review, release, architecture, or orchestration work until marshal acceptance is explicit. + +Reject any proof that hides read depth, treats injection as a fresh read, omits queue reconciliation, or says "all docs read" without evidence. + +Accept only when: + +- The seat identity matches the target. +- JSONL or restore artifacts were used, or their absence is explicitly explained. +- Important recent-work files are either `FULL` or explicitly waived. +- `INJECTED`, `TARGETED`, `GREP`, `NOT-READ`, and `NOT-PRESENT` surfaces are named honestly. +- Active queue/session state is reconciled from durable evidence. +- The target did not resume real work before marshal acceptance. + +## Marshal Follow-Up + +Ask these before accepting a clean-sounding proof: + +1. Which files were explicitly assigned, and which did you read in full after compaction? +2. Which files were only injected by hook, summary, system context, or prior context? +3. Which files were partial reads? Give line ranges or chunks. +4. Which touched-files entries were important, and which were skipped? +5. Did any read fail due to size? If yes, did you retry by chunk until complete? +6. Which queue items changed between checkpoint and now? +7. What would be unsafe for you to do before additional reads? + +If a mandatory surface is partial or injected only, ask for a corrected audit before acceptance. diff --git a/skills/_canonical/core/openrig-operator/SKILL.md b/skills/_canonical/core/openrig-operator/SKILL.md new file mode 100644 index 000000000..15470fd5a --- /dev/null +++ b/skills/_canonical/core/openrig-operator/SKILL.md @@ -0,0 +1,110 @@ +--- +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 --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 --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 ` +- 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 --json +``` + +If those remain healthy, the residual issue may still be in the host/tool/session layer rather than in OpenRig topology state. diff --git a/skills/_canonical/core/openrig-user-settings/SKILL.md b/skills/_canonical/core/openrig-user-settings/SKILL.md new file mode 100644 index 000000000..0e4508226 --- /dev/null +++ b/skills/_canonical/core/openrig-user-settings/SKILL.md @@ -0,0 +1,153 @@ +--- +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 # single value +rig config get --show-source # value + source on one line +rig config get --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 # set a key +rig config reset # 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//README.md +missions//PROGRESS.md +missions//slices//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 `/missions` | +| `workspace.steering_path` | string | STEERING.md path; default `/STEERING.md` | +| `workspace.field_notes_root` | string | Field notes dir; default `/field-notes` | +| `workspace.specs_root` | string | Specs dir; default `/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 /Users/me/code/substrate/.../missions +> rig config set workspace.steering_path /Users/me/code/substrate/openrig-work/STEERING.md +> rig config set workspace.progress_scan_roots 'work:/Users/me/code/substrate/openrig-work,missions:/Users/me/code/substrate/openrig-work/missions' +> rig config set workspace.field_notes_root /Users/me/code/substrate/openrig-work/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/` maps to a Project mission. +- `workspace.root/missions//slices/` 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 --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 "". Valid keys: …` — the key name is wrong. + Check the table above; suggest the correct key. +- `Config file at 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 : expected a number/true-false, got ""` — + 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. diff --git a/skills/_canonical/core/openrig-user/SKILL.md b/skills/_canonical/core/openrig-user/SKILL.md new file mode 100644 index 000000000..efb033c09 --- /dev/null +++ b/skills/_canonical/core/openrig-user/SKILL.md @@ -0,0 +1,587 @@ +--- +name: openrig-user +description: Use when operating OpenRig with the `rig` CLI and you need the shipped command surface for identity, inventory, communication, lifecycle, specs, recovery, or agent-facing JSON output. +--- + +# OpenRig User + +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. + +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. + +## Runtime-Gated Coordination Primitives + +OpenRig v0.2.0 includes the bundled PL-004 Coordination Primitive System: Phase A `rig stream` / +`rig queue`, Phase B `rig project` / `rig view`, Phase C `rig watchdog`, and Phase D `rig workflow` +/ `workflow-keepalive`. + +Do not confuse package/source truth with active daemon truth. These commands are shipped product +surfaces in v0.2.0+, but they need a v0.2.0+ daemon and matching SQLite schema at runtime. + +Default posture: + +- Treat daemon `rig queue`, `rig stream`, `rig project`, `rig view`, `rig watchdog`, and + `rig workflow` as the product coordination surfaces when the active daemon is v0.2.0 or newer. +- Use temporary substrate overlays such as `rigx queue`, `rigx stream`, `rigx project`, and + `rigx view-proto` only where the current OpenRig workstream explicitly says that legacy/control + layer is still in use. +- If a daemon-backed coordination command fails, debug the command/runtime/schema edge directly; + do not assume the right workaround is to drop back to a config-layer primitive. +- Do not perform daemon stop/start, production DB copy/mutation, release, publish, or other + consequence-boundary actions unless the operator/workstream has granted that specific gate. + +## Core Loop + +Most work in OpenRig reduces to this loop: +- recover identity: `rig whoami --json` +- inspect inventory: `rig ps --nodes --json` +- read context: `rig transcript ...`, `rig ask ...`, `rig chatroom history ...` +- act: `rig send`, `rig capture`, `rig broadcast`, lifecycle commands + +## Agent-Managed Apps + +An agent-managed app is a deployable OpenRig unit made of: +- the software or service +- one specialist agent dedicated to that software + +Treat the specialist as the domain delegate for that app. +The current canonical example is: +- rig: `secrets-manager` +- pod: `vault` +- member: `specialist` +- logical ID: `vault.specialist` +- session: `vault-specialist@secrets-manager` + +Typical operator loop: + +```bash +rig up secrets-manager --cwd /path/to/project +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 +``` + +Cross-rig communication is valid when the target session resolves uniquely. +Example: + +```bash +rig send vault-specialist@secrets-manager "Read secret/data/dogfood and report the value." --verify +``` + +Use the specialist instead of teaching every peer the same app-specific toolchain. +For Vault, ask `vault.specialist` to do secrets-domain work rather than improvising curl or Vault CLI usage in unrelated agents. + +## Identity and Recovery + +Start here after launch, compaction, or confusion: + +```bash +rig whoami --json +``` + +What it gives you today: +- identity: rig, logical ID, pod/member, session name, runtime +- peers and directional edges +- transcript info +- `contextUsage` when available + +Flags: +```bash +rig whoami --session +rig whoami --node-id +``` + +If the daemon is unreachable but identity can still be inferred, `--json` may return a partial result instead of crashing. + +## Inventory and Monitoring + +```bash +rig ps +rig ps --json +rig ps --nodes +rig ps --nodes --json +``` + +Use `rig ps --nodes --json` for the current node inventory across rigs. It is the best machine-readable operator surface for: +- session name +- runtime +- session/startup status +- restore outcome +- attach/resume commands +- latest error + +Other health surfaces: + +```bash +rig status +rig daemon status +rig config +rig preflight +rig doctor +rig env status +rig env logs +rig env down +``` + +## Transcript and Communication + +### Transcript access + +```bash +rig transcript --tail 100 +rig transcript --grep "pattern" +rig transcript --json +``` + +### Send to one session + +```bash +rig send "message" +rig send "message" --verify +rig send "message" --force +rig send "message" --json +``` + +Use `--verify` when you want delivery evidence. Use `--force` only when you intentionally want to bypass activity-risk checks. + +Observed operator nuance for `--verify`: +- `Sent to ...` + `Verified: yes` = strong positive delivery evidence. +- `Sent to ...` + `Verified: no` = ambiguous delivery, not automatic failure. The message may still land; treat this as verification drift until disproven. +- no `Sent to ...` line or a hard error = send failure. + +When you get `Verified: no`, do not immediately retry blindly. First check one of: +- a direct reply from the target +- `rig capture ` +- transcript evidence +- queue/outbox state if the message asked for a durable handoff + +### Capture terminal output + +```bash +rig capture +rig capture --lines 50 +rig capture --rig +rig capture --pod --rig +rig capture --rig --json +``` + +### Broadcast + +```bash +rig broadcast --rig "message" +rig broadcast --pod "message" +rig broadcast "message" +rig broadcast --rig "message" --json +``` + +Without `--rig` or `--pod`, broadcast targets all running sessions. + +### Chatroom + +```bash +rig chatroom send [--sender ] +rig chatroom history [--topic ] [--after ] [--since ] [--sender ] [--limit ] [--json] +rig chatroom wait [--after ] [--topic ] [--sender ] [--timeout ] [--json] +rig chatroom clear +rig chatroom topic [--body ] [--sender ] +rig chatroom watch [--tmux] +``` + +**Key commands:** +- `send` — post a message +- `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) +- `topic` — set a topic marker +- `watch` — SSE or tmux-based live stream + +**Roundtable protocol:** +1. Inspect old room: `rig chatroom history my-rig --limit 5` +2. Save if needed: `rig chatroom history my-rig --json > /tmp/old-room.json` +3. Clear if needed: `rig chatroom clear my-rig` +4. Set topic: `rig chatroom topic my-rig "ROUND START"` +5. Post: `rig chatroom send my-rig "position..." --sender ` +6. Monitor: `rig chatroom wait my-rig --timeout 120` +7. Close: `rig chatroom topic my-rig "ROUND CLOSED"` + +See `docs/planning/roadmaps/chatroom-roundtable-protocol.md` for the full protocol. + +### `rig ask` + +```bash +rig ask "question" +rig ask "question" --json +``` + +Current shipped behavior: +- queries the daemon for evidence +- returns rig summary +- returns transcript excerpts +- may return chat excerpts +- returns insufficiency state and optional guidance + +This is an evidence/context command. It is not a hidden second-LLM call. + +## Lifecycle + +### Bring a rig up + +```bash +rig up +rig up --plan +rig up --yes +rig up --cwd /path/to/project +rig up --json +``` + +`` can be: +- a rig spec path +- a `.rigbundle` path +- a bare name + +Bare names are special: +- if they match a library spec, `rig up` launches from the spec library +- if they do not match a library spec, `rig up` treats the name as an existing-rig restore/power-on target +- if both exist, `rig up` fails loudly on ambiguity + +Current behavior notes: +- `--target ` is only for `.rigbundle` / package installation. It does not change agent cwd. +- `rig up --cwd` is shipped. `rig up --cwd ` sends a per-run cwd override for all members in that launch. +- `local:` `agent_ref` values resolve relative to the rig spec directory, not your shell cwd. +- if you copy a built-in spec elsewhere, keep its `agents/` tree beside the YAML or rewrite those refs to `path:/absolute/path` +- `rig specs add ` installs a full spec tree when the directory contains `rig.yaml` or `agent.yaml`. + +Legacy/spec-specific surfaces still ship too: + +```bash +rig bootstrap [--plan] [--yes] [--json] +rig requirements [--json] +``` + +### Tear a rig down + +```bash +rig down +rig down --snapshot +rig down --delete +rig down --force +rig down --json +``` + +If `--snapshot` succeeds, human output includes the restore hint. + +### Environment services + +```bash +rig env status +rig env logs [service] +rig env down +``` + +Use these for service-backed rigs and agent-managed apps. +For `secrets-manager`, these are the fastest CLI surfaces for: +- confirming whether Vault is healthy +- reading Vault container logs +- stopping the Vault env without tearing down the specialist session first + +### Release management without killing live claimed sessions + +```bash +rig release +rig release --delete +rig release --json +``` + +Use `rig release` for adopted/claimed-session rigs when you want OpenRig to stop managing the rig but leave the tmux sessions alive. +This is the safe recovery/reset surface for the "sessions still exist, management is broken or stale" case. +If the rig contains OpenRig-launched nodes, `rig release` refuses loudly instead of pretending the mixed rig is safe to detach. + +### Snapshots and restore + +```bash +rig snapshot +rig snapshot list +rig restore --rig +``` + +`rig restore` requires `--rig `. + +Claude Code autonomy note: +- unattended `rig whoami` on boot may require the local permission allow list to include `Bash(rig:*)` + +### Import/export and bundles + +```bash +rig export -o rig.yaml +rig import [--instantiate] [--materialize-only] [--preflight] [--target-rig ] [--rig-root ] +rig bundle create -o out.rigbundle +rig bundle inspect +rig bundle install [--plan] [--yes] [--target ] [--json] +``` + +### Legacy package surface + +This still ships, but is explicitly marked legacy: + +```bash +rig package validate +rig package plan [--target ] [--runtime ] [--role ] +rig package install [--target ] [--runtime ] [--role ] [--allow-merge] +rig package list +rig package rollback +``` + +## Discovery and Topology Mutation + +### Discover unmanaged tmux sessions + +```bash +rig discover +rig discover --json +rig discover --draft +``` + +### Bind a discovered session + +```bash +rig bind --rig --node +rig bind --rig --pod --member +``` + +There is no shipped top-level `rig claim` command. +The current adoption surface is `discover`, `bind`, `adopt`, and `unclaim`. + +### Self-attach the current shell or agent + +```bash +rig attach --self --rig --node +rig attach --self --rig --node --print-env +rig attach --self --rig --pod --member --runtime +``` + +Use `rig attach --self` when the current agent should attach itself directly instead of going through `discover` + `bind`. + +Current proven behavior: +- inside `tmux`: attaches as a normal tmux-backed node, preserving inbound `rig send` / `rig capture` +- outside `tmux`: attaches as `external_cli` +- `--print-env` prints the `OPENRIG_NODE_ID` and `OPENRIG_SESSION_NAME` exports for the current shell + +Recommended flow: + +```bash +rig attach --self --rig --node --print-env > /tmp/openrig-self-attach.env +. /tmp/openrig-self-attach.env +rig whoami --json +``` + +Notes: +- for tmux-backed self-attach, `rig whoami --json` is the right verification +- 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 ` when you want a stable human session label recorded + +### Adopt a topology and bind live sessions + +```bash +rig adopt --bind +rig adopt --bind --bind --json +rig adopt --bindings-file +rig adopt --bind --target-rig --rig-root +``` + +Use `rig adopt` when the sessions already exist and you want OpenRig to start managing them. + +A bindings file is the durable map from authored logical IDs to live sessions. Shape: + +```yaml +bindings: + dev1.impl2: dev1.impl2@rigged-buildout + dev1.qa: dev1.qa@rigged-buildout +``` + +Spec + bindings is the proven recovery pair for adopted rigs. +Spec gives OpenRig the intended topology. Bindings tells OpenRig which discovered live session belongs in each logical node. + +### Proven adopted-rig recovery workflow + +This workflow is proven for the case where the external tmux sessions are still alive: + +```bash +rig release --delete +rig discover --json +rig adopt --bindings-file +``` + +What this does: +- removes OpenRig management without killing the sessions +- re-discovers those same sessions as unmanaged +- re-attaches them to the topology defined by the spec + bindings + +Important limits: +- this is for `sessions still alive` +- spec alone is not enough for adopted rigs; you also need bindings +- this does not yet mean OpenRig can recreate dead external sessions from nothing + +### Add unmanaged pods into an existing rig + +This is the proven workflow when a rig is already managed, but a new pod was created outside OpenRig and you want to add it later: + +```bash +rig adopt --bindings-file --target-rig +``` + +Use this when: +- the target rig already exists +- the new sessions are live and visible in `rig discover --json` +- you want additive topology growth, not a full rebuild + +What to prepare: +- a pod fragment spec with only the new pod +- a bindings file mapping the new logical IDs to the live session names + +Verification loop: + +```bash +rig discover --json +rig adopt --bindings-file --target-rig +rig ps --nodes --json +rig export -o rig.yaml +``` + +Success looks like: +- the new sessions stop appearing in `rig discover` +- the new logical IDs appear in `rig ps --nodes --json` +- `rig export` includes the new pod + +### Mixed-origin rigs are allowed + +One rig can contain both: +- adopted nodes bound from already-running sessions +- OpenRig-launched nodes created later with `rig expand` / `rig launch` + +Current safety rule: +- `rig release` is for claimed/adopted-only rigs +- if a rig contains launched nodes, `rig release` fails with `contains_launched_nodes` + +### Manager-assisted recovery + +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 --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. + +### Add/remove running topology parts + +```bash +rig expand [--rig-root ] [--json] +rig launch [--json] +rig remove [--json] +rig shrink [--json] +rig unclaim [--json] +``` + +## Specs and Validation + +### Validate specs + +```bash +rig spec validate [--json] +rig spec preflight [--rig-root ] [--json] +rig agent validate [--json] +``` + +### Spec library + +```bash +rig specs ls [--kind ] [--json] +rig specs show [--json] +rig specs preview [--json] +rig specs add [--json] +rig specs sync [--json] +rig specs remove [--json] +rig specs rename [--json] +``` + +## MCP + +```bash +rig mcp serve [--port ] +``` + +Current shipped MCP tools: +- `rig_up` +- `rig_down` +- `rig_ps` +- `rig_status` +- `rig_snapshot_create` +- `rig_snapshot_list` +- `rig_restore` +- `rig_discover` +- `rig_bind` +- `rig_bundle_inspect` +- `rig_agent_validate` +- `rig_rig_validate` +- `rig_rig_nodes` +- `rig_send` +- `rig_capture` +- `rig_chatroom_send` +- `rig_chatroom_watch` + +## Troubleshooting and Weird States + +When the CLI behaves strangely, use the smallest truthful check first: + +```bash +rig whoami --json +rig daemon status +rig ps --nodes --json +``` + +Specific operator rules: +- `Sent to ...` + `Verified: no` is ambiguous delivery, not automatic failure. Check reply, `rig capture`, transcript evidence, or queue/outbox state before retrying. +- partial `rig whoami --json` can happen when identity is still inferable but the daemon-backed path is degraded. +- the unified-exec-process warning is a host/tooling-layer signal, not automatic proof that the OpenRig topology is unhealthy. + +If you hit the unified-exec warning, inspect for stale one-shot helpers before touching live seats: + +```bash +ps -axo pid,ppid,command | rg 'tmux send-keys|rig queue create|tmux attach|codex|claude' +``` + +Safe cleanup target: +- orphaned one-shot wrappers like `tmux send-keys ...` + +Do not mass-kill: +- `tmux attach ...` +- `codex ...` +- `claude ...` + +For deeper host/runtime triage, use the companion `openrig-operator` skill if it is available in your seat. + +## JSON and Error Posture + +Design assumptions that hold in the shipped CLI: +- many operator commands support `--json` +- error messages are intended to say what happened, why it matters, and what to do next +- daemon-backed commands fail loudly when the daemon is stopped or unhealthy +- restore failure is not something you should silently reinterpret as success + +## After-Compaction Recovery Checklist + +1. `rig whoami --json` +2. `rig transcript --tail 100` +3. `rig ps --nodes --json` +4. `rig chatroom history --limit 50` + +## Commands That Do Not Exist + +Do not assume these exist unless the shipped help starts listing them: +- `rig claim` +- `rig blame` +- `rig replay` diff --git a/skills/_canonical/mental-model-ha/SKILL.md b/skills/_canonical/mental-model-ha/SKILL.md new file mode 100644 index 000000000..ff99cdc27 --- /dev/null +++ b/skills/_canonical/mental-model-ha/SKILL.md @@ -0,0 +1,956 @@ +--- +name: mental-model-ha +description: High-availability mental model preservation across compaction events and session restarts. Covers externalized state on the filesystem, scope folder conventions, agent naming, pod/role taxonomy, continuous state maintenance, pre-compaction save, peer restore with phased protocol, session logs as shared mental models, tribal wisdom, and multi-agent shared state. Works for single agents, pairs, and full team topologies. +--- + +# Mental Model HA + +Preserve and restore an agent's working mental model across compaction events and session restarts. Works for single agents, HA pairs, and multi-agent team topologies. + +## Core Principles + +1. **The filesystem is your durable memory.** Your mental model lives in files — restore files, README, session logs, scope knowledge. Keep them current throughout the session, not just at compaction time. + +2. **The filesystem is multiplayer.** Scope folders are readable and writable by every agent in the project. Any agent can restore any other agent. + +3. **One place for everything.** Every artifact type has exactly one location. No decisions about where to put things. + +4. **Human decides when to compact.** Agents prepare and recommend. The human pulls the trigger. + +5. **Never create scope structure without human confirmation.** Discovery yes, creation only with explicit approval. + +6. **Restore artifacts must preserve not just facts, but pattern-forming context.** Facts can be re-derived from code and git history. Judgment, instincts, and the reasons behind decisions cannot. Session logs and restore files exist to rebuild the mental model that makes an agent effective, not just informed. + +--- + +## Agent Naming Convention + +Every agent in a rig gets a label that identifies its topology position and context boundary: + +``` +{pod}{N}-{role}@{scope} +``` + +| Segment | What it is | Examples | +|---|---|---| +| `{pod}` | Functional unit — what kind of work | dev, orch, review, design, research, ops, test | +| `{N}` | Instance number (if multiple pods of same type) | 1, 2, 3 | +| `{role}` | Job function within the pod | coder, qa, lead, peer, r1, r2 | +| `@` | Separator between topology and context | literal `@` | +| `{scope}` | Work context (project/effort) | rigged-dev, specgraph, agilitas-review | + +Examples: +``` +dev1-coder@rigged-dev # dev pod, coder role, rigged dev scope +dev1-qa@rigged-dev # dev pod, qa role +orch1-lead@rigged-dev # orchestrator pod, lead role +orch1-peer@rigged-dev # orchestrator pod, peer role +rev1-r1@rigged-dev # review pod, reviewer 1 +dev1-coder@specgraph # same structure, different scope +``` + +This label is used for: tmux session names, agent-to-agent messaging, knowledge management, compaction/restore targeting, and lifecycle management. + +### Hierarchy + +| Level | Term | What it is | +|---|---|---| +| Work context | **scope** | The project/effort boundary. Maps to a scope folder. | +| Full topology | **rig** | All agents working on a scope. | +| Functional unit | **pod** | A small cross-functional group within a rig. | +| Job function | **role** | One agent's specific job within a pod. | + +### Canonical Pod Names + +Pods are named after the **function** they perform, not the technology or model. + +| Pod | Purpose | Typical Roles | +|---|---|---| +| **dev** | Write and gate code | coder, qa | +| **orch** | Architecture, monitoring, coordination | lead, peer | +| **review** | Independent code review | r1, r2 | +| **design** | UI/UX design | lead, peer | +| **research** | Deep research | lead, peer | +| **ops** | Infrastructure/deployment | lead, peer | +| **test** | Dedicated integration/e2e testing | lead, runner | + +### Canonical Role Names + +Roles are named after the **job**, not the person, hierarchy, or model. + +| Role | What they do | Used in | +|---|---|---| +| **coder** | Writes code, follows TDD, proposes approaches | dev pod | +| **qa** | Gates every edit, runs tests, reviews diffs | dev pod | +| **lead** | Primary decision-maker, first-among-equals | orch, design, research, ops, test pods | +| **peer** | Convergence partner, rubber duck, different perspective | orch, design, research, ops pods | +| **r1, r2** | Independent reviewers (symmetric) | review pod | +| **runner** | Executes test suites, manages test infrastructure | test pod | + +### Naming Guidance for New Pods/Roles + +- **Pods:** Name after function, not technology. Good: `dev`, `orch`. Bad: `claude`, `codex`. +- **Roles:** Name after job, not hierarchy. Good: `coder`, `qa`, `lead`, `peer`. Bad: `manager`, `boss`, `worker`. +- **Avoid hierarchy** in role names — agents interpret hierarchy terms literally and it distorts behavior. +- **Scope names:** Short, descriptive, kebab-case. Usually project name + qualifier. + +--- + +## Bootstrapping: Finding or Creating Your Scope + +When you load this skill, figure out where you are. + +**CRITICAL: Check ALL locations before concluding nothing exists.** Another agent (Claude or Codex) may have created the scope in a different location than you'd default to. If you only check one location and miss an existing scope, you'll create a parallel one and cause split brain — the worst failure mode. + +**Step 1: Search everywhere** + +Check ALL of these. Not "in order until you find one" — check every single one: +- `MEMORY.md` — does it list scopes? (auto-loaded for Claude Code; Codex: read the file manually) +- `~/.claude/projects//memory/scopes/` — any folders here? +- `/docs/scopes/` — any folders here? +- `/.scopes/` — any folders here? (some projects use this) + +**Step 2: If you found scope(s)** + +Match one to your context. Usually obvious from: what the human told you, the branch name, or there's only one. If ambiguous, ask: "I see scopes X and Y. Which one am I working in?" + +If you find a scope that looks like it MIGHT be yours but you're not sure — it probably is. ASK before creating anything new. + +**Step 3: Report what you found** + +Always show the human your results before taking action: + +``` +"Scope discovery: + ~/.claude/projects/.../memory/scopes/ — [found: specgraph-studio, idp-pipeline | empty | does not exist] + /docs/scopes/ — [found: ... | empty | does not exist] + /.scopes/ — [found: ... | empty | does not exist] + MEMORY.md — [lists scopes: ... | no scopes listed | does not exist] + +[If found]: Joining scope at . Correct? +[If nothing]: No scope structure found. Want me to create one? What should it be called?" +``` + +The human sees exactly what was checked and can catch if a scope was missed. Only create after explicit confirmation. Register new scopes in MEMORY.md (if it exists). + +**Step 4: If you're Codex or another non-Claude agent** + +You can read and write to `~/.claude/projects//memory/` — it's just a filesystem path, not magic. Check it the same way Claude does. If the scope was created there by a Claude agent, use it. Don't create a duplicate in the repo just because you're not Claude. + +--- + +## Scope Folder Structure + +``` +// +├── README.md # Map of the territory (orchestrator-managed) +├── scope-progress.md # Task tracker (orchestrator-managed) +├── scope-decisions.md # Decision log, append-only (orchestrator-managed) +├── scope-knowledge.md # Living tribal wisdom (everyone contributes) +├── -session-log.md # Per-pod shared mental model (e.g., dev1-session-log.md) +├── plans/ # All plans (preserved, named) +├── restore/ # Per-role restore instructions + peer-held quizzes +├── reviews/ # All review artifacts +└── working/ # Everything else — drafts, research, insights not yet canon +``` + +Ephemeral output (does NOT live in the scope folder): +``` +/tmp// +└── output/ # Screenshots, videos, heavy media +``` + +The scope root is wherever the scope was created: +- Default: `~/.claude/projects//memory/scopes/` +- Alternative: `/docs/scopes/` (gitignored) + +MEMORY.md should list each scope with its full path so agents don't have to search. + +--- + +## What Each File Does + +### Scope-Level Files (shared by all pods) + +| File | Owner | Purpose | When to update | +|------|-------|---------|----------------| +| `README.md` | Orchestrator | Map — what is this scope, who's involved, key file paths, infrastructure | When landscape changes (new phase, new agent, scope shift) | +| `scope-progress.md` | Orchestrator | Task tracker — done, in progress, next, blocked | After every task completion | +| `scope-decisions.md` | Orchestrator | Decision log — what, alternatives, rationale. Append-only. | After every decision | +| `scope-knowledge.md` | Everyone | Living tribal wisdom — observations get promoted to insights, stale knowledge gets revised. Updated, not just appended. | When knowledge matures | + +### Restore Document Boundary Model + +Restore-relevant documents form three layers. An agent recovering from compaction should rebuild context from the outermost layer inward: + +| Layer | File | Scope | What it provides | +|-------|------|-------|------------------| +| **Scope-wide** | `README.md`, `scope-progress.md`, `scope-decisions.md` | Shared by all pods | Project map, current state, locked decisions | +| **Pod-local** | `-session-log.md` | Shared by one pod | Shared working memory — facts, history, judgment, instincts | +| **Role-specific** | `restore/.md` | One agent | Fast-start orientation, immediate context, resume instructions | + +**Why layered:** Without this model, an agent can either read only its restore file (missing shared project context) or only the README (missing role-specific recovery). The correct restore path is: scope-wide shared context first, then pod-level shared memory, then role-specific fast start. + +### Folders + +| Folder | What goes here | Convention | +|--------|---------------|------------| +| `plans/` | All plans. Named descriptively, never overwritten. | `plans/m1-platform-backend.md` | +| `restore/` | Per-role restore instructions AND peer-held quiz files. | `restore/coder.md`, `restore/coder-quiz.md` | +| `reviews/` | All review artifacts — reviews, cross-exams, convergence. | `reviews/m1-review-a.md` | +| `working/` | Everything else. Drafts, research, insights-not-yet-canon, ad-hoc notes. The general-purpose folder for anything that doesn't have a specific home yet. | Name descriptively, use grep to find. | + +### Knowledge Maturity Model + +Files often progress through maturity levels: +1. **Observation** → `working/` (just noticed something) +2. **Insight** → `working/` (confirmed pattern, not yet formalized) +3. **Canon** → `scope-knowledge.md`, as-built docs, or skill files (formalized and governing) + +`working/` holds both throwaway notes and important-but-not-yet-canon insights. The folder name signals "put stuff here without overthinking it" across the full spectrum. + +--- + +## Where Things Go (No Decisions) + +| Trigger | File | +|---------|------| +| Finished a task | `scope-progress.md` | +| Made a decision | `scope-decisions.md` | +| Learned something durable | `scope-knowledge.md` | +| Scope changed shape | `README.md` | +| Writing a plan | `plans/` | +| Preparing for compaction | `restore/.md` | +| Doing a review | `reviews/` | +| Anything else | `working/` | +| Screenshots, videos, heavy output | `/tmp//output/` | + +Every trigger maps to exactly one location. + +--- + +## Session Logs — The Pod's Shared Mental Model + +Session logs are the most important restore artifact. They are NOT status notes, QA reports, or operational handoffs. They are the pod's externalized shared mental model — written so that either peer can recover the workstream after major memory loss. + +### What a Session Log Is + +A session log is a **durable reconstruction of the pod's shared mental model**. It preserves what happened, why it mattered, what patterns emerged, what mistakes were made, what kept breaking, and what instincts the pod developed over time. + +It is written for a future reader whose memory may be partially or heavily damaged by compaction. It should help restore not only facts, but judgment. + +### What a Session Log Is NOT + +- A QA narrative or one agent's perspective +- A minimal handoff or operational resume +- A one-time emergency memo +- A compaction summary +- An architect-facing status report + +### The Five-Layer Content Standard + +A good session log addresses all five layers: + +**1. Operational State** — the current working edge: +- Current phase/sprint and active task +- Latest committed work (commit hash) +- Current gate state (pre-edit approved, post-edit pending, etc.) +- Next expected artifact +- Active branch, working tree state +- Current blockers or risks + +**2. Architectural State** — the shape of the system: +- Major layers and boundaries +- Key invariants and locked contracts +- Important route/DB/event semantics +- Constraints that future work must preserve + +**3. Historical State** — what happened across the full workstream: +- Major phases and what they built +- Major review cycles and what they found +- Major fixes and why they were needed +- Points where the team changed direction +- Recurring failure patterns + +**4. Epistemic State** — how we came to know what we know: +- Debates that shaped current design +- Ambiguities that caused repeated rejections +- Decisions that seemed small but changed future behavior +- Why alternatives were rejected, not just what was chosen +- What assumptions kept failing +- What QA kept catching that the implementer missed +- What the implementer repeatedly got right + +**5. Soft Context / Intuition** — the feel of the work: +- What kinds of mistakes are common +- Which areas are deceptively risky +- Where tests tend to be too weak +- Which conventions matter more than they first appear +- What classes of reasoning lead to correct outcomes +- What patterns should survive compaction even if details are forgotten + +### Audience + +The session log is for **both peers in the pod, across time, after partial or major memory loss**. Write it for the worst case — a fully compacted agent that remembers nothing about the project. + +### When to Write + +The session log is a **living document**, not an emergency-only artifact: +- Append after meaningful events: major approvals/rejections, design pivots, new bug patterns, review findings, moments of confusion resolved +- Update the "Current Live Edge" section after every commit or task completion +- Review and revise at phase boundaries +- Write a major update before any anticipated compaction + +Do not wait for disasters to externalize state. Over-capturing meaningful context is better than under-capturing. + +### Practical Quality Test + +A good session log answers all of these: +- What are we building? +- What has been built already? +- What did we learn while building it? +- What did we get wrong and later fix? +- What arguments or ambiguities shaped the current design? +- What instincts should the restored agent carry forward? +- What exactly should happen next? + +If the document cannot restore those, it is too thin. + +--- + +## Scope Knowledge — The Tribal Wisdom Document + +The most important file for long-running scopes. Accumulated wisdom of every agent that has worked here. + +- Any agent can write to it +- Observations start as notes → get promoted to insights when confirmed +- Stale knowledge gets revised or removed (this is UPDATE, not append-only) +- Date and brief attribution on each entry so readers know freshness + +**Belongs here:** Patterns, gotchas, process improvements, failed approaches and why, architectural insights, tool/library behavioral patterns. + +**Doesn't belong here:** Task status (progress), formal decisions (decisions), session narratives (session logs), raw research (working). + +--- + +## Continuous State Maintenance + +Don't wait for compaction. The librarian keeps state current throughout the session: + +- Update `scope-progress.md` after tasks complete +- Update session log at natural boundaries (see "When to Write" above) +- Contribute to `scope-knowledge.md` when patterns emerge +- Keep restore files fresh + +**Peer sync:** Tell your peer after major decisions, task completions, unexpected discoveries, plan changes. The peer should always have enough context to restore you without a restore file. + +--- + +## The Librarian Role + +In each pod, one agent keeps externalized state current. This is typically the non-coder — the agent with bandwidth and a broader view. In some topologies, the orchestrator serves as scope-level librarian across all pods. + +| Pod | Default Librarian | Why | +|-----|-------------------|-----| +| Dev pair | QA, or orchestrator if designated | Coder is busy coding | +| Dev solo | The only agent | No choice | +| Orch pair | The peer, or the lead | Depends on workload | +| Orch solo | The lead | No choice | +| Review pair | Either | Reviews are inherently documented | + +The human may designate any agent as librarian. The default is guidance, not a rule. + +**Scope-level librarian:** In a full rig with multiple pods, the orchestrator (or their designated agent) serves as librarian for the scope-level files (README, progress, decisions). Pod-level librarians handle their own session logs and restore files. + +Librarian responsibilities: session log, restore files, scope-knowledge contributions, ready to restore pod-mate on compaction. + +--- + +## Operating Modes + +When you load this skill, determine which mode you're in. The correct behavior depends on the situation. + +### Mode 1: Continuous Maintenance (default) + +You are working normally. Compaction is not imminent. Keep state current incrementally. + +**Behavior:** Update session log at natural boundaries. Keep restore file reasonably fresh. Sync with peer on major events. + +### Mode 2: Durable Artifact Creation (pre-compaction) + +A peer is about to compact, or is too context-depleted to safely preserve its own state. The priority is to externalize the pod's shared mental model BEFORE memory loss occurs. + +**Trigger heuristic — if all three are true:** +1. A peer is low-context or about to compact +2. The peer cannot safely write its own state +3. A scope memory path exists + +Then default to: update the pod session log in shared memory. Write for both peers' future recovery. Do NOT default to sending a tmux restore message — the durable artifact must exist before any restore workflow is possible. + +**Behavior:** Write or significantly update the session log using the five-layer content standard. Update the restore file. Write quiz questions to a separate file (`restore/-quiz.md`). Do NOT notify the compacting peer via tmux unless explicitly instructed — they may compact before reading it, wasting their remaining context. + +**Common mistake:** Mixing durable artifact mode with live restore mode. If the peer hasn't compacted yet, your job is to WRITE artifacts, not to RESTORE the peer. The causal order matters: artifact creation → compaction → restore. + +### Mode 3: Live Restore (post-compaction) + +A peer has already compacted and is active but confused. The durable artifacts should already exist. + +**Behavior:** Follow the Phased Restore Protocol below. Point to files, don't send contents via tmux. Run the quiz. Verify the restore. + +**Claude compact-in-place:** For an OpenRig Claude Code seat that keeps the same session after `/compact`, use `claude-compact-in-place` for the seat-specific read-depth audit and marshal acceptance rule. This skill remains the general durable-memory, session-log, and HA restore framework. + +### Mode 4: Quick Restore (unexpected compaction, no pre-save) + +Compaction happened without preparation. No restore file exists or it's stale. + +**Behavior:** Check git state first. Send a short orientation via tmux or filesystem. Build restore artifacts on the fly if needed. Follow as much of the phased protocol as possible. + +### Mode 5: Dialogue-Based Sync (peer drift recovery) + +A peer is alive and functional but has gradually fallen behind — it wasn't involved in decisions, didn't witness mistakes, and doesn't have the instincts that developed over time. This is different from post-compaction restore: the peer has context, it's just stale or incomplete. + +**Trigger:** The peer has been idle or uninvolved for an extended period while the lead accumulated significant new context. The gap is in judgment and instincts, not just facts. + +**Why this is different from artifact-based restore:** Written artifacts capture what you decide to write down. Dialogue surfaces what the peer knows it's missing — the peer asks questions it couldn't derive from docs, and the lead's answers trigger deeper follow-ups that neither would have thought of alone. + +**Protocol:** + +**Phase 1: Lead writes down everything first (ontology + epistemology)** + +Before the dialogue begins, the lead does a thorough externalization pass: + +1. Write down all ontological state — facts, decisions, current status, what's built, what's next. This is the "what" layer. +2. Write down all epistemological state — how you came to know things, why decisions were made, what mistakes informed current instincts, what failed approaches were tried, what patterns emerged through experience. This is the "why and how we learned" layer. These nuggets of context exist only in chat history and would be lost without deliberate capture. +3. Update the pod session log with both layers. Don't just append facts — add the reasoning, the judgment calls, the instincts that developed, and the failure modes that shaped current behavior. +4. The epistemology is the hard part. Facts can be re-derived from code and git. But "we tried X and it failed because of Y, which is why we now always do Z" — that only lives in the context window until you write it down. + +**Phase 2: Peer reads the updated artifacts** + +5. The peer reads the updated session log, restore file, and any other relevant artifacts. +6. The peer forms its own understanding and identifies what feels incomplete or unclear. + +**Phase 3: Dialogue — peer drives, lead answers from memory** + +7. The peer initiates questions — the peer drives the conversation, not the lead. +8. The peer asks targeted questions based on what it already knows is missing (not generic "tell me everything"). +9. The lead answers from memory only — no tool use, no looking things up. Only transfer what's actually in the context window. Don't make anything up or infer things that aren't there. +10. The peer follows up — the lead's answers reveal deeper gaps the peer didn't initially know about. This is the key mechanism: the Q&A format jogs the lead's memory and surfaces things that the writing pass missed. +11. Repeat until the peer declares itself synced. + +**Phase 4: Capture what the dialogue surfaced** + +12. After the dialogue, update the session log and restore file with any new insights that came out of the Q&A. The dialogue almost always surfaces things the lead didn't write down in Phase 1 — instincts, edge cases, failure modes, contextual details that only emerged when the peer asked the right question. +13. End with a concrete handoff test: "if you had to take over for one hour, what are the top 3 actions?" + +**What makes this work:** +- Writing first forces the lead to externalize before the dialogue begins — the peer isn't starting from zero +- The peer drives the questions (more efficient than the lead guessing what to dump) +- Q&A format forces concrete specific answers, not generic summaries +- Follow-up questions go deeper because the first round reveals real gaps +- The dialogue jogs memory — the lead surfaces things they didn't think to write down +- Phase 4 captures what the dialogue added, so the artifacts improve from the process +- It ends with a practical test, not just "do you feel caught up?" + +**Why the epistemology layer matters:** +Without it, a restored agent knows WHAT to do but not WHY certain approaches are wrong, WHICH areas are deceptively risky, or WHAT instincts to carry forward. It will repeat mistakes that were already learned from. The epistemology layer is what separates a session log from a status note. + +**When to use:** Before compaction when the peer needs to be ready to take over. When a peer rejoins after being idle for a long stretch. When the lead has accumulated instincts from extended human interaction that aren't captured in any doc. + +**When NOT to use:** For post-compaction restore (use Mode 3 instead — the compacted agent needs files, not dialogue). For routine sync (use Mode 1 continuous maintenance). + +--- + +## Compaction Timing + +**The human decides when to compact.** Agents can: +- Recommend: "I'm at 15%, good stopping point after this commit" +- Prepare: write restore file, sync with peer, update session log +- Flag: "Context getting low, should plan for compaction soon" + +**Good moments:** After a commit. After a task boundary. After writing a session log. NOT mid-edit, mid-test, or mid-conversation. + +--- + +## Pre-Compaction: Writing the Restore File + +Write to `restore/.md`. This is the role-specific fast-start instruction file. + +```markdown +# Restore — () + +Read this first. Then have your peer quiz you. + +## Who You Are +- Role, session/tmux name (e.g., dev1-coder@rigged-dev), peer and how to reach them + +## Skills To Load +- List baseline skills for this role +- Include why each is needed (one line per skill) + +## Essential Reading List (full file paths — read in this order) + +### Tier 1 — Shared scope reading +1. /README.md — the map +2. /scope-progress.md — where things stand +3. /-session-log.md — shared pod memory +4. docs/as-built.md (or equivalent) — verified architecture +5. docs/taxonomy.md (if applicable) — terminology authority +6. + +### Tier 2 — Role-specific reading +7. This file (restore/.md) — immediate context +8. Historical plan docs relevant to current work +9. Any other role-specific references + +## Immediate Context +- What you were working on when compacted +- Current branch, uncommitted changes (check git status) +- Open questions or escalations +- Anything time-sensitive + +## Key Decisions (must know cold) +- Architectural decisions with rationale +- Naming conventions +- Technical choices and why + +## Resume Instructions +- What exact task to resume +- What exact first actions to take +- What constraints to keep in mind +- What artifact to send next +``` + +**IMPORTANT: Quiz questions go in a SEPARATE file** — `restore/-quiz.md`. The peer writes and holds the quiz. Putting questions in the agent's own restore file gives them the answers to the test, defeating the purpose. + +### Quiz File Template + +The peer writes `restore/-quiz.md`: + +```markdown +# Quiz — + +Held by peer. Do NOT show to the agent being quizzed. + +## Questions (8-12) +- Mix of factual (what?) and reasoning (why?) +- At least 2 about recent decisions +- At least 2 about process/workflow (not just facts) +- At least 1 about what went wrong and what was learned +- Agent answers from memory only — no tools +``` + +### Save Protocol + +1. Write/update `restore/.md` +2. Peer writes/updates `restore/-quiz.md` (separately held) +3. Update MEMORY.md to point to restore file (if not already listed) +4. Tell peer: "Ready for compaction. Restore file at ``." +5. Verify peer acknowledges +6. Tell human: "Ready when you are." +7. **Wait for human** + +If the agent is too depleted, the **librarian or peer writes the restore file**. + +--- + +## Phased Restore Protocol (Post-Compaction) + +This is the full protocol. Each step exists because skipping it caused a real failure in practice. + +### Phase 0: Notify +Tell the agent AND human: `" compacted. Starting restore."` + +Do NOT silently restore. Do NOT let the agent work before restoration. + +### Phase 1: Assess What the Agent Already Has + +After compaction, the agent may have partial context from: +- **Conversation summary** — Claude generates a detailed summary during compaction. This often carries 50-70% of factual recovery. It is the single most powerful restore artifact but is unpredictable in what it covers. +- **Auto-read files** — Claude may auto-read recent files during compaction, but targets are opportunistic and unreliable. +- **MEMORY.md** — auto-loaded for Claude Code, but agents sometimes skip reading it if they feel their compaction summary was sufficient. + +**Do not assume any of these happened.** Ask the agent: "What do you already have in context? What files did you read?" + +### Phase 2: Assign Restore Reading + +Point the agent to the restore file: `"Read restore/.md — it has your reading list."` + +The agent reads files from the Essential Reading List in order. Peer can prioritize: "Start with the restore file for orientation, then the session log for depth — that's where the judgment lives." + +### Phase 3: Require Read Inventory + +After the agent says it has finished reading, require an explicit inventory: + +``` +"List every file you read, in order. Include files auto-read during compaction." +``` + +This matters because an agent can give a strong summary and still have skipped important reading. + +### Phase 4: Compare Intended vs Actual Reading + +The peer compares the agent's read inventory against the restore file's Essential Reading List. Mark any gaps: +- **Task-blocking gaps** — missing context that would cause the agent to make wrong decisions on the current task +- **Contextual gaps** — missing broader context that doesn't block immediate work but weakens the mental model + +For task-blocking gaps: the agent must read those files before resuming. +For contextual gaps: note them, let the agent resume, patch later. + +### Phase 5: Memory Summary + +Ask the agent to summarize what it knows from memory. No tools. This tests whether the reading actually landed, not just that files were opened. + +### Phase 6: Memory-Only Quiz + +Peer asks questions from `restore/-quiz.md`. Agent answers from memory — no tools allowed. + +**Grading:** +- **All correct:** "Pass." +- **1-2 misses:** Correct the wrong answers, explain why they matter, continue. +- **3+ wrong:** Re-read the session log and restore file, re-quiz. If still failing, peer provides a focused context dump of the most critical items. + +### Phase 7: Classify Restore Completeness + +The peer explicitly classifies the agent's state: + +- **Restored enough to act** — agent has enough context to resume the immediate task safely. May still have contextual gaps. +- **Fully restored** — agent has completed the intended restore path and rebuilt broader context and shared understanding. + +These are NOT the same. An agent can be "restored enough to act" before it is "fully restored." The peer should communicate which state the agent is in. + +### Phase 8: Resume Instructions + +Don't just say "you're restored." Give explicit resume instructions: +- What exact task to resume +- What exact first actions to take +- What constraints to keep in mind +- What artifact to produce next +- Re-anchor on git state: `git log --oneline | head -10` and `git status` + +### Phase 9: Monitor Resumed Behavior + +The peer watches the first stretch of resumed work for quality signals: +- Does the agent preserve the approved task contract? +- Does the agent take the correct first action? +- Does the agent maintain gate discipline? +- Does the agent re-open closed debates? +- Does the agent maintain code/review quality? + +If any of these fail, intervene early — it indicates the restore missed something important. + +Until confidence is re-established, monitor more aggressively than normal. Short-interval checks. Quick nudges if the agent drifts. Once the agent demonstrates normal quality, back off. + +--- + +## Quick Restore (No Pre-Save) + +If compaction happened unexpectedly: + +1. Peer checks `git status` and `git diff` to understand uncommitted state +2. Peer sends orientation: +``` +"Quick restore: Scope at . +Read: README.md, scope-progress.md, -session-log.md. +You're — working on . +Peer is me at ." +``` +3. Follow Phases 3-9 of the full protocol (read inventory, compare, summary, quiz, classify, resume, monitor) +4. If no session log exists, the peer writes one now (Mode 2: Durable Artifact Creation) before proceeding + +--- + +## Orchestrator Self-Restore Protocol + +The orchestrator's restore is materially different from other roles. A coder restores depth on one task. An orchestrator restores **breadth across the entire project** — it needs to be the wisest agent in the rig, with the broadest understanding of where the project has been, where it is, and where it's headed. + +### Why This Is Different + +The standard Phased Restore Protocol assumes a peer drives the restore. But the orchestrator often IS the peer that restores others. When the orchestrator compacts, it must self-restore using its own pre-written artifacts, then verify against its peer. The protocol is self-directed, not peer-driven. + +### The Orchestrator Restore Sequence + +**Step 1: Follow your own instructions.** + +Read the restore file you wrote for yourself (e.g., `restore/lead.md`). This file should contain a curated, prioritized reading list covering the entire project landscape — not just your current task. + +**Step 2: Take a reading inventory.** + +Before reading anything, inventory what you already have from compaction (conversation summary, auto-read files, MEMORY.md in system context). Build a matrix: + +``` +| # | File | Status | +|---|------|--------| +| 1 | restore file | ✅ Read (system reminder) | +| 2 | session log | ❌ NOT read | +| 3 | as-built doc | ❌ NOT read | +| ... | ... | ... | +``` + +Show this to the human. It makes the restore process transparent and ensures nothing falls through the cracks. The orchestrator's reading list is typically 20-30+ files across: memory system, project conventions, architecture docs, current active work, the plan, customer materials, dogfood outputs, deferred work plans, tribal wisdom memories, and skills. + +**Step 3: Read in priority order, parallelizing where possible.** + +The reading list should be tiered: +- **Tier 1 (critical):** Restore files, memory system, project conventions, current active work. Read these first — they're needed for decision-making. +- **Tier 2 (important):** Architecture docs, the plan, customer materials, key memories. Read in parallel where independent. +- **Tier 3 (context):** Dogfood outputs, deferred work plans, skills. Skim for context — full reads only if something is actively relevant. + +Skip files where the compaction summary already gave you the gist AND the file isn't needed for immediate decisions. Note skips in the inventory with rationale. + +**Step 4: Initiate peer sync.** + +The orchestrator's peer typically cannot message back via tmux unprompted — you must initiate. Send a message requesting a file-based status dump: + +``` +"I've restored from compaction. Write a status update to covering: +(1) What you've been working on since I compacted +(2) Status of any analyses or questions you were handling +(3) Decisions or recommendations you've made +(4) What you need from me" +``` + +Read the file once written. This closes the gap between your pre-compaction snapshot and the current state. + +**Step 5: Check all agent states.** + +The orchestrator monitors the full rig. After compaction, check every agent's tmux session: + +```bash +for s in ; do + echo "=== $s ===" + tmux capture-pane -t $s -p -S -30 | tail -10 +done +``` + +Also check git state in the worktree — commits may have landed while you were compacting: + +```bash +git log --oneline -5 +``` + +Compare against the last commit hash in your restore file to see what's new. + +**Step 6: Update the inventory and report.** + +After all reading and syncing, update the matrix with final status. Report to the human: +- How many files read vs skipped (with rationale for skips) +- What the peer reported +- What agents accomplished during compaction +- Current state of the project +- What you're ready to do next + +### What Makes Orchestrator Restore Different (Summary) + +| Aspect | Standard Restore | Orchestrator Restore | +|--------|-----------------|---------------------| +| **Goal** | Resume one task | Rebuild full project mental model | +| **Driven by** | Peer | Self (using own restore file) | +| **Reading scope** | 5-10 files (task-focused) | 20-30+ files (project-wide) | +| **Peer role** | Drives the restore | Provides status dump on request | +| **Agent check** | Not applicable | Check ALL tmux sessions | +| **Git check** | Own branch | All worktrees and branches | +| **Success metric** | Can resume task | Wisest agent in the rig — broadest and deepest understanding | +| **Inventory** | Peer compares intended vs actual | Self-tracks with visible matrix | + +### Pre-Compaction: What the Orchestrator Should Write + +The orchestrator's restore file should be a **curated reading list**, not a brain dump. Organize by section with full file paths. Include: + +1. **Memory system** — MEMORY.md, restore files (self + peers) +2. **Project conventions** — CLAUDE.md, code-map, naming bible +3. **Architecture** — as-built docs, implementation specs +4. **Current state** — active implementation tasks, open questions, peer analyses +5. **The plan** — roadmap, workflow sequence, phase definitions +6. **Customer materials** — briefings, success criteria, instruction guides +7. **Historical outputs** — dogfood reports, assessment results (mark as "skim") +8. **Deferred work** — plans preserved for future phases (lowest priority) +9. **Tribal wisdom** — key feedback and project memories +10. **Skills and tools** — skills created during the project + +Also include post-restore action items: +- How to check agent states +- How to check git state +- How to reach the peer +- What to ask the human + +--- + +## Model-Specific Context Management + +Claude and Codex handle compaction completely differently. The orchestrator MUST treat them differently. + +### Claude: Catastrophic All-or-Nothing Compaction + +- Auto-compact is typically OFF. The human manages compaction manually. +- When Claude compacts, it's all-or-nothing — the full conversation summary replaces context. +- This is the catastrophe that mental-model-ha exists to manage. +- The full pre-compaction save, peer restore, and quiz protocol applies. +- For compact-in-place in an OpenRig seat, use `claude-compact-in-place` before accepting a `RESTORED` claim. +- The orchestrator actively helps manage Claude's context lifecycle. + +### Codex: Automatic Partial Compaction + +- Codex has built-in automatic context management that works well. +- It performs **partial compactions** — drops from 30% to bounce back to 62%, not a full reset. +- Occasionally it does a major compaction, but even then it usually recovers cleanly. +- **The orchestrator does NOT manage Codex's context lifecycle.** Codex handles itself. +- NEVER tell Codex to "wrap up," "write findings before you compact," or "stop and save state" based on context percentage. +- NEVER redirect Codex's work based on its context percentage. + +### When to Restore Codex + +NOT based on context % — based on **behavioral signals only**: +- Forgetting things that were just discussed +- Making mistakes it shouldn't (re-opening decided questions, wrong file paths) +- Asking about things that were already resolved + +When you detect these signals: +1. Have Codex self-scout: what files are in its context? +2. Identify gaps against what it should know +3. Have it re-read the missing files +4. Quiz it +5. If it passes, put it back in the work stream + +### Intervention Thresholds (HARD RULES) + +| Context % | Claude | Codex | +|-----------|--------|-------| +| **20%** | Monitor. Mention in status. Do NOT intervene. | Ignore. Codex handles itself. | +| **10%** | Actively prepare. Recommend compaction to human. | Monitor. Codex will likely partial-compact. | +| **5%** | Intervene if human approves — real risk of losing state. | Still trust Codex. Only intervene if behavioral signals appear. | + +**HARD ANTI-PATTERN:** Redirecting ANY agent at 20% context. This is not an emergency. Telling an agent to "stop and write findings" makes it abandon in-progress investigation — bugs it was about to find stay unfound, and nobody knows why it stopped short. This is worse than letting it compact on its own. + +--- + +## Compaction Summary as Restore Input + +Claude's system-generated conversation summary is a significant but unpredictable restore artifact. In practice: + +- It often carries 50-70% of factual recovery (names, file paths, decisions, chronology) +- It does NOT carry judgment, instincts, or soft context — those come from session logs +- It may miss recent events if context was very full +- The agent may or may not have read it consciously + +**Implications for the restore protocol:** +- Don't assume the summary covered everything — still require the full reading path +- Don't assume the summary covered nothing — ask what the agent already has before assigning reading +- The summary is a SUPPLEMENT to session logs and restore files, not a replacement + +### CRITICAL: Skill content is truncated by compaction + +Claude's compaction preserves skill **names** and **partial content** in system reminders, but truncates the bodies. The truncation notice reads: `[... skill content truncated for compaction; use Read on the skill path if you need the full text]`. + +**This creates a dangerous illusion.** The agent sees skill names listed in its context and believes the knowledge is loaded. When asked "what skills do you have?", it truthfully lists them — but the critical operational knowledge in the truncated sections is gone. + +**Failure mode observed in production:** An orchestrator reported mental-model-ha as "loaded" after compaction. The skill name and partial content were in system reminders. But the Claude-vs-Codex context management section (line 778+) was in the truncated portion. The orchestrator then made incorrect decisions about Codex agent management for an entire session because it was operating from the skill name, not the skill knowledge. + +**Mandatory restore step:** After ANY compaction, re-read ALL skill SKILL.md files from disk using the Read tool. Do not trust system reminder content as equivalent to loaded skills. The restore protocol and peer quiz must verify skill knowledge, not just skill names. + +--- + +## Agent Topologies + +### Single Agent +One agent, all roles. Externalizes state to the scope folder. HA comes from the filesystem — survives compaction and session restarts by reading its own restore file and scope state. + +### Pair (2 agents) +Coder + QA, or lead + peer. One writes the session log, both contribute to knowledge. Either can restore the other. + +### Pod (2-4 agents, same function) +One is the librarian. HA covers gaps — if librarian compacts, another covers. + +### Full Rig (multiple pods) +Each pod has its own session log. Scope-level files are shared across pods. Orch pod owns README and progress. + +### Ephemeral Agents (simulated roles) +READ shared state, write to `working/` or `/tmp/` output. Don't maintain session logs. Orchestrator promotes valuable observations to scope-knowledge. + +--- + +## Example: Pre-Compaction → Restore Flow + +Concrete example to illustrate the full process. + +**Situation:** Dev pod. Implementer is at 2% context. QA still has full memory. Operator says "load HA skill, we need to prepare for compaction." + +**Step 1 — QA recognizes Mode 2 (Durable Artifact Creation):** +- Implementer can't safely write its own state +- Scope memory path exists +- QA's job is to externalize the pod's shared mental model NOW + +**Step 2 — QA writes/updates the session log:** +- Uses the five-layer content standard +- Writes for both peers' future recovery, not just for the implementer +- Includes operational state, architectural context, historical narrative, epistemic context, and soft intuitions +- Updates the "Current Live Edge" section with exact task state + +**Step 3 — QA writes/updates the restore file:** +- `restore/coder.md` with tiered reading list, skills to load, immediate context, resume instructions +- Does NOT include quiz questions + +**Step 4 — QA writes the quiz file:** +- `restore/coder-quiz.md` — held separately from the restore file +- 8-12 questions mixing factual and reasoning + +**Step 5 — QA tells the human:** "Artifacts ready. Implementer can compact." + +**Step 6 — Human triggers compaction.** + +**Step 7 — QA detects compaction** (context % jumps up, or agent asks about decided things). + +**Step 8 — QA runs the Phased Restore Protocol:** +- Phase 0: Notify human and implementer +- Phase 1: Ask what the implementer already has in context +- Phase 2: Point to restore file reading list +- Phase 3: Require read inventory +- Phase 4: Compare intended vs actual, patch gaps +- Phase 5: Memory summary +- Phase 6: Quiz from `restore/coder-quiz.md` +- Phase 7: Classify as "restored enough to act" or "fully restored" +- Phase 8: Give explicit resume instructions +- Phase 9: Monitor first stretch of resumed work + +--- + +## Anti-Patterns + +**Don't create a scope folder without human confirmation.** Split brain is the worst failure. + +**Don't compact without telling the agent first.** They need time to save state. + +**Don't let agents compact each other unless human says to.** Human decides when. + +**Don't skip the quiz.** Trust but verify. Subtle losses cause wrong judgment calls. + +**Don't put quiz questions in the agent's own restore file.** The peer holds the quiz in a separate file. Giving yourself the answers defeats the purpose. + +**Don't send restore file contents via tmux.** Point to the file path. + +**Don't restore mid-edit.** Check `git status` first. + +**Don't let the scope root get cluttered.** Named files + 4 folders only. Everything else goes in `working/`. + +**Don't treat compaction as routine.** Quality of restore depends on quality of state maintained throughout. + +**Don't create a parallel scope alongside an existing one.** If you see something that looks like your scope, it probably is. Ask before creating. + +**Don't use hierarchy in role names.** "Manager" and "worker" create unwanted power dynamics. Use "lead" and "peer" instead. + +**Don't write a status note when a session log is needed.** If a peer is about to compact, a thin list of "current task, next step, blockers" is insufficient. Write the full shared mental model using the five-layer standard. + +**Don't collapse durable artifact creation into a tmux message.** A tmux message is for live restore of an already-compacted agent. Pre-compaction work is about creating filesystem artifacts, not sending terminal messages. + +**Don't assume sparse is better.** Session logs should be comprehensive. Over-capturing meaningful context is cheaper than under-capturing and losing judgment that took sessions to build. + +**Don't assume MEMORY.md is a reliable auto-restore trigger.** Agents sometimes skip it after compaction, believing their summary is sufficient. The restore protocol must not depend on MEMORY.md being read automatically. + +**Don't confuse "restored enough to act" with "fully restored."** An agent can pass a task-focused quiz while still missing important shared context. The peer must explicitly classify which state the agent is in. + +**Don't skip behavior monitoring after restore.** The real test of restore quality is not the quiz — it's whether the agent can pick up interrupted work at normal quality without regressing. Watch the first stretch of resumed work. + +**Don't let the orchestrator start making decisions before restore is complete.** The orchestrator's value is broad context and wise judgment. Acting on partial context produces worse decisions than waiting 5 minutes to finish reading. The inventory matrix makes this visible — if there are ❌ items in Tiers 1-2, the orchestrator is not ready to decide. + +**Don't skip the peer sync during orchestrator restore.** Even if the restore file is perfect, the peer may have made decisions or received information during the compaction window. The peer status dump closes this gap. Without it, the orchestrator is working from a stale snapshot. + +**Don't assume agents were idle during orchestrator compaction.** Check tmux sessions and git log. Agents may have committed work, hit blockers, gone idle, or context-reset themselves. The orchestrator needs to know the actual state, not the pre-compaction expected state. diff --git a/skills/_canonical/pm/backlog-capture/SKILL.md b/skills/_canonical/pm/backlog-capture/SKILL.md new file mode 100644 index 000000000..04aa6cc59 --- /dev/null +++ b/skills/_canonical/pm/backlog-capture/SKILL.md @@ -0,0 +1,43 @@ +--- +name: backlog-capture +description: "Quickly capture product ideas, feature requests, or insights from meetings and conversations. Rapid documentation with smart categorization and deduplication." +--- + +You help a product manager rapidly capture ideas, feature requests, and insights into a structured backlog. + +## When to Use + +- After meetings where feature ideas or requests surfaced +- When a customer or sales rep mentions a need +- When competitive research reveals a gap +- When a PM has a shower thought worth recording + +## Process + +1. **Take the input** — the PM provides rough text: a meeting quote, a feature idea, a customer request, a competitive gap. + +2. **Structure it** — produce a one-liner for the backlog with: + - **Bold name** — short, descriptive feature name + - **Description** — 1-3 sentences covering: what it is, who it's for, why it matters, where it originated (meeting, customer, competitor) + - **Epic/area** — which product area it belongs to + - **Dependencies** — if it relates to existing features or backlog items + +3. **Check for duplicates** — search the existing backlog for similar items. If a match exists: + - Update the existing item with new evidence rather than creating a duplicate + - Add the new source/date to the existing description + +4. **Append to backlog** — add to the "Ideas Not Yet in Jira" section of the backlog file. + +## Output Format + +```markdown +- **[Feature Name]** — [Description. Who needs it. Why. Origin (meeting/customer/competitor, date).] Belongs under [Epic] epic. [Dependencies if any.] +``` + +## Guidelines + +- **Capture fast, refine later.** The goal is not to lose the idea. Polish comes during prioritization. +- **Include the source.** "From Acme Corp demo feedback (2026-03-15)" is better than "customers want this." +- **Convert relative dates to absolute.** "Next Thursday" becomes "2026-04-10." +- **One idea per entry.** If a meeting produced 5 ideas, create 5 entries. +- **Don't validate here.** That's what `/office-hours` is for. Just capture. diff --git a/skills/_canonical/pm/context-builder/SKILL.md b/skills/_canonical/pm/context-builder/SKILL.md new file mode 100644 index 000000000..0d8106050 --- /dev/null +++ b/skills/_canonical/pm/context-builder/SKILL.md @@ -0,0 +1,87 @@ +--- +name: context-builder +description: "Gather and distill context from meetings, competitors, regulatory sources, and internal discussions. Produces background.md for a feature and updates shared context docs when new knowledge is discovered." +--- + +You are a context research assistant helping a product manager gather and distill all relevant background material for a feature or initiative. + +## What You Produce + +1. **background.md** — Feature-specific context summary. Goes in the feature folder. References shared context sources. +2. **Shared context updates** — When you discover new synthesized knowledge useful across features (e.g., a customer requirements summary, a competitive analysis), write or update the appropriate shared context doc. + +## Three-Layer Context Model + +``` +reference/ Layer 3 — Raw sources (meetings, PDFs, documents) + | distill +context/ Layer 2 — Synthesized markdown (shared across features) + | pull relevant +background.md Layer 1 — Feature-specific context +``` + +## Process + +### Step 1: Understand the Feature + +Ask the PM: +- What feature or initiative is this context for? +- What aspects are most important? (customer needs, competitive, regulatory, technical) +- Any specific meetings, customers, or competitors to focus on? + +### Step 2: Search and Gather + +Search across all layers. Be thorough but focused: + +- **Validation first**: Check the feature folder for `validation.md` (office hours output). If it exists, it has demand evidence, named customers, competitive status quo, and the narrowest wedge. +- **Shared context first**: Check if synthesized context already exists. +- **Meetings**: Search by topic keywords, customer names. Check last 3-6 months. +- **Competitors**: Check competitor research for existing analysis. +- **Regulatory**: Find applicable regulations. +- **Customers**: Look for customer requests and pain points. +- **Existing specs**: Check for related work and shipped features. + +### Step 3: Update Shared Context (if new knowledge found) + +If your research produces synthesized knowledge useful beyond this one feature, write or update the appropriate shared context doc. + +### Step 4: Write background.md + +```markdown +--- +title: "Background: [Feature Name]" +feature: [feature folder name] +updated: [today's date] +sources: + meetings: [list of meeting file paths] + competitive: [list of context/reference paths] + regulatory: [list of relevant regulatory sources] + customers: [list of customer context paths] +--- + +# Background: [Feature Name] + +## Customer Drivers +[Who's asking and why. Key quotes and pain points.] + +## Competitive Landscape +[How competitors handle this. Where we differentiate.] + +## Regulatory Considerations +[Applicable regulations and compliance requirements.] + +## Persona Context +[Which personas use this. Day-in-the-life context.] + +## Internal Context +[Strategic alignment, stakeholder decisions, related initiatives.] +``` + +## Guidelines + +- **Reference, don't duplicate.** Point to source files rather than copying content. +- **Distill, don't dump.** background.md should be under 500 lines. +- **Include sources for everything.** Every claim traces back to a meeting, report, or decision. +- **Highlight what's surprising or non-obvious.** +- **Flag contradictions.** If customers want different things, or data conflicts, call it out. +- **Date your sources.** Context decays. diff --git a/skills/_canonical/pm/exec-summary/SKILL.md b/skills/_canonical/pm/exec-summary/SKILL.md new file mode 100644 index 000000000..bc40c69ec --- /dev/null +++ b/skills/_canonical/pm/exec-summary/SKILL.md @@ -0,0 +1,84 @@ +--- +name: exec-summary +description: "Generate a 1-2 page executive summary for a feature — orients sales, leadership, and engineering from a single document." +--- + +You generate an executive summary for a feature that's ready for development. The summary orients three audiences from one document: sales (pitch), leadership (strategy), and engineering (behavioral overview). + +## What You Produce + +A single `executive-summary.md` file in the feature folder. 600-800 words excluding mockups and FAQ. Written in present tense as if the feature already exists. + +## Sources to Read + +Before writing, silently gather all context from the feature folder: + +1. **requirements.md** — acceptance criteria, business rules, scope, user stories +2. **background.md** — customer drivers, competitive context, regulatory considerations +3. **validation.md** — demand evidence, status quo, desperate user, narrowest wedge +4. **supporting/mockup-ascii.md** — visual mockups (pull 2-3 key screens) + +## Output Structure + +```markdown +--- +title: "Executive Summary: [Feature Name]" +feature: [feature-folder-name] +status: [ready | in-progress | shipped] +jira: [ticket key] +updated: [today's date] +--- + +# [Feature Name] + +## The Problem +[2-3 sentences. Customer pain in their language. Name real customers/prospects.] + +## The Solution +[2-3 sentences. What we built, present tense. No jargon.] + +## Who It's For +[Primary personas + named customers/prospects waiting for this.] + +## Why Now +[Deals it unblocks, competitive gap it closes, what it enables next.] + +## How It Works +[5-8 key capabilities. Describe actual user-facing behavior — enough for a dev to understand what to build.] + +## Key Decisions +[5-8 non-obvious business rules and design choices. Focus on surprising or counter-intuitive ones.] + +## Visual Preview +[2-3 ASCII mockup screens from supporting/ — the key screens that tell the story.] + +## What We're NOT Building +[5-8 key out-of-scope items with brief reason.] + +## Dependencies & Sequencing +[What must ship first. Cross-feature dependencies. Prerequisites.] + +## Success Metrics +[2-4 measurable outcomes. Mix of usage and business metrics.] + +## FAQ + +### For Sales +[2-3 questions. When available, what to tell prospects, competitive positioning.] + +### For Leadership +[2-3 questions. Opportunity cost, strategic fit, risks.] + +### For Engineering +[2-3 questions. Dependencies, known risks, what's deferred, data model implications.] +``` + +## Writing Guidelines + +- **Present tense throughout.** Write as if the feature exists. +- **Customer-readable language.** A prospect should understand sections 1-5. +- **Be specific, not vague.** Name deals, dollar amounts, competitors. +- **Key Decisions should surprise.** Don't list obvious things. +- **Mockups are curated.** Pick the 2-3 that tell the story. +- **FAQ answers should be direct.** No hedging. +- **Hard cap: 2 pages** for core content. FAQ can be a third page. diff --git a/skills/_canonical/pm/office-hours/SKILL.md b/skills/_canonical/pm/office-hours/SKILL.md new file mode 100644 index 000000000..f6c2863b6 --- /dev/null +++ b/skills/_canonical/pm/office-hours/SKILL.md @@ -0,0 +1,129 @@ +--- +name: office-hours +description: "YC-style product validation using six forcing questions. Pressure-tests a feature idea before it becomes a requirement — ensuring real demand, a clear wedge, and evidence behind assumptions." +--- + +You are a YC-style product advisor running office hours. Your job is to pressure-test a feature idea before it becomes a requirement — ensuring there's real demand, a clear wedge, and evidence behind the assumption. + +## The Six Forcing Questions + +Work through these sequentially. Each question builds on the previous answer. + +### 1. Demand Reality +"Who is actively asking for this, and what evidence do you have?" + +- Name specific customers, meetings, or support tickets +- Distinguish between "customers asked for this" vs "we think customers want this" +- Search meeting notes and customer records for actual conversations +- If no evidence: flag it. An assumption isn't demand. + +### 2. Status Quo +"How are users solving this problem today, and why is that not good enough?" + +- Map the current workflow (Excel? Manual? Competitor tool?) +- Reference persona profiles for current technology stack +- Quantify the pain: time wasted, errors, cost, compliance risk +- If the status quo is "fine": question whether this is a real problem + +### 3. Desperate Specificity +"Who is the single most desperate user for this, and what does their day look like?" + +- Get to ONE specific person or company, not a category +- Walk through their actual workflow step by step +- What breaks for them? What's the moment of maximum frustration? +- If nobody is desperate: this might be a "nice to have" not a "must have" + +### 4. Narrowest Wedge +"What is the absolute smallest version of this that would solve the desperate user's problem?" + +- Strip away everything that isn't essential for that one user +- What's the MVP that, if you shipped it tomorrow, would make them switch? +- Reference existing capabilities — what already exists? +- Resist the urge to scope-expand. Narrower is better. + +### 5. Observation / Surprise +"What have you observed or learned that surprised you about this problem?" + +- Non-obvious insights from customer meetings, competitive research, or domain expertise +- Things the team didn't expect to find +- Industry-specific patterns or workflow quirks +- If nothing surprised you: you might not understand the problem deeply enough yet + +### 6. Future-Fit +"If this succeeds, what does it unlock? If it fails, what have we learned?" + +- Does this feature compound? Does it make future features easier? +- Does it strengthen competitive position or just maintain parity? +- What's the learning value even if the feature doesn't land? + +## Process + +### Step 1: Get the Pitch +Ask the PM to describe the feature idea in 2-3 sentences. No jargon, no implementation details. + +### Step 2: Run the Questions +Work through all six questions. After each answer: +- Summarize what you heard +- Rate the strength of the answer (Strong / Needs Work / Red Flag) +- Ask follow-up probes if the answer is vague + +### Step 3: Verdict + +Save the assessment to the feature folder as **`validation.md`**. + +```markdown +--- +title: "Validation: [Feature Name]" +type: validation +verdict: [GO | REFINE | PAUSE] +date: [today's date] +pm: [name] +feature: [feature-folder-name] +--- + +# Validation: [Feature Name] + +## Demand Reality +**Rating: [Strong / Needs Work / Red Flag]** +[Summary of evidence. Name customers, deals, dollar amounts.] + +## Status Quo +**Rating: [Strong / Needs Work / Red Flag]** +[Current workflow and pain. What tools they use today.] + +## Desperate User +**Rating: [Strong / Needs Work / Red Flag]** +[The single most desperate user and their breaking point.] + +## Narrowest Wedge +**Rating: [Strong / Needs Work / Red Flag]** +[The smallest thing worth shipping. What's in, what's out.] + +## Surprise +**Rating: [Strong / Needs Work / Red Flag]** +[Non-obvious insights. What the team didn't expect to find.] + +## Future-Fit +**Rating: [Strong / Needs Work / Red Flag]** +[What this unlocks. How it compounds.] + +## Verdict: [GO / REFINE / PAUSE] +- **GO**: Strong evidence, clear wedge, proceed to requirements +- **REFINE**: Promise but gaps — do more research first (list what) +- **PAUSE**: Insufficient evidence of demand — revisit when evidence emerges + +## Next Steps +- [Specific actions — what to do immediately after this assessment] +``` + +**Naming matters.** This file is read by downstream skills: +- Context builder reads it for customer drivers and competitive context +- Requirements writer reads it for demand evidence, scope, and personas +- Executive summary reads it for the Problem, Why Now, and FAQ sections + +## Guidelines + +- **Be constructively skeptical.** Your job is to find weaknesses before the team invests in building. +- **Push for evidence, not opinions.** "Customers want this" -> "Which customers? When did they say this?" +- **Don't kill ideas — sharpen them.** Even a PAUSE verdict should include what evidence would change it. +- **The narrowest wedge is the most valuable question.** Most features are scoped too broadly. diff --git a/skills/_canonical/pm/plan-review/SKILL.md b/skills/_canonical/pm/plan-review/SKILL.md new file mode 100644 index 000000000..e00ded1ca --- /dev/null +++ b/skills/_canonical/pm/plan-review/SKILL.md @@ -0,0 +1,98 @@ +--- +name: plan-review +description: "Multi-perspective review of a feature plan or requirements doc before development begins. Evaluates from strategy, design/UX, and engineering angles to catch gaps early." +--- + +You are a multi-perspective plan reviewer. Before a feature moves from requirements to development, you evaluate it from three angles to catch gaps, scope drift, and missed opportunities. + +## Three Review Lenses + +### 1. Strategy Review (CEO/Product Leader Lens) + +- Does this align with company growth objectives? +- Which personas does this serve? Are they buyers, users, or influencers? +- How does this compare to what competitors offer? +- Is the scope right? Too ambitious or too focused? +- What's the opportunity cost — what are we NOT building by doing this? + +### 2. Design Review (UX/Interaction Lens) + +Rate these dimensions (0-10): +1. **Information architecture** — discoverable and logically organized? +2. **Interaction states** — empty, loading, error, success, edge cases covered? +3. **User journey** — matches how the persona actually works? +4. **Consistency** — follows existing UI patterns? +5. **Accessibility** — keyboard nav, screen readers, color contrast? +6. **AI integration** — if AI-powered, is it natural and trustworthy? + +### 3. Engineering Feasibility (Technical Lens) + +- Are acceptance criteria specific enough that a dev won't need to guess? +- Are there data model implications needing early discussion? +- Are there dependencies on other features or systems? +- Are there performance/scale considerations? +- Is the scope realistic for the implied timeline? + +## Process + +### Step 1: Read the Material +Read all available docs in the feature folder: +- **validation.md** — office hours verdict, demand evidence, wedge scope (if exists) +- **background.md** — customer drivers, competitive context (if exists) +- **requirements.md** — the main document to review +- **supporting/** — mockups, data files, visual references + +### Step 2: Run All Three Reviews + +### Step 3: Synthesis + +```markdown +## Plan Review: [Feature Name] + +**Date**: [date] +**Reviewed**: [requirements.md path] + +### Strategy Assessment +**Score: [1-10]** +- [Key findings] + +### Design Assessment +**Score: [1-10]** +| Dimension | Score | Notes | +|-----------|-------|-------| +| Information Architecture | X/10 | [notes] | +| Interaction States | X/10 | [notes] | +| User Journey | X/10 | [notes] | +| Consistency | X/10 | [notes] | +| Accessibility | X/10 | [notes] | +| AI Integration | X/10 | [notes] | + +### Engineering Feasibility +**Score: [1-10]** +- [Key findings] + +### Issues Found + +#### Blocking (must fix before dev) +1. [Issue with specific reference to requirement] + +#### Important (should fix, but not blocking) +1. [Issue] + +#### Suggestions (nice to have) +1. [Suggestion] + +### Recommended Actions +- [Specific actions before proceeding to development] +``` + +### Step 4: Generate Executive Summary + +After the review is complete and issues are resolved, generate an executive summary using the exec-summary skill. Save it to the feature folder as `executive-summary.md`. + +## Guidelines + +- **Be specific.** Cite exact requirements that have issues. +- **Reference real context.** Check personas, competitors, and existing features. +- **Don't do the dev's job.** The engineering lens is about PM-side clarity, not architecture. +- **Praise what's good.** Helps the PM know what to keep doing. diff --git a/skills/_canonical/pm/requirements-writer/SKILL.md b/skills/_canonical/pm/requirements-writer/SKILL.md new file mode 100644 index 000000000..1547a55b7 --- /dev/null +++ b/skills/_canonical/pm/requirements-writer/SKILL.md @@ -0,0 +1,113 @@ +--- +name: requirements-writer +description: "Conversational intake that produces a structured requirements.md following a standardized PM schema. Enforces PM lane — no architecture, no estimates, no implementation details. Uses GIVEN/WHEN/THEN acceptance criteria." +--- + +You are an expert product analyst helping a product manager create well-structured feature requirements. + +Your job is to take the PM's rough, unstructured thinking about a feature and — through a focused conversation — produce a `requirements.md` that follows the standardized schema, is clear enough for a developer or AI agent to implement from, and stays firmly in the PM lane. + +**Critical**: AI agents treat everything in requirements.md as literal instructions. Be precise. No aspirational content, no future phases, no nice-to-haves. Only what's being built NOW. + +## Your Boundaries + +You own the "what" and "why." You do NOT: +- Make architecture or implementation decisions +- Estimate timelines or effort +- Suggest specific technical approaches +- Define data models, API contracts, or database schemas + +## Context Gathering + +Before starting the conversation, silently gather context: + +1. **Check for validation.md** (office hours output): If it exists, read it — it contains demand evidence, the desperate user, the narrowest wedge, and the GO/REFINE/PAUSE verdict. Use it to skip questions the PM already answered. +2. **Check for background.md**: May have customer drivers, competitive context, and regulatory considerations. +3. **Check for existing requirements**: Look for any existing specs on this feature. +4. **Check for shipped features**: Look for related as-built specs. + +If validation.md exists with a GO verdict, you can skip demand/scope questions and jump straight to acceptance criteria. + +## Conversation Process + +### Round 1: Absorb and Reflect + +1. **Summarize back** what you understand the feature to be in 2-3 sentences. +2. **Map to existing product.** Identify what this touches, depends on, or extends. +3. **Ask your first round of questions** (5-8 max). Focus on the biggest gaps. + +### Subsequent Rounds + +Each round, ask follow-up questions based on what's still unclear: +- **Early rounds**: Scope, personas, core behavior +- **Middle rounds**: Acceptance criteria (GIVEN/WHEN/THEN), business rules, edge cases +- **Late rounds**: Scope refinements, open questions + +### After Each Exchange + +Return the current state of the requirements. Mark items that still need PM input as `[draft]`. No marker needed for finalized items. + +## Output Schema + +```markdown +--- +title: [Feature Name] +status: draft +owner: [PM name] +product_area: [area] +jira: +branch: +created: [today's date] +updated: [today's date] +depends_on: [] +--- + +# [Feature Name] + +## Problem & Opportunity +[Why this matters. Who feels the pain. 2-4 sentences.] + +## Target Personas +- **Primary**: [Role] +- **Secondary**: [Role] + +## User Stories +- As a [persona], I want [capability], so that [outcome]. + +## Acceptance Criteria + +### [Functional Area 1] +- GIVEN [context or precondition] + WHEN [user action or system event] + THEN [expected observable result] — [draft] if not yet confirmed + +## Business Rules +1. When [condition], then [behavior]. + +## Scope + +### In Scope +- [What this feature covers] + +### Explicitly Out of Scope +- [What is NOT included] + +## Open Questions +- [ ] [Unresolved question] +``` + +## Acceptance Criteria Guidelines + +- **GIVEN** = the starting state or precondition +- **WHEN** = the trigger +- **THEN** = the observable result +- Keep each criterion independent +- Describe what the user sees/experiences, not what the system does internally + +## Guidelines + +- When the PM is unsure, offer 2-3 concrete options with trade-offs. +- Reference existing product behavior when relevant. +- The goal is requirements complete enough that a dev or AI agent doesn't need to chase the PM. +- Scope to current phase only — future phases go in Out of Scope. +- Always ask about business rules — the non-obvious logic is where bugs live. diff --git a/skills/_canonical/pm/ui-mockup/SKILL.md b/skills/_canonical/pm/ui-mockup/SKILL.md new file mode 100644 index 000000000..25a4d71b6 --- /dev/null +++ b/skills/_canonical/pm/ui-mockup/SKILL.md @@ -0,0 +1,76 @@ +--- +name: ui-mockup +description: "Create UI mockups at three fidelity levels — ASCII wireframes for quick iteration, standalone HTML mockups for delivery with requirements, and live prototypes for interaction testing." +--- + +You are a UI prototyping assistant that creates mockups for product managers at three fidelity levels. + +## Three Fidelity Levels + +### Level 1: ASCII Wireframes (fastest, during requirements writing) + +Text-based wireframes in markdown showing layout, information hierarchy, and key interactions. +**Where**: `supporting/mockup-ascii.md` + +Rules: +- Use box-drawing characters for structure +- Show real data, not placeholder text +- Annotate interactive elements +- Note key behaviors below each wireframe +- Include frontmatter with screen list + +### Level 2: Standalone HTML Mockups (for delivery with requirements) + +Self-contained HTML files that look like the real app. Portable, no dependencies except Google Fonts. +**Where**: `supporting/mockup-{feature}.html` + +Rules: +- Match the application's existing styling exactly +- Use real data from the codebase +- Only show what's in requirements.md +- Self-contained single HTML file +- Screen switcher nav to toggle between screens via JavaScript +- Keep under 1,000 lines + +### Level 3: Live Prototypes (for interaction testing) + +Real framework pages using the actual component library. Runs in the dev server. + +Rules: +- Use ONLY existing components — don't create new ones +- Hardcoded mock data, no API calls +- Match existing page styling exactly + +## Process + +### Step 1: Understand What to Mockup + +Read feature folder docs first: +- **requirements.md** — acceptance criteria define what screens are needed +- **validation.md** — the narrowest wedge tells you what's most important to show +- **background.md** — customer drivers and competitive context inform what to emphasize + +Then ask the PM about fidelity level and specific screens. + +### Step 2: Gather Real Data + +- Read the requirements acceptance criteria +- Read existing codebase components to match styling +- Pull real data from seed files or config +- Never use placeholder data + +### Step 3: Create the Mockup + +### Step 4: Connect to Requirements + +- Save to `supporting/` +- Reference from background.md under "Visual References" +- Note in requirements if the mockup informed acceptance criteria + +## Guidelines + +- **Use real data.** Real names, real ranges, real hierarchies. +- **Only show what's in requirements.md.** Don't add features beyond the requirement. +- **Less is more.** 3-5 screens beats 10. +- **Match the app exactly.** Read existing code and match styling patterns. +- **Tell the PM what's real vs mocked.** diff --git a/skills/_canonical/pods/development-team/SKILL.md b/skills/_canonical/pods/development-team/SKILL.md new file mode 100644 index 000000000..b7bca3008 --- /dev/null +++ b/skills/_canonical/pods/development-team/SKILL.md @@ -0,0 +1,149 @@ +--- +name: development-team +description: How the development pod coordinates implementation, QA, and design without skipping gates. +--- + +# Development Team + +You are part of the development pod. Your shared job is to turn product direction into working software without guesswork, hidden assumptions, or skipped review gates. + +## Startup sequence + +Before the pod starts real implementation: +- load the packaged skills named in your role startup checklist +- run `rig whoami --json` +- confirm who is playing implementer, QA, and design in this run +- wait for the orchestrator's real assignment instead of freelancing off a partial guess + +The development pod should feel like a real working pod, not three isolated agents improvising alone. + +## Pod shape + +The development pod may include: +- an implementer who writes the change +- a QA partner who gates every edit +- a designer who clarifies product behavior and UX before implementation fills in the blanks + +Some starters only launch the implementer and QA. Others also launch a designer. The workflow stays the same: clarify first, implement deliberately, verify independently. + +## Shared loop + +This is the default loop for product work: + +``` +1. Clarify the work and the acceptance criteria +2. Implementer sends a pre-edit proposal to QA +3. QA approves or rejects with specifics +4. Implementer changes code with TDD +5. Implementer sends the diff and verification output back to QA +6. QA approves or rejects with specifics +7. If commit authority is enabled, the implementer may commit +8. If commit authority is not enabled, stop at a QA-approved working tree and report that state clearly +``` + +Skip no gates. If the task is ambiguous, resolve the ambiguity before editing. + +## What the implementer must hand QA + +Pre-edit proposal should include: +- the files expected to change +- the behavior or acceptance criteria being targeted +- the first failing test or verification step +- any likely edge cases or invariants + +Post-edit review bundle should include: +- what changed +- the actual verification commands run +- the result of those commands +- any remaining uncertainty or follow-up risk + +QA should not have to reverse-engineer what the implementer thought they were doing. + +## Implementer + +Before proposing: +- read the task fully +- inspect the relevant code before promising a solution +- name the files, tests, and acceptance criteria in the proposal + +After QA rejection: +- read the exact feedback +- fix the issue instead of arguing around it +- resubmit with the changes called out explicitly + +## QA + +QA is not a rubber stamp. QA is a product voice — not just a test gate. + +When reviewing a proposal: +- reject if the scope is wrong +- check whether the planned tests actually prove the contract +- flag hidden risks and missing failure cases + +When reviewing a diff: +- read the actual code, not just the summary +- verify independently when possible +- if you cannot verify independently, require real output in the review bundle and inspect it critically + +If the implementer stalls on a permission or approval prompt, call that out immediately. Do not treat a blocked pane as finished implementation. + +### QA dogfood mode + +When QA is dogfooding (testing existing features rather than gating new code), QA works solo with full autonomy: +- find issues AND fix them in a loop +- test the fix, then move to the next issue +- only escalate architecture-level concerns to the orchestrator +- do not wait for approval to fix obvious bugs during dogfood +- report findings to the chatroom so the rig has visibility + +### QA as a product voice + +QA sees the product from the user's perspective. When QA has insights about naming, UX, error messages, or workflow coherence, those are product contributions — not just defect reports. The orchestrator should give QA architecture input, not limit QA to test gating. + +## Designer + +When present, the designer should work ahead of implementation: +- turn vague goals into concrete flows, states, copy, and interaction choices +- surface edge cases before engineering has to guess +- review built results for coherence, not just visual polish + +The designer is part of the development pod, not a decorative sidecar. + +## Browser testing and dogfood tools + +The development pod has access to browser automation and structured dogfood testing tools: + +- **`agent-browser`** — browser automation CLI. Navigate to the daemon UI, snapshot interactive elements, take annotated screenshots, record repro videos. Use `agent-browser open `, `agent-browser snapshot -i`, `agent-browser screenshot --annotate`. +- **`dogfood`** — structured exploratory testing workflow. Produces a report with screenshots, repro videos, and step-by-step evidence for every finding. +- **`containerized-e2e`** — Docker-based clean-install testing. Simulates a fresh user environment. + +QA typically drives browser and dogfood testing, but both impl and QA should know these tools exist and can use them. When dogfooding UI: +1. Load `/agent-browser` and `/dogfood` +2. Open the daemon UI: `agent-browser open http://127.0.0.1:7433` +3. Systematically explore surfaces, take screenshots as proof +4. Report findings using the PASS/FAIL/GAP format to the chatroom + +## When the pod is blocked + +If the blocker is: +- ambiguity: pull in design or ask the orchestrator for clarification +- failing tests / unexpected behavior: use `systematic-debugging` +- code changes: use `test-driven-development` +- completion claims: use `verification-before-completion` + +Do not hand-wave around blockers. Name them and route them. + +## Communication + +- Pre-edit proposal: `rig send "PRE-EDIT: ..." --verify` +- Review bundle: `rig send "REVIEW BUNDLE: ..." --verify` +- Design clarification: `rig send "Need product/design input on ..." --verify` + +## When blocked + +If permissions block tests, file access, or commits: +1. identify the exact blocked command +2. tell the human what that prevents +3. continue with the work you can still do + +Do not silently stall. Do not pretend blocked verification is complete. diff --git a/skills/_canonical/pods/orchestration-team/SKILL.md b/skills/_canonical/pods/orchestration-team/SKILL.md new file mode 100644 index 000000000..d10941196 --- /dev/null +++ b/skills/_canonical/pods/orchestration-team/SKILL.md @@ -0,0 +1,237 @@ +--- +name: orchestration-team +description: Operating manual for the orchestration pod. Covers lead vs peer roles, monitoring with rig commands, permission handling, implementation pair gating, dogfood loops, review routing, agent behavioral models, intervention discipline, and communication culture. +--- + +# Orchestration Team + +You are part of the orchestration pod. Your job is to keep the team productive, not to do the implementation work yourself. + +## 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`. +2. Run `rig whoami --json` so you know your true identity and observation edges. +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. + +Do not improvise a team model from the first partial snapshot you happen to see. + +## Pod responsibilities + +The orchestration pod is responsible for: +- receiving direction from the human +- breaking work into clear assignments +- dispatching implementation, design, QA, and review work +- watching for idle agents, blocked agents, and coordination gaps + +If there is more than one orchestrator, divide the load: + +**Lead** owns: +- Main work stream and milestone sequencing +- Human communication and product decisions +- Dispatching implementation and review tasks +- Resolving PUSHBACK escalations from agents +- Final call when lead and peer disagree (after one round of genuine discussion) + +**Peer** owns: +- Coverage monitoring — who's idle, who's stuck, who's drifting +- QA flow health — are gates being followed, is QA actually reviewing +- Different-model perspective on architectural decisions +- Mental model sync — keeping shared state current +- Convergence partner for reviews and roundtables + +If there is only one orchestrator, you own both the main work stream and the coverage checks. + +## Delegation rules + +Before delegating: +1. Check `rig ps --nodes` to see who is running, idle, or blocked. +2. Check `rig whoami --json` so you know your delegates and observation edges. +3. If you are in a built-in starter with a known team shape, wait for the expected topology to settle before saying the rig is ready for real work. +4. Re-check `rig ps --nodes --json` until the nodes you expect are present and no longer pending, or report exactly which nodes are still coming up. +5. Do not silently shrink the team model from an early partial inventory. If QA or reviewers are expected by topology, do not reassign their role to yourself just because they were late to the first inventory snapshot. +6. Send clear, scoped tasks: what to do, which files matter, what tests or proof to run, and what done looks like. + +## Task packet shape + +When you dispatch work, give the receiving agent enough structure to act without guessing: +- what outcome you want +- which files or surfaces matter +- what acceptance criteria define success +- what proof or verification you expect back +- which peer or pod they must involve before calling the work complete + +If design clarity is missing, route to design first. +If QA gating is required, say so explicitly in the assignment. +If reviewers should wait for a milestone, say what milestone triggers them. + +After delegating: +1. Let the assigned agent work. +2. Check progress with `rig capture ` when you need a real status update. +3. If an agent is stuck for more than one cycle, investigate and redirect or unblock. + +## Monitoring and unblock loop + +When an agent looks stuck: +1. Capture the pane or transcript and identify the exact blocker. +2. If it is a permission, trust, or approval prompt, treat that as an unblock task, not "the agent is slow." +3. If the blocker is ambiguity, route the question to design, QA, review, or the human instead of leaving the agent to spin. +4. If the blocker is a product bug in OpenRig, say so plainly and adjust the plan around it. + +Do not call a blocked agent "in progress" forever. + +## Starter topology settlement + +For the launch-grade `demo` rig, the expected team is: +- `orch1.lead` +- `orch1.peer` +- `dev1.design` +- `dev1.impl` +- `dev1.qa` +- `rev1.r1` +- `rev1.r2` + +Before you declare the team fully ready or dispatch a real implementation task: +- confirm those nodes exist in `rig ps --nodes --json` +- if any are pending or missing, wait and say exactly which nodes are still starting +- once they appear, refresh your mental model before planning + +If the settled inventory later contradicts your earlier assumption, correct course immediately and use the actual QA/review nodes. + +## Milestone routing + +For launch-grade product work: +- do not let implementation start from pure intuition when product behavior is unclear +- do not let edits land before QA has approved a pre-edit proposal +- do not skip reviewer involvement once there is a real diff, a QA-approved working tree, or a meaningful architectural checkpoint +- if commit authority is disabled, route review on the working tree, verification output, and transcript evidence instead of waiting for a commit + +## When to pull in reviewers + +Ask for review: +- after a significant implementation milestone +- when two agents disagree on approach or quality +- when the human asks for a checkpoint +- when you are unsure whether a piece of work is trustworthy enough to ship + +## Keeping the team utilized + +Check `rig ps --nodes` regularly. If an agent is ready but idle: +- QA with no pending reviews should scan recent work for gaps +- reviewers with no assignment should review the newest meaningful progress +- designers with no open task should audit current flows and clarify ambiguous UX + +Do not let agents idle when there is obviously useful work available. + +## Communication modes + +Use direct `rig send` when: +- you are assigning one agent or one pod +- you need a specific answer from one seat +- you are sending a scoped task packet + +Use the chatroom when: +- the whole rig should see the status +- you are running a roundtable or review checkpoint +- you want startup, milestone, or blocker visibility shared across pods + +Use `rig capture` and `rig transcript` when you need evidence, not guesses. + +## Implementation pair — gated workflow + +When dispatching implementation work, the pair follows this loop: + +1. Impl sends a pre-edit proposal to QA +2. QA approves or rejects with specifics +3. Impl implements with TDD +4. Impl sends post-edit diff to QA +5. QA approves or rejects +6. Impl commits +7. Repeat for next task + +The orchestrator does NOT relay messages between them. They communicate directly via `rig send`. The orchestrator monitors for: +- Permission prompts blocking either agent +- Handshake gaps (both idle, neither initiating) +- Impl skipping the gate (going straight to implementation without QA pre-approval) +- QA not actually reviewing (rubber-stamping) + +Never send impl a "Go" without explicitly stating the FIRST action is to send a pre-edit to QA. Impl will race through an entire task list if given a general "Go." + +## Dogfood fix loop + +When QA is dogfooding (testing existing features), QA works solo with full autonomy: +- QA finds issues AND fixes them in a loop +- QA tests the fix, then moves to the next issue +- QA only escalates architecture-level concerns +- Do not dispatch QA to "test and report" — dispatch to "dogfood, fix what you find, re-test" +- The orchestrator does NOT fix things — QA and impl fix things + +## Permission prompt handling + +Permission prompts are the #1 mechanical blocker. Check for them every monitoring cycle. + +For Codex (3-option prompts): select option 2 ("Yes, and don't ask again") to permanently approve the pattern. +For Claude (2-option): approve with Enter. +For destructive operations (git push, rm, daemon stop, npm publish): DO NOT auto-approve. Check with the human. + +## Agent behavioral models + +### Claude Code agents (impl, reviewers, lead) +- Will blast through an entire task list if given a "Go" without explicit gates +- After being told to slow down, over-corrects to "wait for permission for everything" +- Compaction is catastrophic — full context loss, needs preparation +- After compaction: must re-read ALL skills from disk (skill names survive in system reminders but content is truncated) +- For Claude compact-in-place, use `claude-compact-in-place` and require marshal acceptance before treating a `RESTORED` claim as real + +### Codex agents (QA, peer, R2) +- Self-manages its own context window — do NOT intervene based on context percentage +- Compacts automatically and continues working — this is normal, not an emergency +- Never tell Codex to "wrap up" or "save state" based on context percentage +- Over-engineers when given spec-writing authority — never let Codex write implementation specs +- Excellent at: implementation, code review, dogfood testing, finding edge cases + +## Intervention discipline + +Agents treat orchestrator messages as high-authority commands. They will DROP whatever they're doing to obey, even if their current work is more important. + +Rules: +1. Never command. Provide information. The agent decides when to act. +2. Always say "finish what you're on first." Explicitly. Every time. +3. Frame as context updates, not directives. +4. Do not interrupt working agents. If an agent shows ANY sign of activity, do not send a message. +5. Wait for confirmed idleness (2+ monitoring cycles) before nudging. + +## Destructive operations — hard rules + +NEVER run without human approval: +- `rig down --delete --force` (kills tmux sessions) +- `rig down --force` on adopted/claimed rigs +- `npm publish` +- `git push --force` +- Any command that could kill agent sessions or destroy shared state + +Before any destructive operation: "If this goes wrong, can I undo it?" If no, confirm with the human. + +## After compaction recovery + +1. Re-read ALL skills from disk — actually read the SKILL.md files, not just check names +2. `rig whoami --json` to recover identity +3. `rig ps --nodes` to see the topology +4. Read your restore file and session log if available +5. Ask your peer for a quiz to verify your mental model + +For Claude Code seats in OpenRig, marshals/orchestrators should use `claude-compact-in-place` for the asked-vs-read-depth audit before accepting recovery. Preserve the Codex boundary: do not intervene on Codex context percentage or apply Claude compact-in-place by default. + +## What you do not do + +- write production code just because it would be faster +- override QA or reviewer concerns without understanding them +- pretend blocked agents are making progress +- keep hidden work queues in your head instead of assigning them clearly +- relay messages between agents (they communicate directly) +- auto-approve destructive operations +- rush agents with deadline pressure +- write implementation specs (that's a Claude task, not Codex) +- intervene based on Codex context percentage diff --git a/skills/_canonical/pods/review-team/SKILL.md b/skills/_canonical/pods/review-team/SKILL.md new file mode 100644 index 000000000..7bcaef8fc --- /dev/null +++ b/skills/_canonical/pods/review-team/SKILL.md @@ -0,0 +1,210 @@ +--- +name: review-team +description: Complete operating manual for the review pod. Covers everyday review discipline, anti-slop analysis, empirical verification, context priming, the full deep review protocol (independent → cross-exam → convergence → roundtable), artifact management, and reviewer behavioral awareness. +--- + +# Review Team + +You are part of the review pod. Your value is fresh scrutiny that implementation and QA do not have. + +## Startup sequence + +Before you announce a review position: +- load `using-superpowers`, `openrig-user`, `review-team`, `systematic-debugging`, and `verification-before-completion` +- run `rig whoami --json` +- inspect the current rig state so you know whether you are reviewing a diff, a working tree, verification output, or only startup behavior + +If there is no real review target yet, say that plainly and stay ready. + +## Context priming — always do this first + +Before reviewing ANY code, you must understand the codebase context. Never review cold. + +1. Read the project's `CLAUDE.md` or equivalent conventions doc +2. Read the as-built architecture docs for the subsystems you're reviewing +3. Read the relevant planning/spec docs if they exist +4. Understand the domain vocabulary and key invariants + +If you have blanks — areas you don't understand — say so explicitly and fill them before forming opinions. A review built on misunderstood context is worse than no review. + +For deep reviews, write a **context proof** before proceeding: +- Subsystem purpose summary +- Key invariants (must-not-break rules) +- Architecture boundaries and constraints +- PR/range intent and expected behavior +- Unknowns / missing context +- Confidence scores (0-100) per section + +## Everyday review discipline + +These apply to every review, not just deep reviews. + +### Anti-slop lens + +The primary question for every review: **"Will an agent working on this code in 3 months find two ways to do the same thing?"** + +Check for: +- Code duplication across files or subsystems +- Pattern divergence from established codebase conventions +- Naming inconsistencies that would confuse an agent scanning available commands +- Parallel implementations where one should extend the other +- Abstractions that don't earn their complexity + +### Empirical verification + +Every claim you make must be verified against actual code. Not plausible inference. Not file-tree reasoning. + +- Run the tests yourself: `npm test -w @openrig/daemon -- ` +- Read the actual source at the line you're citing +- If you claim something is broken, write a repro (even a quick `npx tsx -e "..."`) +- If you claim a test is missing, explain what input would break the code +- If you claim duplication exists, cite both locations + +A finding you haven't verified is a finding you shouldn't report. + +### Severity rating + +Rate every finding clearly: +- **MUST-FIX** — blocks merge. Broken behavior, security issue, or test suite failure. +- **HIGH** — contract violation or honesty failure. Should fix before calling the range clean. +- **MEDIUM** — real concern that affects maintenance or agent UX. Should fix soon. +- **LOW** — polish, robustness, or minor inconsistency. Fix when convenient. +- **INFO** — observation worth noting. Not a defect. + +### Reporting findings + +Write review artifacts to disk so they survive compaction: +``` +docs/review//01-review-.md +``` + +Also report to the orchestrator or chatroom: +```bash +rig send "REVIEW: +HIGH :: <file:line> :: <issue> +MEDIUM :: <file:line> :: <issue> +..." --verify +``` + +Or for rig-wide visibility: +```bash +rig chatroom send <rig> "[review] <structured findings>" +``` + +## When to review + +Do not wait forever for a perfect formal handoff. Review when: +- the orchestrator assigns a review checkpoint +- a meaningful implementation milestone appears +- you can see active work and the team would benefit from fresh eyes + +Check for reviewable work with: +```bash +rig capture <impl-session> --lines 30 +rig transcript <impl-session> --tail 50 +git log --oneline -10 +git diff --stat +``` + +If commit authority is disabled, review the working tree, verification output, and implementation transcript instead of waiting for a commit that may never happen. + +## When there is no spec + +When reviewing work that was implemented without a pre-existing spec (ad hoc, dogfood fixes, iterative patches): +- Reconstruct what was intended from commit messages, chatroom history, and code context +- Review against the reconstructed intent, not against a nonexistent plan +- Ask: "Does this code deliver what it appears to intend? Are the contracts honest?" +- This is called a **hindsight review** — you review forward from the code, not backward from a spec + +## Deep review protocol + +For significant milestones, the review team follows a structured multi-phase process. The orchestrator manages the overall flow; reviewers execute these phases. + +### Phase 1: Context priming gate + +Each reviewer independently reads context docs and writes a context proof (see above). The orchestrator reads both proofs and decides GO or NO-GO. No code review starts until the gate passes. + +### Phase 2: Independent reviews + +Each reviewer reads the full diff/range independently and writes findings to disk: +``` +docs/review/<review-name>/01-review-<your-id>.md +``` + +Do NOT read the other reviewer's work during this phase. Independence is the point — different reviewers catch different things. + +Your independent review should cover: +- Test posture (does the suite pass? are there regressions?) +- Theme-by-theme or file-by-file analysis +- Anti-slop audit +- Answers to any review questions from the orchestrator or hindsight doc +- Merge readiness verdict + +### Phase 3: Cross-examination + +Each reviewer reads the other's independent review and responds to every finding: + +- **AGREE** — correct, evidence checks out +- **DISAGREE** — incorrect, here is counter-evidence +- **PARTIALLY AGREE** — valid concern but severity or details are wrong + +You must also state: +- What did they find that you missed? (Be honest about your blind spots) +- What did you find that they missed? +- Do their findings change any of your severity assessments? +- Updated merge readiness verdict + +Write cross-exam to disk: +``` +docs/review/<review-name>/02-cross-review-<your-id>.md +``` + +### Phase 4: Convergence and roundtable + +The orchestration pod reads all reviews and cross-exams and writes a convergence synthesis classifying each finding as: +- **CONFIRMED** — all reviewers agree +- **DISPUTED** — disagreement exists with evidence on both sides +- **WITHDRAWN** — originator retracted + +Then a roundtable in the chatroom where all participants (reviewers + orchestrators) post positions, respond to each other, and converge on final findings and action items. + +Culture for the roundtable: +- Truth-seeking. Not contrarian for theater. Not agreeable to be nice. +- Every participant posts an initial position +- Every participant responds to at least one other's position +- Every participant posts a final concur or amend +- The host does not synthesize early — real back-and-forth first + +### Phase 5: Final output + +The host writes the final roundtable document with: +- Confirmed findings with severity +- Final priority stack (P0 / P1 / P2) +- Action items with owner +- What the implementation team should NOT reopen + +## Reviewer behavioral awareness + +### If you are Claude (R1) +- You tend to be strongest on architecture and weakest on edge-case honesty +- You verify the happy path thoroughly but may miss failure-mode gaps +- You should deliberately check: "What happens when this fails? What happens with bad input? What about the release-then-remove sequence?" + +### If you are Codex (R2) +- You catch edge cases that Claude misses +- You are thorough at empirical verification +- You may over-weight severity on issues that are real but minor +- You should deliberately check: "Is this actually a shipped defect or just a robustness wish?" + +### When reviewers disagree + +Disagreement is useful. Keep your position grounded in evidence and let the orchestrator or roundtable resolve the conflict. Do not collapse your view just to create false consensus. If you're right, defend it. If you're wrong, retract it honestly. + +## When there is nothing obvious to review + +If the team is between milestones: +- check topology state with `rig ps --nodes` +- scan for coverage gaps or risky areas +- offer the orchestrator a proactive review target + +Do not idle without saying so. If you are available, make that explicit. diff --git a/skills/_canonical/process/agent-browser/LOCAL-INSIGHTS.md b/skills/_canonical/process/agent-browser/LOCAL-INSIGHTS.md new file mode 100644 index 000000000..c1acb6b42 --- /dev/null +++ b/skills/_canonical/process/agent-browser/LOCAL-INSIGHTS.md @@ -0,0 +1,189 @@ +# agent-browser: Local Dev Insights + +> Companion to the official SKILL.md. These are gotchas, corrections, and best practices +> discovered through hands-on testing that the upstream skill doesn't cover. +> Last updated: 2026-02-20 | Tested against: v0.13.0 + +--- + +## Command Compatibility Matrix + +**Not all `get` subcommands accept @refs.** This is the #1 source of confusion. + +| Command | @refs | CSS selectors | Notes | +|---------|-------|---------------|-------| +| `get text @e1` | YES | YES | Works with both | +| `get html` | NO | YES | Fails silently with refs | +| `get box` | NO | YES | Returns `{x, y, width, height}` JSON | +| `get styles` | NO | YES | Returns compact summary (font, color, bg, border-radius) | +| `get value` | NO | YES | For form inputs | +| `get attr` | NO | YES | Any HTML attribute | +| `get count` | N/A | YES | Returns element count | +| `get url` | N/A | N/A | No selector needed | +| `get title` | N/A | N/A | No selector needed | +| `click` | YES | YES | Works with both | +| `fill` | YES | YES | Works with both | +| `highlight` | NO | YES | Skill shows `highlight @e1` but this fails | + +**Rule of thumb:** Interaction commands (click, fill, type, check, select) work with @refs. +Inspection commands (get html/box/styles, highlight) need CSS selectors. + +## CSS Selectors: Strict Mode + +Playwright strict mode means CSS selectors must match **exactly one element**. If multiple match, you get an error listing all matches (which is actually helpful for debugging). + +**Strategies for unique selectors:** +- Use IDs: `#fork-button` +- Use unique attributes: `[data-testid="submit"]` +- Combine: `.header > a:first-child` +- Use `nth`: `.item:nth-child(3)` + +## Ref Lifecycle: The Golden Rule + +Refs are invalidated by **any page state change**. This includes: +- Navigation (click links, `open`, `back`, `forward`) +- Scoped snapshots (`snapshot -s`) <-- easy to forget this one +- Form submissions +- Dynamic content (modals, dropdowns, AJAX loads) +- Even `snapshot` itself replaces all previous refs + +**Pattern:** Always snapshot immediately before interacting. Never cache refs across multiple actions that change the page. + +## Snapshot Mode Comparison + +| Flag | What it returns | When to use | +|------|----------------|-------------| +| `-i` | Interactive elements only | **Default choice** - best token efficiency | +| `-i -C` | Interactive + cursor-interactive | When divs with onclick aren't showing up | +| `-c` | Compact (removes empty nodes) | Unreliable - can return "Empty page" on some sites | +| `-d N` | Depth-limited | When `-i` returns too much | +| `-s "#sel"` | Scoped to selector | Laser focus on one component | +| `--json` | JSON format | Programmatic parsing | + +**Token efficiency example:** GitHub repo page with 4,574 DOM elements → `snapshot -i` returns ~25 lines. + +## Annotated Screenshots + +`screenshot --annotate` is powerful but **can hang on complex pages** (known issue #509). If it hangs: +1. Kill with Ctrl-C or timeout +2. Fall back to regular `screenshot` + separate `snapshot -i` +3. Works best on simpler pages + +The annotated screenshot also **caches refs**, so you can interact with elements immediately after without a separate snapshot. + +## Network Monitoring + +```bash +# See all requests (captured since page was opened) +agent-browser network requests + +# Filter to just API calls (huge noise reduction) +agent-browser network requests --filter "/api/" + +# Mock an API response +agent-browser network route "https://api.example.com/data" --body '{"mocked": true}' + +# Block a request (e.g., analytics) +agent-browser network route "https://www.google-analytics.com/*" --abort +``` + +Requests are captured from session start. The `--filter` flag is essential on real sites - without it you get dozens of CSS/image/analytics requests. + +## JavaScript Eval Patterns + +```bash +# Quick one-liner (single quotes, no nesting) +agent-browser eval 'document.title' + +# Complex JS (ALWAYS use --stdin for anything with quotes/arrows/template literals) +agent-browser eval --stdin <<'EVALEOF' +JSON.stringify( + Array.from(document.querySelectorAll("a")) + .map(a => ({ text: a.textContent.trim(), href: a.href })) + .filter(a => a.text.length > 0) + .slice(0, 10) +) +EVALEOF + +# Fetch API from browser context (uses page cookies/auth) +agent-browser eval --stdin <<'EVALEOF' +(async () => { + const res = await fetch('/api/data'); + return JSON.stringify(await res.json()); +})() +EVALEOF +``` + +## Session Management + +- **Always close when done:** `agent-browser close` prevents leaked daemon processes +- **Headed mode for debugging:** `agent-browser --headed open <url>` +- **Persistent headed config:** Add `{"headed": true}` to `~/.agent-browser/config.json` +- **Named sessions for parallel work:** `agent-browser --session name open <url>` + +## Authentication: What Actually Works + +**`--session-name` (state save/restore) does NOT work for all apps.** It saves cookies and localStorage, but apps using HTTP-only cookies, server-side sessions, or complex auth flows may not persist. Tested and failed on: example-app-1 (Example Service One / localhost:8083). + +**`--profile` (persistent Chrome profile) is the reliable approach.** It preserves everything - cookies, localStorage, IndexedDB, cache, service workers. This is what actually works for real apps. + +### Saved Profiles + +| Profile | Service | URL | Command | +|---------|---------|-----|---------| +| `example-app-1` | Example Service One | `http://localhost:8083` | `agent-browser --profile ~/.agent-browser/profiles/example-app-1 open http://localhost:8083` | +| `localhost-3000` | Example Service Two (Clerk auth) | `http://localhost:3000` | `agent-browser --profile ~/.agent-browser/profiles/localhost-3000 open http://localhost:3000` | +| `local-app-email-profile` | Example Service Three (email login) | `http://localhost:3010` | `agent-browser --profile ~/.agent-browser/profiles/local-app-email-profile open http://localhost:3010` | +| `local-app-google-profile` | Example Service Three (Google auth) | `http://localhost:3010` | See Google OAuth note below | + +### Google OAuth Profiles + +Google blocks sign-in from the bundled Chromium ("This browser or app may not be secure"). The workaround is to use the **real Chrome binary** with automation detection disabled: + +```bash +agent-browser \ + --profile ~/.agent-browser/profiles/local-app-google-profile \ + --executable-path "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ + --args "--disable-blink-features=AutomationControlled" \ + open http://localhost:3010 +``` + +**This applies to ANY profile that needs Google OAuth.** Always use `--executable-path` + `--args` for Google sign-in flows. + +### Auth Setup Pattern + +```bash +# First time: login in headed mode (user enters password) +agent-browser --profile ~/.agent-browser/profiles/<name> --headed true open <login-url> +# ... user logs in manually ... +agent-browser close + +# Every future run: headless, already authenticated +agent-browser --profile ~/.agent-browser/profiles/<name> open <app-url> +``` + +### Encryption + +Session state files in `~/.agent-browser/sessions/` are encrypted with AES-256-GCM. +Key stored at `~/.agent-browser/.encryption-key` (chmod 600). +Loaded via `AGENT_BROWSER_ENCRYPTION_KEY` env var in `~/.zshrc`. + +Note: `--profile` directories are NOT encrypted (they're standard Chromium profile dirs). +Keep `~/.agent-browser/profiles/` permissions locked down. + +## Updating the Official Skill + +To sync SKILL.md with upstream while preserving local insights: + +```bash +# Download latest official SKILL.md +curl -sL https://raw.githubusercontent.com/vercel-labs/agent-browser/main/skills/agent-browser/SKILL.md \ + -o ~/.claude/skills/agent-browser/SKILL.md + +# Re-append the local insights reference (3 lines at end of SKILL.md) +cat >> ~/.claude/skills/agent-browser/SKILL.md << 'EOF' + +## Local Dev Insights +**IMPORTANT:** Read `LOCAL-INSIGHTS.md` in this skill directory for gotchas, corrections, and tested workflows discovered through hands-on use that this upstream skill doesn't cover. +EOF +``` diff --git a/skills/_canonical/process/agent-browser/SKILL.md b/skills/_canonical/process/agent-browser/SKILL.md new file mode 100644 index 000000000..493d3972f --- /dev/null +++ b/skills/_canonical/process/agent-browser/SKILL.md @@ -0,0 +1,417 @@ +--- +name: agent-browser +description: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. +allowed-tools: Bash(npx agent-browser:*), Bash(agent-browser:*) +--- + +# Browser Automation with agent-browser + +## Core Workflow + +Every browser automation follows this pattern: + +1. **Navigate**: `agent-browser open <url>` +2. **Snapshot**: `agent-browser snapshot -i` (get element refs like `@e1`, `@e2`) +3. **Interact**: Use refs to click, fill, select +4. **Re-snapshot**: After navigation or DOM changes, get fresh refs + +```bash +agent-browser open https://example.com/form +agent-browser snapshot -i +# Output: @e1 [input type="email"], @e2 [input type="password"], @e3 [button] "Submit" + +agent-browser fill @e1 "user@example.com" +agent-browser fill @e2 "password123" +agent-browser click @e3 +agent-browser wait --load networkidle +agent-browser snapshot -i # Check result +``` + +## Command Chaining + +Commands can be chained with `&&` in a single shell invocation. The browser persists between commands via a background daemon, so chaining is safe and more efficient than separate calls. + +```bash +# Chain open + wait + snapshot in one call +agent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i + +# Chain multiple interactions +agent-browser fill @e1 "user@example.com" && agent-browser fill @e2 "password123" && agent-browser click @e3 + +# Navigate and capture +agent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser screenshot page.png +``` + +**When to chain:** Use `&&` when you don't need to read the output of an intermediate command before proceeding (e.g., open + wait + screenshot). Run commands separately when you need to parse the output first (e.g., snapshot to discover refs, then interact using those refs). + +## Essential Commands + +```bash +# Navigation +agent-browser open <url> # Navigate (aliases: goto, navigate) +agent-browser close # Close browser + +# Snapshot +agent-browser snapshot -i # Interactive elements with refs (recommended) +agent-browser snapshot -i -C # Include cursor-interactive elements (divs with onclick, cursor:pointer) +agent-browser snapshot -s "#selector" # Scope to CSS selector + +# Interaction (use @refs from snapshot) +agent-browser click @e1 # Click element +agent-browser click @e1 --new-tab # Click and open in new tab +agent-browser fill @e2 "text" # Clear and type text +agent-browser type @e2 "text" # Type without clearing +agent-browser select @e1 "option" # Select dropdown option +agent-browser check @e1 # Check checkbox +agent-browser press Enter # Press key +agent-browser scroll down 500 # Scroll page + +# Get information +agent-browser get text @e1 # Get element text +agent-browser get url # Get current URL +agent-browser get title # Get page title + +# Wait +agent-browser wait @e1 # Wait for element +agent-browser wait --load networkidle # Wait for network idle +agent-browser wait --url "**/page" # Wait for URL pattern +agent-browser wait 2000 # Wait milliseconds + +# Capture +agent-browser screenshot # Screenshot to temp dir +agent-browser screenshot --full # Full page screenshot +agent-browser screenshot --annotate # Annotated screenshot with numbered element labels +agent-browser pdf output.pdf # Save as PDF + +# Diff (compare page states) +agent-browser diff snapshot # Compare current vs last snapshot +agent-browser diff snapshot --baseline before.txt # Compare current vs saved file +agent-browser diff screenshot --baseline before.png # Visual pixel diff +agent-browser diff url <url1> <url2> # Compare two pages +agent-browser diff url <url1> <url2> --wait-until networkidle # Custom wait strategy +agent-browser diff url <url1> <url2> --selector "#main" # Scope to element +``` + +## Common Patterns + +### Form Submission + +```bash +agent-browser open https://example.com/signup +agent-browser snapshot -i +agent-browser fill @e1 "Jane Doe" +agent-browser fill @e2 "jane@example.com" +agent-browser select @e3 "California" +agent-browser check @e4 +agent-browser click @e5 +agent-browser wait --load networkidle +``` + +### Authentication with State Persistence + +```bash +# Login once and save state +agent-browser open https://app.example.com/login +agent-browser snapshot -i +agent-browser fill @e1 "$USERNAME" +agent-browser fill @e2 "$PASSWORD" +agent-browser click @e3 +agent-browser wait --url "**/dashboard" +agent-browser state save auth.json + +# Reuse in future sessions +agent-browser state load auth.json +agent-browser open https://app.example.com/dashboard +``` + +### Session Persistence + +```bash +# Auto-save/restore cookies and localStorage across browser restarts +agent-browser --session-name myapp open https://app.example.com/login +# ... login flow ... +agent-browser close # State auto-saved to ~/.agent-browser/sessions/ + +# Next time, state is auto-loaded +agent-browser --session-name myapp open https://app.example.com/dashboard + +# Encrypt state at rest +export AGENT_BROWSER_ENCRYPTION_KEY=$(openssl rand -hex 32) +agent-browser --session-name secure open https://app.example.com + +# Manage saved states +agent-browser state list +agent-browser state show myapp-default.json +agent-browser state clear myapp +agent-browser state clean --older-than 7 +``` + +### Data Extraction + +```bash +agent-browser open https://example.com/products +agent-browser snapshot -i +agent-browser get text @e5 # Get specific element text +agent-browser get text body > page.txt # Get all page text + +# JSON output for parsing +agent-browser snapshot -i --json +agent-browser get text @e1 --json +``` + +### Parallel Sessions + +```bash +agent-browser --session site1 open https://site-a.com +agent-browser --session site2 open https://site-b.com + +agent-browser --session site1 snapshot -i +agent-browser --session site2 snapshot -i + +agent-browser session list +``` + +### Connect to Existing Chrome + +```bash +# Auto-discover running Chrome with remote debugging enabled +agent-browser --auto-connect open https://example.com +agent-browser --auto-connect snapshot + +# Or with explicit CDP port +agent-browser --cdp 9222 snapshot +``` + +### Visual Browser (Debugging) + +```bash +agent-browser --headed open https://example.com +agent-browser highlight @e1 # Highlight element +agent-browser record start demo.webm # Record session +agent-browser profiler start # Start Chrome DevTools profiling +agent-browser profiler stop trace.json # Stop and save profile (path optional) +``` + +### Local Files (PDFs, HTML) + +```bash +# Open local files with file:// URLs +agent-browser --allow-file-access open file:///path/to/document.pdf +agent-browser --allow-file-access open file:///path/to/page.html +agent-browser screenshot output.png +``` + +### iOS Simulator (Mobile Safari) + +```bash +# List available iOS simulators +agent-browser device list + +# Launch Safari on a specific device +agent-browser -p ios --device "iPhone 16 Pro" open https://example.com + +# Same workflow as desktop - snapshot, interact, re-snapshot +agent-browser -p ios snapshot -i +agent-browser -p ios tap @e1 # Tap (alias for click) +agent-browser -p ios fill @e2 "text" +agent-browser -p ios swipe up # Mobile-specific gesture + +# Take screenshot +agent-browser -p ios screenshot mobile.png + +# Close session (shuts down simulator) +agent-browser -p ios close +``` + +**Requirements:** macOS with Xcode, Appium (`npm install -g appium && appium driver install xcuitest`) + +**Real devices:** Works with physical iOS devices if pre-configured. Use `--device "<UDID>"` where UDID is from `xcrun xctrace list devices`. + +## Diffing (Verifying Changes) + +Use `diff snapshot` after performing an action to verify it had the intended effect. This compares the current accessibility tree against the last snapshot taken in the session. + +```bash +# Typical workflow: snapshot -> action -> diff +agent-browser snapshot -i # Take baseline snapshot +agent-browser click @e2 # Perform action +agent-browser diff snapshot # See what changed (auto-compares to last snapshot) +``` + +For visual regression testing or monitoring: + +```bash +# Save a baseline screenshot, then compare later +agent-browser screenshot baseline.png +# ... time passes or changes are made ... +agent-browser diff screenshot --baseline baseline.png + +# Compare staging vs production +agent-browser diff url https://staging.example.com https://prod.example.com --screenshot +``` + +`diff snapshot` output uses `+` for additions and `-` for removals, similar to git diff. `diff screenshot` produces a diff image with changed pixels highlighted in red, plus a mismatch percentage. + +## Timeouts and Slow Pages + +The default Playwright timeout is 60 seconds for local browsers. For slow websites or large pages, use explicit waits instead of relying on the default timeout: + +```bash +# Wait for network activity to settle (best for slow pages) +agent-browser wait --load networkidle + +# Wait for a specific element to appear +agent-browser wait "#content" +agent-browser wait @e1 + +# Wait for a specific URL pattern (useful after redirects) +agent-browser wait --url "**/dashboard" + +# Wait for a JavaScript condition +agent-browser wait --fn "document.readyState === 'complete'" + +# Wait a fixed duration (milliseconds) as a last resort +agent-browser wait 5000 +``` + +When dealing with consistently slow websites, use `wait --load networkidle` after `open` to ensure the page is fully loaded before taking a snapshot. If a specific element is slow to render, wait for it directly with `wait <selector>` or `wait @ref`. + +## Session Management and Cleanup + +When running multiple agents or automations concurrently, always use named sessions to avoid conflicts: + +```bash +# Each agent gets its own isolated session +agent-browser --session agent1 open site-a.com +agent-browser --session agent2 open site-b.com + +# Check active sessions +agent-browser session list +``` + +Always close your browser session when done to avoid leaked processes: + +```bash +agent-browser close # Close default session +agent-browser --session agent1 close # Close specific session +``` + +If a previous session was not closed properly, the daemon may still be running. Use `agent-browser close` to clean it up before starting new work. + +## Ref Lifecycle (Important) + +Refs (`@e1`, `@e2`, etc.) are invalidated when the page changes. Always re-snapshot after: + +- Clicking links or buttons that navigate +- Form submissions +- Dynamic content loading (dropdowns, modals) + +```bash +agent-browser click @e5 # Navigates to new page +agent-browser snapshot -i # MUST re-snapshot +agent-browser click @e1 # Use new refs +``` + +## Annotated Screenshots (Vision Mode) + +Use `--annotate` to take a screenshot with numbered labels overlaid on interactive elements. Each label `[N]` maps to ref `@eN`. This also caches refs, so you can interact with elements immediately without a separate snapshot. + +```bash +agent-browser screenshot --annotate +# Output includes the image path and a legend: +# [1] @e1 button "Submit" +# [2] @e2 link "Home" +# [3] @e3 textbox "Email" +agent-browser click @e2 # Click using ref from annotated screenshot +``` + +Use annotated screenshots when: +- The page has unlabeled icon buttons or visual-only elements +- You need to verify visual layout or styling +- Canvas or chart elements are present (invisible to text snapshots) +- You need spatial reasoning about element positions + +## Semantic Locators (Alternative to Refs) + +When refs are unavailable or unreliable, use semantic locators: + +```bash +agent-browser find text "Sign In" click +agent-browser find label "Email" fill "user@test.com" +agent-browser find role button click --name "Submit" +agent-browser find placeholder "Search" type "query" +agent-browser find testid "submit-btn" click +``` + +## JavaScript Evaluation (eval) + +Use `eval` to run JavaScript in the browser context. **Shell quoting can corrupt complex expressions** -- use `--stdin` or `-b` to avoid issues. + +```bash +# Simple expressions work with regular quoting +agent-browser eval 'document.title' +agent-browser eval 'document.querySelectorAll("img").length' + +# Complex JS: use --stdin with heredoc (RECOMMENDED) +agent-browser eval --stdin <<'EVALEOF' +JSON.stringify( + Array.from(document.querySelectorAll("img")) + .filter(i => !i.alt) + .map(i => ({ src: i.src.split("/").pop(), width: i.width })) +) +EVALEOF + +# Alternative: base64 encoding (avoids all shell escaping issues) +agent-browser eval -b "$(echo -n 'Array.from(document.querySelectorAll("a")).map(a => a.href)' | base64)" +``` + +**Why this matters:** When the shell processes your command, inner double quotes, `!` characters (history expansion), backticks, and `$()` can all corrupt the JavaScript before it reaches agent-browser. The `--stdin` and `-b` flags bypass shell interpretation entirely. + +**Rules of thumb:** +- Single-line, no nested quotes -> regular `eval 'expression'` with single quotes is fine +- Nested quotes, arrow functions, template literals, or multiline -> use `eval --stdin <<'EVALEOF'` +- Programmatic/generated scripts -> use `eval -b` with base64 + +## Configuration File + +Create `agent-browser.json` in the project root for persistent settings: + +```json +{ + "headed": true, + "proxy": "http://localhost:8080", + "profile": "./browser-data" +} +``` + +Priority (lowest to highest): `~/.agent-browser/config.json` < `./agent-browser.json` < env vars < CLI flags. Use `--config <path>` or `AGENT_BROWSER_CONFIG` env var for a custom config file (exits with error if missing/invalid). All CLI options map to camelCase keys (e.g., `--executable-path` -> `"executablePath"`). Boolean flags accept `true`/`false` values (e.g., `--headed false` overrides config). Extensions from user and project configs are merged, not replaced. + +## Deep-Dive Documentation + +| Reference | When to Use | +|-----------|-------------| +| [references/commands.md](references/commands.md) | Full command reference with all options | +| [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle, invalidation rules, troubleshooting | +| [references/session-management.md](references/session-management.md) | Parallel sessions, state persistence, concurrent scraping | +| [references/authentication.md](references/authentication.md) | Login flows, OAuth, 2FA handling, state reuse | +| [references/video-recording.md](references/video-recording.md) | Recording workflows for debugging and documentation | +| [references/profiling.md](references/profiling.md) | Chrome DevTools profiling for performance analysis | +| [references/proxy-support.md](references/proxy-support.md) | Proxy configuration, geo-testing, rotating proxies | + +## Ready-to-Use Templates + +| Template | Description | +|----------|-------------| +| [templates/form-automation.sh](templates/form-automation.sh) | Form filling with validation | +| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, reuse state | +| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Content extraction with screenshots | + +```bash +./templates/form-automation.sh https://example.com/form +./templates/authenticated-session.sh https://app.example.com/login +./templates/capture-workflow.sh https://example.com ./output +``` + +## Local Dev Insights + +**IMPORTANT:** Read `LOCAL-INSIGHTS.md` in this skill directory for gotchas, corrections, and tested workflows discovered through hands-on use that this upstream skill doesn't cover. diff --git a/skills/_canonical/process/brainstorming/SKILL.md b/skills/_canonical/process/brainstorming/SKILL.md new file mode 100644 index 000000000..460f73a28 --- /dev/null +++ b/skills/_canonical/process/brainstorming/SKILL.md @@ -0,0 +1,96 @@ +--- +name: brainstorming +description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation." +--- + +# Brainstorming Ideas Into Designs + +## Overview + +Help turn ideas into fully formed designs and specs through natural collaborative dialogue. + +Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design and get user approval. + +<HARD-GATE> +Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity. +</HARD-GATE> + +## Anti-Pattern: "This Is Too Simple To Need A Design" + +Every project goes through this process. A todo list, a single-function utility, a config change — all of them. "Simple" projects are where unexamined assumptions cause the most wasted work. The design can be short (a few sentences for truly simple projects), but you MUST present it and get approval. + +## Checklist + +You MUST create a task for each of these items and complete them in order: + +1. **Explore project context** — check files, docs, recent commits +2. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria +3. **Propose 2-3 approaches** — with trade-offs and your recommendation +4. **Present design** — in sections scaled to their complexity, get user approval after each section +5. **Write design doc** — save to `docs/plans/YYYY-MM-DD-<topic>-design.md` and commit +6. **Transition to implementation** — invoke writing-plans skill to create implementation plan + +## Process Flow + +```dot +digraph brainstorming { + "Explore project context" [shape=box]; + "Ask clarifying questions" [shape=box]; + "Propose 2-3 approaches" [shape=box]; + "Present design sections" [shape=box]; + "User approves design?" [shape=diamond]; + "Write design doc" [shape=box]; + "Invoke writing-plans skill" [shape=doublecircle]; + + "Explore project context" -> "Ask clarifying questions"; + "Ask clarifying questions" -> "Propose 2-3 approaches"; + "Propose 2-3 approaches" -> "Present design sections"; + "Present design sections" -> "User approves design?"; + "User approves design?" -> "Present design sections" [label="no, revise"]; + "User approves design?" -> "Write design doc" [label="yes"]; + "Write design doc" -> "Invoke writing-plans skill"; +} +``` + +**The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans. + +## The Process + +**Understanding the idea:** +- Check out the current project state first (files, docs, recent commits) +- Ask questions one at a time to refine the idea +- Prefer multiple choice questions when possible, but open-ended is fine too +- Only one question per message - if a topic needs more exploration, break it into multiple questions +- Focus on understanding: purpose, constraints, success criteria + +**Exploring approaches:** +- Propose 2-3 different approaches with trade-offs +- Present options conversationally with your recommendation and reasoning +- Lead with your recommended option and explain why + +**Presenting the design:** +- Once you believe you understand what you're building, present the design +- Scale each section to its complexity: a few sentences if straightforward, up to 200-300 words if nuanced +- Ask after each section whether it looks right so far +- Cover: architecture, components, data flow, error handling, testing +- Be ready to go back and clarify if something doesn't make sense + +## After the Design + +**Documentation:** +- Write the validated design to `docs/plans/YYYY-MM-DD-<topic>-design.md` +- Use elements-of-style:writing-clearly-and-concisely skill if available +- Commit the design document to git + +**Implementation:** +- Invoke the writing-plans skill to create a detailed implementation plan +- Do NOT invoke any other skill. writing-plans is the next step. + +## Key Principles + +- **One question at a time** - Don't overwhelm with multiple questions +- **Multiple choice preferred** - Easier to answer than open-ended when possible +- **YAGNI ruthlessly** - Remove unnecessary features from all designs +- **Explore alternatives** - Always propose 2-3 approaches before settling +- **Incremental validation** - Present design, get approval before moving on +- **Be flexible** - Go back and clarify when something doesn't make sense diff --git a/skills/_canonical/process/containerized-e2e/SKILL.md b/skills/_canonical/process/containerized-e2e/SKILL.md new file mode 100644 index 000000000..855e182f3 --- /dev/null +++ b/skills/_canonical/process/containerized-e2e/SKILL.md @@ -0,0 +1,256 @@ +--- +name: containerized-e2e +description: Run end-to-end dogfood tests inside Docker containers to simulate real user experiences. Use when you need to verify install paths, control plane functionality, UI rendering, or packaging correctness in a clean environment. Triggers include "containerized test", "Docker dogfood", "clean install test", "e2e in container", or testing that requires a fresh environment without dev-mode shortcuts. +allowed-tools: Bash(docker:*), Bash(agent-browser:*), Bash(npx agent-browser:*) +--- + +# Containerized E2E Testing + +Run OpenRig (or any npm-installable CLI + web UI project) through end-to-end testing inside Docker containers, simulating real user install and usage scenarios. + +## When to Use + +- Verifying the npm install path works from a packed tarball +- Testing control plane functionality without live agent runtimes +- Checking UI rendering via agent-browser in a clean environment +- Regression testing after packaging changes +- Phase boundary acceptance gates + +## When NOT to Use + +- Testing live agent behavior (send/capture/broadcast, whoami from inside an agent, transcript capture) — these need real claude-code/codex runtimes on the host +- Quick feedback during active TDD cycles — too slow for the edit/test loop + +## Prerequisites + +- Docker installed and running +- The repo builds successfully (`npm run build` for all workspaces) +- `agent-browser` skill loaded (for UI verification commands) + +## Testing Personas + +### Fresh User + +A brand new user who has never installed OpenRig. Exercises the first-run experience. + +- Empty `~/.openrig/` directory +- No existing rigs, snapshots, or specs +- Tests: install, daemon start, preflight, doctor, first rig up, UI renders + +### Mature User + +A user with existing OpenRig state — rigs, snapshots, library additions, transcripts. + +- Pre-populated `~/.openrig/` via Docker volume persistence +- Build this state organically: run the fresh-user tests first, and the volume accumulates real state +- Tests: restore from existing snapshots, expand existing rigs, library with user-added specs, upgrade-path behaviors + +To set up a mature user volume: + +```bash +# Create a named volume +docker volume create openrig-mature-user + +# Run fresh-user tests with the volume mounted +docker run -it --rm --shm-size=1g \ + -v openrig-mature-user:/root/.openrig \ + -v /tmp/openrig-e2e-artifacts:/artifacts \ + openrig-e2e + +# The volume now has real state from actual rig commands +# Subsequent runs with the same volume simulate a mature user +``` + +## Workflow + +### 1. Build the E2E Image + +Use the provided build script or do it manually: + +```bash +# Using the build script (recommended) +bash {SKILL_DIR}/scripts/build-e2e-image.sh /path/to/repo + +# Or manually: +cd /path/to/repo +npm run build --workspace @openrig/daemon +npm run build --workspace @openrig/ui +npm run build --workspace @openrig/cli +bash scripts/build-package.sh +cd packages/cli && npm pack --pack-destination /tmp/e2e-build +cp {SKILL_DIR}/scripts/Dockerfile /tmp/e2e-build/ +mv /tmp/e2e-build/openrig-cli-*.tgz /tmp/e2e-build/openrig-cli.tgz +cd /tmp/e2e-build && docker build -t openrig-e2e:latest . +``` + +### 2. Start the Container + +```bash +# Fresh user (ephemeral state) +docker run -d --rm --name openrig-e2e \ + --shm-size=1g \ + -v /tmp/openrig-e2e-artifacts:/artifacts \ + openrig-e2e sleep infinity + +# Mature user (persistent volume) +docker run -d --rm --name openrig-e2e \ + --shm-size=1g \ + -v openrig-mature-user:/root/.openrig \ + -v /tmp/openrig-e2e-artifacts:/artifacts \ + openrig-e2e sleep infinity +``` + +**Important:** Always use `--shm-size=1g` for Chromium stability during browser tests. + +### 3. Run Tests Inside the Container + +Execute commands via `docker exec`: + +```bash +# Start the daemon +docker exec openrig-e2e rig daemon start + +# Run preflight and doctor +docker exec openrig-e2e rig preflight --json +docker exec openrig-e2e rig doctor --json + +# Copy test specs into the container +docker cp {SKILL_DIR}/templates/control-plane-test.yaml openrig-e2e:/workspace/ +docker cp {SKILL_DIR}/templates/expansion-pod-fragment.yaml openrig-e2e:/workspace/ +docker cp {SKILL_DIR}/templates/expansion-collision-fragment.yaml openrig-e2e:/workspace/ + +# Launch a rig +docker exec openrig-e2e rig up /workspace/control-plane-test.yaml --json + +# Check topology +docker exec openrig-e2e rig ps --json +docker exec openrig-e2e rig ps --nodes --json +``` + +### 4. Browser Testing Inside the Container + +agent-browser runs inside the container via `docker exec`: + +```bash +# Open the daemon UI +docker exec openrig-e2e agent-browser open http://127.0.0.1:7433 +docker exec openrig-e2e agent-browser wait --load networkidle + +# Inspect interactive elements +docker exec openrig-e2e agent-browser snapshot -i + +# Capture screenshots +docker exec openrig-e2e agent-browser screenshot /artifacts/screenshots/dashboard.png +docker exec openrig-e2e agent-browser screenshot --annotate /artifacts/screenshots/dashboard-annotated.png + +# Navigate and verify specific surfaces +docker exec openrig-e2e agent-browser click @e4 # Open specs drawer (ref from snapshot) +docker exec openrig-e2e agent-browser wait 1000 +docker exec openrig-e2e agent-browser screenshot /artifacts/screenshots/specs-drawer.png +``` + +**ARM64 note:** The Dockerfile uses Debian's system chromium instead of Chrome for Testing, which is unavailable on Linux ARM64. The environment variables `AGENT_BROWSER_EXECUTABLE_PATH` and `AGENT_BROWSER_ARGS` are set in the image. + +### 5. Test Scenarios + +#### Control Plane Lifecycle + +```bash +# Launch the multi-pod test spec +docker exec openrig-e2e rig up /workspace/control-plane-test.yaml --json +RIG_ID=$(docker exec openrig-e2e rig ps --json | jq -r '.[0].rigId') + +# Verify topology +docker exec openrig-e2e rig ps --nodes --json + +# Expand with a new pod +docker exec openrig-e2e rig expand "$RIG_ID" /workspace/expansion-pod-fragment.yaml --json + +# Verify expansion +docker exec openrig-e2e rig ps --nodes --json + +# Test validation rejection (colliding namespace) +docker exec openrig-e2e rig expand "$RIG_ID" /workspace/expansion-collision-fragment.yaml --json +# Should fail with namespace collision error, rig unchanged + +# Snapshot +docker exec openrig-e2e rig down "$RIG_ID" --snapshot --json + +# Restore and verify +SNAPSHOT_ID=$(docker exec openrig-e2e rig snapshot list "$RIG_ID" | awk 'NR==2 {print $1}') +docker exec openrig-e2e rig restore "$SNAPSHOT_ID" --rig "$RIG_ID" + +# Export +docker exec openrig-e2e rig export "$RIG_ID" -o /artifacts/captures/exported-rig.yaml +``` + +#### UI Verification + +```bash +# After launching a rig, verify the graph renders +docker exec openrig-e2e agent-browser open http://127.0.0.1:7433 +docker exec openrig-e2e agent-browser wait --load networkidle +docker exec openrig-e2e agent-browser snapshot -i +docker exec openrig-e2e agent-browser screenshot --annotate /artifacts/screenshots/graph-with-rig.png + +# Open drawers and verify content +docker exec openrig-e2e agent-browser snapshot -i # Get fresh refs +# Click through specs drawer, discovery drawer, rig detail, etc. +# Take screenshots at each step +``` + +### 6. Cleanup + +```bash +docker exec openrig-e2e rig daemon stop +docker exec openrig-e2e agent-browser close +docker stop openrig-e2e +``` + +### 7. Write Report + +Copy the report template and fill it in: + +```bash +cp {SKILL_DIR}/templates/e2e-report-template.md /tmp/openrig-e2e-artifacts/report.md +``` + +Fill in results as tests complete — do not batch findings for the end. + +## Test Spec Templates + +| Template | Purpose | +|----------|---------| +| `templates/control-plane-test.yaml` | Multi-pod terminal-only rig spec (backend + frontend, 3 nodes, cross-pod edges) | +| `templates/expansion-pod-fragment.yaml` | Pod fragment for expansion happy path (ops pod with cross-pod edge) | +| `templates/expansion-collision-fragment.yaml` | Pod fragment that intentionally collides — for validation rejection testing | +| `templates/e2e-report-template.md` | Structured test report template | + +## Scripts + +| Script | Purpose | +|--------|---------| +| `scripts/build-e2e-image.sh` | Build the Docker image from the repo (builds packages, packs tarball, builds image) | +| `scripts/Dockerfile` | The proven Dockerfile — Node 22, tmux, system Chromium, agent-browser, OpenRig CLI | + +## Limitations + +- **No live agent runtimes.** The container does not include claude-code or codex. Use `runtime: terminal` specs for control plane testing. Test live agent behavior on the host. +- **ARM64 browser workaround.** Chrome for Testing is unavailable on Linux ARM64. The Dockerfile uses Debian chromium. This is transparent to agent-browser commands. +- **No GPU/display.** All browser testing is headless. Screenshots and videos capture what a user would see, but there is no visible browser window. + +## Combining with Host-Based Dogfood + +For complete coverage, use both approaches: + +| What to test | Where | Tool | +|-------------|-------|------| +| Install path, packaging | Container | This skill | +| CLI commands, lifecycle | Container | This skill | +| UI rendering, drawers | Container | This skill + agent-browser | +| Validation/error paths | Container | This skill | +| Live agent startup | Host | QA with /dogfood skill | +| Communication (send/capture) | Host | QA with live agents | +| Whoami from inside agent | Host | QA with live agents | +| Transcript capture | Host | QA with live agents | +| Chatroom with real participants | Host | QA with live agents | diff --git a/skills/_canonical/process/containerized-e2e/scripts/Dockerfile b/skills/_canonical/process/containerized-e2e/scripts/Dockerfile new file mode 100644 index 000000000..6a3a2f578 --- /dev/null +++ b/skills/_canonical/process/containerized-e2e/scripts/Dockerfile @@ -0,0 +1,39 @@ +# OpenRig Containerized E2E Testing Image +# +# Provides: Node 22, tmux, agent-browser (with system Chromium), OpenRig CLI +# Usage: +# 1. Build the CLI tarball: cd <repo>/packages/cli && npm pack +# 2. Copy tarball to build context as openrig-cli.tgz +# 3. docker build -t openrig-e2e . +# 4. docker run -it --rm --shm-size=1g -v /tmp/e2e-artifacts:/artifacts openrig-e2e +# +# ARM64 note: Chrome for Testing is unavailable on Linux ARM64. +# This image uses Debian's system chromium instead, pointed via +# AGENT_BROWSER_EXECUTABLE_PATH. + +FROM node:22-bookworm + +ENV DEBIAN_FRONTEND=noninteractive +ENV AGENT_BROWSER_ARGS=--no-sandbox +ENV AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium +ENV OPENRIG_HOME=/root/.openrig + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + chromium \ + curl \ + git \ + procps \ + tmux \ + && rm -rf /var/lib/apt/lists/* + +RUN npm install -g agent-browser + +COPY openrig-cli.tgz /tmp/openrig-cli.tgz +RUN npm install -g /tmp/openrig-cli.tgz \ + && rm /tmp/openrig-cli.tgz + +WORKDIR /workspace + +CMD ["/bin/bash"] diff --git a/skills/_canonical/process/containerized-e2e/scripts/build-e2e-image.sh b/skills/_canonical/process/containerized-e2e/scripts/build-e2e-image.sh new file mode 100755 index 000000000..3d137df58 --- /dev/null +++ b/skills/_canonical/process/containerized-e2e/scripts/build-e2e-image.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Build the OpenRig containerized E2E testing image. +# +# Usage: ./build-e2e-image.sh [repo-root] +# repo-root defaults to the current directory. +# +# Produces: Docker image tagged openrig-e2e:latest + +set -euo pipefail + +REPO_ROOT="${1:-.}" +SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)" +BUILD_CTX="/tmp/openrig-e2e-build" + +echo "=== Building OpenRig packages ===" +cd "$REPO_ROOT" +npm run build --workspace @openrig/daemon +npm run build --workspace @openrig/ui +npm run build --workspace @openrig/cli +bash scripts/build-package.sh + +echo "=== Packing CLI tarball ===" +mkdir -p "$BUILD_CTX" +cd "$REPO_ROOT/packages/cli" +npm pack --pack-destination "$BUILD_CTX" + +echo "=== Preparing Docker build context ===" +cp "$SKILL_DIR/scripts/Dockerfile" "$BUILD_CTX/Dockerfile" +# Rename tarball to a stable name +mv "$BUILD_CTX"/openrig-cli-*.tgz "$BUILD_CTX/openrig-cli.tgz" + +echo "=== Building Docker image ===" +cd "$BUILD_CTX" +docker build -t openrig-e2e:latest . + +echo "=== Done ===" +echo "Run: docker run -it --rm --shm-size=1g -v /tmp/openrig-e2e-artifacts:/artifacts openrig-e2e" diff --git a/skills/_canonical/process/containerized-e2e/templates/control-plane-test.yaml b/skills/_canonical/process/containerized-e2e/templates/control-plane-test.yaml new file mode 100644 index 000000000..461806848 --- /dev/null +++ b/skills/_canonical/process/containerized-e2e/templates/control-plane-test.yaml @@ -0,0 +1,40 @@ +version: "0.2" +name: control-plane-test +summary: > + Multi-pod terminal-only topology for containerized control-plane testing. + Exercises pods, cross-pod edges, expansion targets, and snapshot/restore + without requiring live coding runtimes. + +pods: + - id: backend + label: Backend Team + members: + - id: api + runtime: terminal + agent_ref: "builtin:terminal" + profile: none + cwd: /tmp + - id: db + runtime: terminal + agent_ref: "builtin:terminal" + profile: none + cwd: /tmp + edges: + - kind: delegates_to + from: api + to: db + + - id: frontend + label: Frontend Team + members: + - id: ui + runtime: terminal + agent_ref: "builtin:terminal" + profile: none + cwd: /tmp + edges: [] + +edges: + - kind: delegates_to + from: frontend.ui + to: backend.api diff --git a/skills/_canonical/process/containerized-e2e/templates/e2e-report-template.md b/skills/_canonical/process/containerized-e2e/templates/e2e-report-template.md new file mode 100644 index 000000000..0158affc3 --- /dev/null +++ b/skills/_canonical/process/containerized-e2e/templates/e2e-report-template.md @@ -0,0 +1,94 @@ +# Containerized E2E Test Report + +Date: {{DATE}} +Persona: {{PERSONA}} +Image: openrig-e2e:latest + +## Summary + +- Tests run: {{TOTAL}} +- Passed: {{PASSED}} +- Failed: {{FAILED}} +- Skipped: {{SKIPPED}} + +## Environment + +- Node: {{NODE_VERSION}} +- tmux: {{TMUX_VERSION}} +- Chromium: {{CHROMIUM_VERSION}} +- OpenRig CLI: {{RIG_VERSION}} +- Platform: {{PLATFORM}} + +## Test Results + +### Install & Boot + +| Test | Result | Notes | +|------|--------|-------| +| npm install -g | | | +| rig daemon start | | | +| rig preflight | | | +| rig doctor | | | +| UI loads in browser | | | + +### Rig Lifecycle + +| Test | Result | Notes | +|------|--------|-------| +| rig up (terminal-only spec) | | | +| rig ps / rig ps --nodes | | | +| Graph renders in browser | | | +| rig down --snapshot | | | +| rig restore | | | +| Restored nodes match | | | + +### Expansion + +| Test | Result | Notes | +|------|--------|-------| +| rig expand (happy path) | | | +| Graph updates after expand | | | +| ps --nodes shows new nodes | | | +| Expand with collision (rejected) | | | +| Rig unchanged after rejection | | | + +### Snapshot/Restore with Expansion + +| Test | Result | Notes | +|------|--------|-------| +| Snapshot captures expanded pods | | | +| Restore brings back expanded pods | | | +| Cross-pod edges survive restore | | | +| Export includes expanded topology | | | + +### CLI Surface + +| Test | Result | Notes | +|------|--------|-------| +| rig specs ls | | | +| rig specs show | | | +| rig config | | | +| rig whoami (daemon down) | | | +| rig export | | | + +### UI Surface (agent-browser) + +| Test | Result | Notes | +|------|--------|-------| +| Dashboard renders | | | +| Explorer sidebar | | | +| Specs drawer opens | | | +| Discovery drawer opens | | | +| System drawer opens | | | +| Rig detail drawer | | | +| Node detail in graph | | | + +## Bugs Found + +(Append each bug as discovered — do not batch) + +## Artifacts + +- Screenshots: /artifacts/screenshots/ +- Videos: /artifacts/videos/ +- CLI transcript: /artifacts/cli-transcript.txt diff --git a/skills/_canonical/process/containerized-e2e/templates/expansion-collision-fragment.yaml b/skills/_canonical/process/containerized-e2e/templates/expansion-collision-fragment.yaml new file mode 100644 index 000000000..4c3da8560 --- /dev/null +++ b/skills/_canonical/process/containerized-e2e/templates/expansion-collision-fragment.yaml @@ -0,0 +1,13 @@ +# This fragment intentionally collides with the existing 'backend' pod. +# Use it to verify that expansion validation rejects namespace collisions +# and leaves the rig unchanged. +pod: + id: backend + label: Colliding Pod + members: + - id: worker + runtime: terminal + agent_ref: "builtin:terminal" + profile: none + cwd: /tmp + edges: [] diff --git a/skills/_canonical/process/containerized-e2e/templates/expansion-pod-fragment.yaml b/skills/_canonical/process/containerized-e2e/templates/expansion-pod-fragment.yaml new file mode 100644 index 000000000..297b316f8 --- /dev/null +++ b/skills/_canonical/process/containerized-e2e/templates/expansion-pod-fragment.yaml @@ -0,0 +1,14 @@ +pod: + id: ops + label: Operations + members: + - id: monitor + runtime: terminal + agent_ref: "builtin:terminal" + profile: none + cwd: /tmp + edges: [] +crossPodEdges: + - kind: delegates_to + from: ops.monitor + to: backend.api diff --git a/skills/_canonical/process/dogfood/SKILL.md b/skills/_canonical/process/dogfood/SKILL.md new file mode 100644 index 000000000..dcd7d4d08 --- /dev/null +++ b/skills/_canonical/process/dogfood/SKILL.md @@ -0,0 +1,220 @@ +--- +name: dogfood +description: Systematically explore and test a web application to find bugs, UX issues, and other problems. Use when asked to "dogfood", "QA", "exploratory test", "find issues", "bug hunt", "test this app/site/platform", or review the quality of a web application. Produces a structured report with full reproduction evidence -- step-by-step screenshots, repro videos, and detailed repro steps for every issue -- so findings can be handed directly to the responsible teams. +allowed-tools: Bash(agent-browser:*), Bash(npx agent-browser:*) +--- + +# Dogfood + +Systematically explore a web application, find issues, and produce a report with full reproduction evidence for every finding. + +## Setup + +Only the **Target URL** is required. Everything else has sensible defaults -- use them unless the user explicitly provides an override. + +| Parameter | Default | Example override | +|-----------|---------|-----------------| +| **Target URL** | _(required)_ | `vercel.com`, `http://localhost:3000` | +| **Session name** | Slugified domain (e.g., `vercel.com` -> `vercel-com`) | `--session my-session` | +| **Output directory** | `./dogfood-output/` | `Output directory: /tmp/qa` | +| **Scope** | Full app | `Focus on the billing page` | +| **Authentication** | None | `Sign in to user@example.com` | + +If the user says something like "dogfood vercel.com", start immediately with defaults. Do not ask clarifying questions unless authentication is mentioned but credentials are missing. + +Always use `agent-browser` directly -- never `npx agent-browser`. The direct binary uses the fast Rust client. `npx` routes through Node.js and is significantly slower. + +## Workflow + +``` +1. Initialize Set up session, output dirs, report file +2. Authenticate Sign in if needed, save state +3. Orient Navigate to starting point, take initial snapshot +4. Explore Systematically visit pages and test features +5. Document Screenshot + record each issue as found +6. Wrap up Update summary counts, close session +``` + +### 1. Initialize + +```bash +mkdir -p {OUTPUT_DIR}/screenshots {OUTPUT_DIR}/videos +``` + +Copy the report template into the output directory and fill in the header fields: + +```bash +cp {SKILL_DIR}/templates/dogfood-report-template.md {OUTPUT_DIR}/report.md +``` + +Start a named session: + +```bash +agent-browser --session {SESSION} open {TARGET_URL} +agent-browser --session {SESSION} wait --load networkidle +``` + +### 2. Authenticate + +If the app requires login: + +```bash +agent-browser --session {SESSION} snapshot -i +# Identify login form refs, fill credentials +agent-browser --session {SESSION} fill @e1 "{EMAIL}" +agent-browser --session {SESSION} fill @e2 "{PASSWORD}" +agent-browser --session {SESSION} click @e3 +agent-browser --session {SESSION} wait --load networkidle +``` + +For OTP/email codes: ask the user, wait for their response, then enter the code. + +After successful login, save state for potential reuse: + +```bash +agent-browser --session {SESSION} state save {OUTPUT_DIR}/auth-state.json +``` + +### 3. Orient + +Take an initial annotated screenshot and snapshot to understand the app structure: + +```bash +agent-browser --session {SESSION} screenshot --annotate {OUTPUT_DIR}/screenshots/initial.png +agent-browser --session {SESSION} snapshot -i +``` + +Identify the main navigation elements and map out the sections to visit. + +### 4. Explore + +Read [references/issue-taxonomy.md](references/issue-taxonomy.md) for the full list of what to look for and the exploration checklist. + +**Strategy -- work through the app systematically:** + +- Start from the main navigation. Visit each top-level section. +- Within each section, test interactive elements: click buttons, fill forms, open dropdowns/modals. +- Check edge cases: empty states, error handling, boundary inputs. +- Try realistic end-to-end workflows (create, edit, delete flows). +- Check the browser console for errors periodically. + +**At each page:** + +```bash +agent-browser --session {SESSION} snapshot -i +agent-browser --session {SESSION} screenshot --annotate {OUTPUT_DIR}/screenshots/{page-name}.png +agent-browser --session {SESSION} errors +agent-browser --session {SESSION} console +``` + +Use your judgment on how deep to go. Spend more time on core features and less on peripheral pages. If you find a cluster of issues in one area, investigate deeper. + +### 5. Document Issues (Repro-First) + +Steps 4 and 5 happen together -- explore and document in a single pass. When you find an issue, stop exploring and document it immediately before moving on. Do not explore the whole app first and document later. + +Every issue must be reproducible. When you find something wrong, do not just note it -- prove it with evidence. The goal is that someone reading the report can see exactly what happened and replay it. + +**Choose the right level of evidence for the issue:** + +#### Interactive / behavioral issues (functional, ux, console errors on action) + +These require user interaction to reproduce -- use full repro with video and step-by-step screenshots: + +1. **Start a repro video** _before_ reproducing: + +```bash +agent-browser --session {SESSION} record start {OUTPUT_DIR}/videos/issue-{NNN}-repro.webm +``` + +2. **Walk through the steps at human pace.** Pause 1-2 seconds between actions so the video is watchable. Take a screenshot at each step: + +```bash +agent-browser --session {SESSION} screenshot {OUTPUT_DIR}/screenshots/issue-{NNN}-step-1.png +sleep 1 +# Perform action (click, fill, etc.) +sleep 1 +agent-browser --session {SESSION} screenshot {OUTPUT_DIR}/screenshots/issue-{NNN}-step-2.png +sleep 1 +# ...continue until the issue manifests +``` + +3. **Capture the broken state.** Pause so the viewer can see it, then take an annotated screenshot: + +```bash +sleep 2 +agent-browser --session {SESSION} screenshot --annotate {OUTPUT_DIR}/screenshots/issue-{NNN}-result.png +``` + +4. **Stop the video:** + +```bash +agent-browser --session {SESSION} record stop +``` + +5. Write numbered repro steps in the report, each referencing its screenshot. + +#### Static / visible-on-load issues (typos, placeholder text, clipped text, misalignment, console errors on load) + +These are visible without interaction -- a single annotated screenshot is sufficient. No video, no multi-step repro: + +```bash +agent-browser --session {SESSION} screenshot --annotate {OUTPUT_DIR}/screenshots/issue-{NNN}.png +``` + +Write a brief description and reference the screenshot in the report. Set **Repro Video** to `N/A`. + +--- + +**For all issues:** + +1. **Append to the report immediately.** Do not batch issues for later. Write each one as you find it so nothing is lost if the session is interrupted. + +2. **Increment the issue counter** (ISSUE-001, ISSUE-002, ...). + +### 6. Wrap Up + +Aim to find **5-10 well-documented issues**, then wrap up. Depth of evidence matters more than total count -- 5 issues with full repro beats 20 with vague descriptions. + +After exploring: + +1. Re-read the report and update the summary severity counts so they match the actual issues. Every `### ISSUE-` block must be reflected in the totals. +2. Close the session: + +```bash +agent-browser --session {SESSION} close +``` + +3. Tell the user the report is ready and summarize findings: total issues, breakdown by severity, and the most critical items. + +## Guidance + +- **Repro is everything.** Every issue needs proof -- but match the evidence to the issue. Interactive bugs need video and step-by-step screenshots. Static bugs (typos, placeholder text, visual glitches visible on load) only need a single annotated screenshot. +- **Verify reproducibility before collecting evidence.** Before recording video or taking screenshots, verify the issue is reproducible with at least one retry. If it can't be reproduced consistently, it's not a valid issue. +- **Don't record video for static issues.** A typo or clipped text doesn't benefit from a video. Save video for issues that involve user interaction, timing, or state changes. +- **For interactive issues, screenshot each step.** Capture the before, the action, and the after -- so someone can see the full sequence. +- **Write repro steps that map to screenshots.** Each numbered step in the report should reference its corresponding screenshot. A reader should be able to follow the steps visually without touching a browser. +- **Use the right snapshot command.** + - `snapshot -i` — for finding clickable/fillable elements (buttons, inputs, links) + - `snapshot` (no flag) — for reading page content (text, headings, data lists) +- **Be thorough but use judgment.** You are not following a test script -- you are exploring like a real user would. If something feels off, investigate. +- **Write findings incrementally.** Append each issue to the report as you discover it. If the session is interrupted, findings are preserved. Never batch all issues for the end. +- **Never delete output files.** Do not `rm` screenshots, videos, or the report mid-session. Do not close the session and restart. Work forward, not backward. +- **Never read the target app's source code.** You are testing as a user, not auditing code. Do not read HTML, JS, or config files of the app under test. All findings must come from what you observe in the browser. +- **Check the console.** Many issues are invisible in the UI but show up as JS errors or failed requests. +- **Test like a user, not a robot.** Try common workflows end-to-end. Click things a real user would click. Enter realistic data. +- **Type like a human.** When filling form fields during video recording, use `type` instead of `fill` -- it types character-by-character. Use `fill` only outside of video recording when speed matters. +- **Pace repro videos for humans.** Add `sleep 1` between actions and `sleep 2` before the final result screenshot. Videos should be watchable at 1x speed -- a human reviewing the report needs to see what happened, not a blur of instant state changes. +- **Be efficient with commands.** Batch multiple `agent-browser` commands in a single shell call when they are independent (e.g., `agent-browser ... screenshot ... && agent-browser ... console`). Use `agent-browser --session {SESSION} scroll down 300` for scrolling -- do not use `key` or `evaluate` to scroll. + +## References + +| Reference | When to Read | +|-----------|--------------| +| [references/issue-taxonomy.md](references/issue-taxonomy.md) | Start of session -- calibrate what to look for, severity levels, exploration checklist | + +## Templates + +| Template | Purpose | +|----------|---------| +| [templates/dogfood-report-template.md](templates/dogfood-report-template.md) | Copy into output directory as the report file | diff --git a/skills/_canonical/process/dogfood/references/issue-taxonomy.md b/skills/_canonical/process/dogfood/references/issue-taxonomy.md new file mode 100644 index 000000000..c3edbe573 --- /dev/null +++ b/skills/_canonical/process/dogfood/references/issue-taxonomy.md @@ -0,0 +1,109 @@ +# Issue Taxonomy + +Reference for categorizing issues found during dogfooding. Read this at the start of a dogfood session to calibrate what to look for. + +## Contents + +- [Severity Levels](#severity-levels) +- [Categories](#categories) +- [Exploration Checklist](#exploration-checklist) + +## Severity Levels + +| Severity | Definition | +|----------|------------| +| **critical** | Blocks a core workflow, causes data loss, or crashes the app | +| **high** | Major feature broken or unusable, no workaround | +| **medium** | Feature works but with noticeable problems, workaround exists | +| **low** | Minor cosmetic or polish issue | + +## Categories + +### Visual / UI + +- Layout broken or misaligned elements +- Overlapping or clipped text +- Inconsistent spacing, padding, or margins +- Missing or broken icons/images +- Dark mode / light mode rendering issues +- Responsive layout problems (viewport sizes) +- Z-index stacking issues (elements hidden behind others) +- Font rendering issues (wrong font, size, weight) +- Color contrast problems +- Animation glitches or jank + +### Functional + +- Broken links (404, wrong destination) +- Buttons or controls that do nothing on click +- Form validation that rejects valid input or accepts invalid input +- Incorrect redirects +- Features that fail silently +- State not persisted when expected (lost on refresh, navigation) +- Race conditions (double-submit, stale data) +- Broken search or filtering +- Pagination issues +- File upload/download failures + +### UX + +- Confusing or unclear navigation +- Missing loading indicators or feedback after actions +- Slow or unresponsive interactions (>300ms perceived delay) +- Unclear error messages +- Missing confirmation for destructive actions +- Dead ends (no way to go back or proceed) +- Inconsistent patterns across similar features +- Missing keyboard shortcuts or focus management +- Unintuitive defaults +- Missing empty states or unhelpful empty states + +### Content + +- Typos or grammatical errors +- Outdated or incorrect text +- Placeholder or lorem ipsum content left in +- Truncated text without tooltip or expansion +- Missing or wrong labels +- Inconsistent terminology + +### Performance + +- Slow page loads (>3s) +- Janky scrolling or animations +- Large layout shifts (content jumping) +- Excessive network requests (check via console/network) +- Memory leaks (page slows over time) +- Unoptimized images (large file sizes) + +### Console / Errors + +- JavaScript exceptions in console +- Failed network requests (4xx, 5xx) +- Deprecation warnings +- CORS errors +- Mixed content warnings +- Unhandled promise rejections + +### Accessibility + +- Missing alt text on images +- Unlabeled form inputs +- Poor keyboard navigation (can't tab to elements) +- Focus traps +- Insufficient color contrast +- Missing ARIA attributes on dynamic content +- Screen reader incompatible patterns + +## Exploration Checklist + +Use this as a guide for what to test on each page/feature: + +1. **Visual scan** -- Take an annotated screenshot. Look for layout, alignment, and rendering issues. +2. **Interactive elements** -- Click every button, link, and control. Do they work? Is there feedback? +3. **Forms** -- Fill and submit. Test empty submission, invalid input, and edge cases. +4. **Navigation** -- Follow all navigation paths. Check breadcrumbs, back button, deep links. +5. **States** -- Check empty states, loading states, error states, and full/overflow states. +6. **Console** -- Check for JS errors, failed requests, and warnings. +7. **Responsiveness** -- If relevant, test at different viewport sizes. +8. **Auth boundaries** -- Test what happens when not logged in, with different roles if applicable. diff --git a/skills/_canonical/process/dogfood/templates/dogfood-report-template.md b/skills/_canonical/process/dogfood/templates/dogfood-report-template.md new file mode 100644 index 000000000..a7732a409 --- /dev/null +++ b/skills/_canonical/process/dogfood/templates/dogfood-report-template.md @@ -0,0 +1,53 @@ +# Dogfood Report: {APP_NAME} + +| Field | Value | +|-------|-------| +| **Date** | {DATE} | +| **App URL** | {URL} | +| **Session** | {SESSION_NAME} | +| **Scope** | {SCOPE} | + +## Summary + +| Severity | Count | +|----------|-------| +| Critical | 0 | +| High | 0 | +| Medium | 0 | +| Low | 0 | +| **Total** | **0** | + +## Issues + +<!-- Copy this block for each issue found. Interactive issues need video + step-by-step screenshots. Static issues (typos, visual glitches) only need a single screenshot -- set Repro Video to N/A. --> + +### ISSUE-001: {Short title} + +| Field | Value | +|-------|-------| +| **Severity** | critical / high / medium / low | +| **Category** | visual / functional / ux / content / performance / console / accessibility | +| **URL** | {page URL where issue was found} | +| **Repro Video** | {path to video, or N/A for static issues} | + +**Description** + +{What is wrong, what was expected, and what actually happened.} + +**Repro Steps** + +<!-- Each step has a screenshot. A reader should be able to follow along visually. --> + +1. Navigate to {URL} + ![Step 1](screenshots/issue-001-step-1.png) + +2. {Action -- e.g., click "Settings" in the sidebar} + ![Step 2](screenshots/issue-001-step-2.png) + +3. {Action -- e.g., type "test" in the search field and press Enter} + ![Step 3](screenshots/issue-001-step-3.png) + +4. **Observe:** {what goes wrong -- e.g., the page shows a blank white screen instead of search results} + ![Result](screenshots/issue-001-result.png) + +--- diff --git a/skills/_canonical/process/executing-plans/SKILL.md b/skills/_canonical/process/executing-plans/SKILL.md new file mode 100644 index 000000000..c1b2533f4 --- /dev/null +++ b/skills/_canonical/process/executing-plans/SKILL.md @@ -0,0 +1,84 @@ +--- +name: executing-plans +description: Use when you have a written implementation plan to execute in a separate session with review checkpoints +--- + +# Executing Plans + +## Overview + +Load plan, review critically, execute tasks in batches, report for review between batches. + +**Core principle:** Batch execution with checkpoints for architect review. + +**Announce at start:** "I'm using the executing-plans skill to implement this plan." + +## The Process + +### Step 1: Load and Review Plan +1. Read plan file +2. Review critically - identify any questions or concerns about the plan +3. If concerns: Raise them with your human partner before starting +4. If no concerns: Create TodoWrite and proceed + +### Step 2: Execute Batch +**Default: First 3 tasks** + +For each task: +1. Mark as in_progress +2. Follow each step exactly (plan has bite-sized steps) +3. Run verifications as specified +4. Mark as completed + +### Step 3: Report +When batch complete: +- Show what was implemented +- Show verification output +- Say: "Ready for feedback." + +### Step 4: Continue +Based on feedback: +- Apply changes if needed +- Execute next batch +- Repeat until complete + +### Step 5: Complete Development + +After all tasks complete and verified: +- Announce: "I'm using the finishing-a-development-branch skill to complete this work." +- **REQUIRED SUB-SKILL:** Use superpowers:finishing-a-development-branch +- Follow that skill to verify tests, present options, execute choice + +## When to Stop and Ask for Help + +**STOP executing immediately when:** +- Hit a blocker mid-batch (missing dependency, test fails, instruction unclear) +- Plan has critical gaps preventing starting +- You don't understand an instruction +- Verification fails repeatedly + +**Ask for clarification rather than guessing.** + +## When to Revisit Earlier Steps + +**Return to Review (Step 1) when:** +- Partner updates the plan based on your feedback +- Fundamental approach needs rethinking + +**Don't force through blockers** - stop and ask. + +## Remember +- Review plan critically first +- Follow plan steps exactly +- Don't skip verifications +- Reference skills when plan says to +- Between batches: just report and wait +- Stop when blocked, don't guess +- Never start implementation on main/master branch without explicit user consent + +## Integration + +**Required workflow skills:** +- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting +- **superpowers:writing-plans** - Creates the plan this skill executes +- **superpowers:finishing-a-development-branch** - Complete development after all tasks diff --git a/skills/_canonical/process/frontend-design/LICENSE.txt b/skills/_canonical/process/frontend-design/LICENSE.txt new file mode 100644 index 000000000..f433b1a53 --- /dev/null +++ b/skills/_canonical/process/frontend-design/LICENSE.txt @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/skills/_canonical/process/frontend-design/SKILL.md b/skills/_canonical/process/frontend-design/SKILL.md new file mode 100644 index 000000000..5be498e25 --- /dev/null +++ b/skills/_canonical/process/frontend-design/SKILL.md @@ -0,0 +1,42 @@ +--- +name: frontend-design +description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics. +license: Complete terms in LICENSE.txt +--- + +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. + +The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints. + +## Design Thinking + +Before coding, understand the context and commit to a BOLD aesthetic direction: +- **Purpose**: What problem does this interface solve? Who uses it? +- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction. +- **Constraints**: Technical requirements (framework, performance, accessibility). +- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember? + +**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity. + +Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is: +- Production-grade and functional +- Visually striking and memorable +- Cohesive with a clear aesthetic point-of-view +- Meticulously refined in every detail + +## Frontend Aesthetics Guidelines + +Focus on: +- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font. +- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes. +- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise. +- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density. +- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays. + +NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character. + +Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations. + +**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well. + +Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision. diff --git a/skills/_canonical/process/systematic-debugging/CREATION-LOG.md b/skills/_canonical/process/systematic-debugging/CREATION-LOG.md new file mode 100644 index 000000000..024d00a5e --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/CREATION-LOG.md @@ -0,0 +1,119 @@ +# Creation Log: Systematic Debugging Skill + +Reference example of extracting, structuring, and bulletproofing a critical skill. + +## Source Material + +Extracted debugging framework from `/Users/jesse/.claude/CLAUDE.md`: +- 4-phase systematic process (Investigation → Pattern Analysis → Hypothesis → Implementation) +- Core mandate: ALWAYS find root cause, NEVER fix symptoms +- Rules designed to resist time pressure and rationalization + +## Extraction Decisions + +**What to include:** +- Complete 4-phase framework with all rules +- Anti-shortcuts ("NEVER fix symptom", "STOP and re-analyze") +- Pressure-resistant language ("even if faster", "even if I seem in a hurry") +- Concrete steps for each phase + +**What to leave out:** +- Project-specific context +- Repetitive variations of same rule +- Narrative explanations (condensed to principles) + +## Structure Following skill-creation/SKILL.md + +1. **Rich when_to_use** - Included symptoms and anti-patterns +2. **Type: technique** - Concrete process with steps +3. **Keywords** - "root cause", "symptom", "workaround", "debugging", "investigation" +4. **Flowchart** - Decision point for "fix failed" → re-analyze vs add more fixes +5. **Phase-by-phase breakdown** - Scannable checklist format +6. **Anti-patterns section** - What NOT to do (critical for this skill) + +## Bulletproofing Elements + +Framework designed to resist rationalization under pressure: + +### Language Choices +- "ALWAYS" / "NEVER" (not "should" / "try to") +- "even if faster" / "even if I seem in a hurry" +- "STOP and re-analyze" (explicit pause) +- "Don't skip past" (catches the actual behavior) + +### Structural Defenses +- **Phase 1 required** - Can't skip to implementation +- **Single hypothesis rule** - Forces thinking, prevents shotgun fixes +- **Explicit failure mode** - "IF your first fix doesn't work" with mandatory action +- **Anti-patterns section** - Shows exactly what shortcuts look like + +### Redundancy +- Root cause mandate in overview + when_to_use + Phase 1 + implementation rules +- "NEVER fix symptom" appears 4 times in different contexts +- Each phase has explicit "don't skip" guidance + +## Testing Approach + +Created 4 validation tests following skills/meta/testing-skills-with-subagents: + +### Test 1: Academic Context (No Pressure) +- Simple bug, no time pressure +- **Result:** Perfect compliance, complete investigation + +### Test 2: Time Pressure + Obvious Quick Fix +- User "in a hurry", symptom fix looks easy +- **Result:** Resisted shortcut, followed full process, found real root cause + +### Test 3: Complex System + Uncertainty +- Multi-layer failure, unclear if can find root cause +- **Result:** Systematic investigation, traced through all layers, found source + +### Test 4: Failed First Fix +- Hypothesis doesn't work, temptation to add more fixes +- **Result:** Stopped, re-analyzed, formed new hypothesis (no shotgun) + +**All tests passed.** No rationalizations found. + +## Iterations + +### Initial Version +- Complete 4-phase framework +- Anti-patterns section +- Flowchart for "fix failed" decision + +### Enhancement 1: TDD Reference +- Added link to skills/testing/test-driven-development +- Note explaining TDD's "simplest code" ≠ debugging's "root cause" +- Prevents confusion between methodologies + +## Final Outcome + +Bulletproof skill that: +- ✅ Clearly mandates root cause investigation +- ✅ Resists time pressure rationalization +- ✅ Provides concrete steps for each phase +- ✅ Shows anti-patterns explicitly +- ✅ Tested under multiple pressure scenarios +- ✅ Clarifies relationship to TDD +- ✅ Ready for use + +## Key Insight + +**Most important bulletproofing:** Anti-patterns section showing exact shortcuts that feel justified in the moment. When Claude thinks "I'll just add this one quick fix", seeing that exact pattern listed as wrong creates cognitive friction. + +## Usage Example + +When encountering a bug: +1. Load skill: skills/debugging/systematic-debugging +2. Read overview (10 sec) - reminded of mandate +3. Follow Phase 1 checklist - forced investigation +4. If tempted to skip - see anti-pattern, stop +5. Complete all phases - root cause found + +**Time investment:** 5-10 minutes +**Time saved:** Hours of symptom-whack-a-mole + +--- + +*Created: 2025-10-03* +*Purpose: Reference example for skill extraction and bulletproofing* diff --git a/skills/_canonical/process/systematic-debugging/SKILL.md b/skills/_canonical/process/systematic-debugging/SKILL.md new file mode 100644 index 000000000..111d2a98c --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/SKILL.md @@ -0,0 +1,296 @@ +--- +name: systematic-debugging +description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes +--- + +# Systematic Debugging + +## Overview + +Random fixes waste time and create new bugs. Quick patches mask underlying issues. + +**Core principle:** ALWAYS find root cause before attempting fixes. Symptom fixes are failure. + +**Violating the letter of this process is violating the spirit of debugging.** + +## The Iron Law + +``` +NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST +``` + +If you haven't completed Phase 1, you cannot propose fixes. + +## When to Use + +Use for ANY technical issue: +- Test failures +- Bugs in production +- Unexpected behavior +- Performance problems +- Build failures +- Integration issues + +**Use this ESPECIALLY when:** +- Under time pressure (emergencies make guessing tempting) +- "Just one quick fix" seems obvious +- You've already tried multiple fixes +- Previous fix didn't work +- You don't fully understand the issue + +**Don't skip when:** +- Issue seems simple (simple bugs have root causes too) +- You're in a hurry (rushing guarantees rework) +- Manager wants it fixed NOW (systematic is faster than thrashing) + +## The Four Phases + +You MUST complete each phase before proceeding to the next. + +### Phase 1: Root Cause Investigation + +**BEFORE attempting ANY fix:** + +1. **Read Error Messages Carefully** + - Don't skip past errors or warnings + - They often contain the exact solution + - Read stack traces completely + - Note line numbers, file paths, error codes + +2. **Reproduce Consistently** + - Can you trigger it reliably? + - What are the exact steps? + - Does it happen every time? + - If not reproducible → gather more data, don't guess + +3. **Check Recent Changes** + - What changed that could cause this? + - Git diff, recent commits + - New dependencies, config changes + - Environmental differences + +4. **Gather Evidence in Multi-Component Systems** + + **WHEN system has multiple components (CI → build → signing, API → service → database):** + + **BEFORE proposing fixes, add diagnostic instrumentation:** + ``` + For EACH component boundary: + - Log what data enters component + - Log what data exits component + - Verify environment/config propagation + - Check state at each layer + + Run once to gather evidence showing WHERE it breaks + THEN analyze evidence to identify failing component + THEN investigate that specific component + ``` + + **Example (multi-layer system):** + ```bash + # Layer 1: Workflow + echo "=== Secrets available in workflow: ===" + echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}" + + # Layer 2: Build script + echo "=== Env vars in build script: ===" + env | grep IDENTITY || echo "IDENTITY not in environment" + + # Layer 3: Signing script + echo "=== Keychain state: ===" + security list-keychains + security find-identity -v + + # Layer 4: Actual signing + codesign --sign "$IDENTITY" --verbose=4 "$APP" + ``` + + **This reveals:** Which layer fails (secrets → workflow ✓, workflow → build ✗) + +5. **Trace Data Flow** + + **WHEN error is deep in call stack:** + + See `root-cause-tracing.md` in this directory for the complete backward tracing technique. + + **Quick version:** + - Where does bad value originate? + - What called this with bad value? + - Keep tracing up until you find the source + - Fix at source, not at symptom + +### Phase 2: Pattern Analysis + +**Find the pattern before fixing:** + +1. **Find Working Examples** + - Locate similar working code in same codebase + - What works that's similar to what's broken? + +2. **Compare Against References** + - If implementing pattern, read reference implementation COMPLETELY + - Don't skim - read every line + - Understand the pattern fully before applying + +3. **Identify Differences** + - What's different between working and broken? + - List every difference, however small + - Don't assume "that can't matter" + +4. **Understand Dependencies** + - What other components does this need? + - What settings, config, environment? + - What assumptions does it make? + +### Phase 3: Hypothesis and Testing + +**Scientific method:** + +1. **Form Single Hypothesis** + - State clearly: "I think X is the root cause because Y" + - Write it down + - Be specific, not vague + +2. **Test Minimally** + - Make the SMALLEST possible change to test hypothesis + - One variable at a time + - Don't fix multiple things at once + +3. **Verify Before Continuing** + - Did it work? Yes → Phase 4 + - Didn't work? Form NEW hypothesis + - DON'T add more fixes on top + +4. **When You Don't Know** + - Say "I don't understand X" + - Don't pretend to know + - Ask for help + - Research more + +### Phase 4: Implementation + +**Fix the root cause, not the symptom:** + +1. **Create Failing Test Case** + - Simplest possible reproduction + - Automated test if possible + - One-off test script if no framework + - MUST have before fixing + - Use the `superpowers:test-driven-development` skill for writing proper failing tests + +2. **Implement Single Fix** + - Address the root cause identified + - ONE change at a time + - No "while I'm here" improvements + - No bundled refactoring + +3. **Verify Fix** + - Test passes now? + - No other tests broken? + - Issue actually resolved? + +4. **If Fix Doesn't Work** + - STOP + - Count: How many fixes have you tried? + - If < 3: Return to Phase 1, re-analyze with new information + - **If ≥ 3: STOP and question the architecture (step 5 below)** + - DON'T attempt Fix #4 without architectural discussion + +5. **If 3+ Fixes Failed: Question Architecture** + + **Pattern indicating architectural problem:** + - Each fix reveals new shared state/coupling/problem in different place + - Fixes require "massive refactoring" to implement + - Each fix creates new symptoms elsewhere + + **STOP and question fundamentals:** + - Is this pattern fundamentally sound? + - Are we "sticking with it through sheer inertia"? + - Should we refactor architecture vs. continue fixing symptoms? + + **Discuss with your human partner before attempting more fixes** + + This is NOT a failed hypothesis - this is a wrong architecture. + +## Red Flags - STOP and Follow Process + +If you catch yourself thinking: +- "Quick fix for now, investigate later" +- "Just try changing X and see if it works" +- "Add multiple changes, run tests" +- "Skip the test, I'll manually verify" +- "It's probably X, let me fix that" +- "I don't fully understand but this might work" +- "Pattern says X but I'll adapt it differently" +- "Here are the main problems: [lists fixes without investigation]" +- Proposing solutions before tracing data flow +- **"One more fix attempt" (when already tried 2+)** +- **Each fix reveals new problem in different place** + +**ALL of these mean: STOP. Return to Phase 1.** + +**If 3+ fixes failed:** Question the architecture (see Phase 4.5) + +## your human partner's Signals You're Doing It Wrong + +**Watch for these redirections:** +- "Is that not happening?" - You assumed without verifying +- "Will it show us...?" - You should have added evidence gathering +- "Stop guessing" - You're proposing fixes without understanding +- "Ultrathink this" - Question fundamentals, not just symptoms +- "We're stuck?" (frustrated) - Your approach isn't working + +**When you see these:** STOP. Return to Phase 1. + +## Common Rationalizations + +| Excuse | Reality | +|--------|---------| +| "Issue is simple, don't need process" | Simple issues have root causes too. Process is fast for simple bugs. | +| "Emergency, no time for process" | Systematic debugging is FASTER than guess-and-check thrashing. | +| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. | +| "I'll write test after confirming fix works" | Untested fixes don't stick. Test first proves it. | +| "Multiple fixes at once saves time" | Can't isolate what worked. Causes new bugs. | +| "Reference too long, I'll adapt the pattern" | Partial understanding guarantees bugs. Read it completely. | +| "I see the problem, let me fix it" | Seeing symptoms ≠ understanding root cause. | +| "One more fix attempt" (after 2+ failures) | 3+ failures = architectural problem. Question pattern, don't fix again. | + +## Quick Reference + +| Phase | Key Activities | Success Criteria | +|-------|---------------|------------------| +| **1. Root Cause** | Read errors, reproduce, check changes, gather evidence | Understand WHAT and WHY | +| **2. Pattern** | Find working examples, compare | Identify differences | +| **3. Hypothesis** | Form theory, test minimally | Confirmed or new hypothesis | +| **4. Implementation** | Create test, fix, verify | Bug resolved, tests pass | + +## When Process Reveals "No Root Cause" + +If systematic investigation reveals issue is truly environmental, timing-dependent, or external: + +1. You've completed the process +2. Document what you investigated +3. Implement appropriate handling (retry, timeout, error message) +4. Add monitoring/logging for future investigation + +**But:** 95% of "no root cause" cases are incomplete investigation. + +## Supporting Techniques + +These techniques are part of systematic debugging and available in this directory: + +- **`root-cause-tracing.md`** - Trace bugs backward through call stack to find original trigger +- **`defense-in-depth.md`** - Add validation at multiple layers after finding root cause +- **`condition-based-waiting.md`** - Replace arbitrary timeouts with condition polling + +**Related skills:** +- **superpowers:test-driven-development** - For creating failing test case (Phase 4, Step 1) +- **superpowers:verification-before-completion** - Verify fix worked before claiming success + +## Real-World Impact + +From debugging sessions: +- Systematic approach: 15-30 minutes to fix +- Random fixes approach: 2-3 hours of thrashing +- First-time fix rate: 95% vs 40% +- New bugs introduced: Near zero vs common diff --git a/skills/_canonical/process/systematic-debugging/condition-based-waiting-example.ts b/skills/_canonical/process/systematic-debugging/condition-based-waiting-example.ts new file mode 100644 index 000000000..703a06b65 --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/condition-based-waiting-example.ts @@ -0,0 +1,158 @@ +// Complete implementation of condition-based waiting utilities +// From: Lace test infrastructure improvements (2025-10-03) +// Context: Fixed 15 flaky tests by replacing arbitrary timeouts + +import type { ThreadManager } from '~/threads/thread-manager'; +import type { LaceEvent, LaceEventType } from '~/threads/types'; + +/** + * Wait for a specific event type to appear in thread + * + * @param threadManager - The thread manager to query + * @param threadId - Thread to check for events + * @param eventType - Type of event to wait for + * @param timeoutMs - Maximum time to wait (default 5000ms) + * @returns Promise resolving to the first matching event + * + * Example: + * await waitForEvent(threadManager, agentThreadId, 'TOOL_RESULT'); + */ +export function waitForEvent( + threadManager: ThreadManager, + threadId: string, + eventType: LaceEventType, + timeoutMs = 5000 +): Promise<LaceEvent> { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + const check = () => { + const events = threadManager.getEvents(threadId); + const event = events.find((e) => e.type === eventType); + + if (event) { + resolve(event); + } else if (Date.now() - startTime > timeoutMs) { + reject(new Error(`Timeout waiting for ${eventType} event after ${timeoutMs}ms`)); + } else { + setTimeout(check, 10); // Poll every 10ms for efficiency + } + }; + + check(); + }); +} + +/** + * Wait for a specific number of events of a given type + * + * @param threadManager - The thread manager to query + * @param threadId - Thread to check for events + * @param eventType - Type of event to wait for + * @param count - Number of events to wait for + * @param timeoutMs - Maximum time to wait (default 5000ms) + * @returns Promise resolving to all matching events once count is reached + * + * Example: + * // Wait for 2 AGENT_MESSAGE events (initial response + continuation) + * await waitForEventCount(threadManager, agentThreadId, 'AGENT_MESSAGE', 2); + */ +export function waitForEventCount( + threadManager: ThreadManager, + threadId: string, + eventType: LaceEventType, + count: number, + timeoutMs = 5000 +): Promise<LaceEvent[]> { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + const check = () => { + const events = threadManager.getEvents(threadId); + const matchingEvents = events.filter((e) => e.type === eventType); + + if (matchingEvents.length >= count) { + resolve(matchingEvents); + } else if (Date.now() - startTime > timeoutMs) { + reject( + new Error( + `Timeout waiting for ${count} ${eventType} events after ${timeoutMs}ms (got ${matchingEvents.length})` + ) + ); + } else { + setTimeout(check, 10); + } + }; + + check(); + }); +} + +/** + * Wait for an event matching a custom predicate + * Useful when you need to check event data, not just type + * + * @param threadManager - The thread manager to query + * @param threadId - Thread to check for events + * @param predicate - Function that returns true when event matches + * @param description - Human-readable description for error messages + * @param timeoutMs - Maximum time to wait (default 5000ms) + * @returns Promise resolving to the first matching event + * + * Example: + * // Wait for TOOL_RESULT with specific ID + * await waitForEventMatch( + * threadManager, + * agentThreadId, + * (e) => e.type === 'TOOL_RESULT' && e.data.id === 'call_123', + * 'TOOL_RESULT with id=call_123' + * ); + */ +export function waitForEventMatch( + threadManager: ThreadManager, + threadId: string, + predicate: (event: LaceEvent) => boolean, + description: string, + timeoutMs = 5000 +): Promise<LaceEvent> { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + const check = () => { + const events = threadManager.getEvents(threadId); + const event = events.find(predicate); + + if (event) { + resolve(event); + } else if (Date.now() - startTime > timeoutMs) { + reject(new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`)); + } else { + setTimeout(check, 10); + } + }; + + check(); + }); +} + +// Usage example from actual debugging session: +// +// BEFORE (flaky): +// --------------- +// const messagePromise = agent.sendMessage('Execute tools'); +// await new Promise(r => setTimeout(r, 300)); // Hope tools start in 300ms +// agent.abort(); +// await messagePromise; +// await new Promise(r => setTimeout(r, 50)); // Hope results arrive in 50ms +// expect(toolResults.length).toBe(2); // Fails randomly +// +// AFTER (reliable): +// ---------------- +// const messagePromise = agent.sendMessage('Execute tools'); +// await waitForEventCount(threadManager, threadId, 'TOOL_CALL', 2); // Wait for tools to start +// agent.abort(); +// await messagePromise; +// await waitForEventCount(threadManager, threadId, 'TOOL_RESULT', 2); // Wait for results +// expect(toolResults.length).toBe(2); // Always succeeds +// +// Result: 60% pass rate → 100%, 40% faster execution diff --git a/skills/_canonical/process/systematic-debugging/condition-based-waiting.md b/skills/_canonical/process/systematic-debugging/condition-based-waiting.md new file mode 100644 index 000000000..70994f777 --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/condition-based-waiting.md @@ -0,0 +1,115 @@ +# Condition-Based Waiting + +## Overview + +Flaky tests often guess at timing with arbitrary delays. This creates race conditions where tests pass on fast machines but fail under load or in CI. + +**Core principle:** Wait for the actual condition you care about, not a guess about how long it takes. + +## When to Use + +```dot +digraph when_to_use { + "Test uses setTimeout/sleep?" [shape=diamond]; + "Testing timing behavior?" [shape=diamond]; + "Document WHY timeout needed" [shape=box]; + "Use condition-based waiting" [shape=box]; + + "Test uses setTimeout/sleep?" -> "Testing timing behavior?" [label="yes"]; + "Testing timing behavior?" -> "Document WHY timeout needed" [label="yes"]; + "Testing timing behavior?" -> "Use condition-based waiting" [label="no"]; +} +``` + +**Use when:** +- Tests have arbitrary delays (`setTimeout`, `sleep`, `time.sleep()`) +- Tests are flaky (pass sometimes, fail under load) +- Tests timeout when run in parallel +- Waiting for async operations to complete + +**Don't use when:** +- Testing actual timing behavior (debounce, throttle intervals) +- Always document WHY if using arbitrary timeout + +## Core Pattern + +```typescript +// ❌ BEFORE: Guessing at timing +await new Promise(r => setTimeout(r, 50)); +const result = getResult(); +expect(result).toBeDefined(); + +// ✅ AFTER: Waiting for condition +await waitFor(() => getResult() !== undefined); +const result = getResult(); +expect(result).toBeDefined(); +``` + +## Quick Patterns + +| Scenario | Pattern | +|----------|---------| +| Wait for event | `waitFor(() => events.find(e => e.type === 'DONE'))` | +| Wait for state | `waitFor(() => machine.state === 'ready')` | +| Wait for count | `waitFor(() => items.length >= 5)` | +| Wait for file | `waitFor(() => fs.existsSync(path))` | +| Complex condition | `waitFor(() => obj.ready && obj.value > 10)` | + +## Implementation + +Generic polling function: +```typescript +async function waitFor<T>( + condition: () => T | undefined | null | false, + description: string, + timeoutMs = 5000 +): Promise<T> { + const startTime = Date.now(); + + while (true) { + const result = condition(); + if (result) return result; + + if (Date.now() - startTime > timeoutMs) { + throw new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`); + } + + await new Promise(r => setTimeout(r, 10)); // Poll every 10ms + } +} +``` + +See `condition-based-waiting-example.ts` in this directory for complete implementation with domain-specific helpers (`waitForEvent`, `waitForEventCount`, `waitForEventMatch`) from actual debugging session. + +## Common Mistakes + +**❌ Polling too fast:** `setTimeout(check, 1)` - wastes CPU +**✅ Fix:** Poll every 10ms + +**❌ No timeout:** Loop forever if condition never met +**✅ Fix:** Always include timeout with clear error + +**❌ Stale data:** Cache state before loop +**✅ Fix:** Call getter inside loop for fresh data + +## When Arbitrary Timeout IS Correct + +```typescript +// Tool ticks every 100ms - need 2 ticks to verify partial output +await waitForEvent(manager, 'TOOL_STARTED'); // First: wait for condition +await new Promise(r => setTimeout(r, 200)); // Then: wait for timed behavior +// 200ms = 2 ticks at 100ms intervals - documented and justified +``` + +**Requirements:** +1. First wait for triggering condition +2. Based on known timing (not guessing) +3. Comment explaining WHY + +## Real-World Impact + +From debugging session (2025-10-03): +- Fixed 15 flaky tests across 3 files +- Pass rate: 60% → 100% +- Execution time: 40% faster +- No more race conditions diff --git a/skills/_canonical/process/systematic-debugging/defense-in-depth.md b/skills/_canonical/process/systematic-debugging/defense-in-depth.md new file mode 100644 index 000000000..e2483354d --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/defense-in-depth.md @@ -0,0 +1,122 @@ +# Defense-in-Depth Validation + +## Overview + +When you fix a bug caused by invalid data, adding validation at one place feels sufficient. But that single check can be bypassed by different code paths, refactoring, or mocks. + +**Core principle:** Validate at EVERY layer data passes through. Make the bug structurally impossible. + +## Why Multiple Layers + +Single validation: "We fixed the bug" +Multiple layers: "We made the bug impossible" + +Different layers catch different cases: +- Entry validation catches most bugs +- Business logic catches edge cases +- Environment guards prevent context-specific dangers +- Debug logging helps when other layers fail + +## The Four Layers + +### Layer 1: Entry Point Validation +**Purpose:** Reject obviously invalid input at API boundary + +```typescript +function createProject(name: string, workingDirectory: string) { + if (!workingDirectory || workingDirectory.trim() === '') { + throw new Error('workingDirectory cannot be empty'); + } + if (!existsSync(workingDirectory)) { + throw new Error(`workingDirectory does not exist: ${workingDirectory}`); + } + if (!statSync(workingDirectory).isDirectory()) { + throw new Error(`workingDirectory is not a directory: ${workingDirectory}`); + } + // ... proceed +} +``` + +### Layer 2: Business Logic Validation +**Purpose:** Ensure data makes sense for this operation + +```typescript +function initializeWorkspace(projectDir: string, sessionId: string) { + if (!projectDir) { + throw new Error('projectDir required for workspace initialization'); + } + // ... proceed +} +``` + +### Layer 3: Environment Guards +**Purpose:** Prevent dangerous operations in specific contexts + +```typescript +async function gitInit(directory: string) { + // In tests, refuse git init outside temp directories + if (process.env.NODE_ENV === 'test') { + const normalized = normalize(resolve(directory)); + const tmpDir = normalize(resolve(tmpdir())); + + if (!normalized.startsWith(tmpDir)) { + throw new Error( + `Refusing git init outside temp dir during tests: ${directory}` + ); + } + } + // ... proceed +} +``` + +### Layer 4: Debug Instrumentation +**Purpose:** Capture context for forensics + +```typescript +async function gitInit(directory: string) { + const stack = new Error().stack; + logger.debug('About to git init', { + directory, + cwd: process.cwd(), + stack, + }); + // ... proceed +} +``` + +## Applying the Pattern + +When you find a bug: + +1. **Trace the data flow** - Where does bad value originate? Where used? +2. **Map all checkpoints** - List every point data passes through +3. **Add validation at each layer** - Entry, business, environment, debug +4. **Test each layer** - Try to bypass layer 1, verify layer 2 catches it + +## Example from Session + +Bug: Empty `projectDir` caused `git init` in source code + +**Data flow:** +1. Test setup → empty string +2. `Project.create(name, '')` +3. `WorkspaceManager.createWorkspace('')` +4. `git init` runs in `process.cwd()` + +**Four layers added:** +- Layer 1: `Project.create()` validates not empty/exists/writable +- Layer 2: `WorkspaceManager` validates projectDir not empty +- Layer 3: `WorktreeManager` refuses git init outside tmpdir in tests +- Layer 4: Stack trace logging before git init + +**Result:** All 1847 tests passed, bug impossible to reproduce + +## Key Insight + +All four layers were necessary. During testing, each layer caught bugs the others missed: +- Different code paths bypassed entry validation +- Mocks bypassed business logic checks +- Edge cases on different platforms needed environment guards +- Debug logging identified structural misuse + +**Don't stop at one validation point.** Add checks at every layer. diff --git a/skills/_canonical/process/systematic-debugging/find-polluter.sh b/skills/_canonical/process/systematic-debugging/find-polluter.sh new file mode 100755 index 000000000..1d71c5607 --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/find-polluter.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# Bisection script to find which test creates unwanted files/state +# Usage: ./find-polluter.sh <file_or_dir_to_check> <test_pattern> +# Example: ./find-polluter.sh '.git' 'src/**/*.test.ts' + +set -e + +if [ $# -ne 2 ]; then + echo "Usage: $0 <file_to_check> <test_pattern>" + echo "Example: $0 '.git' 'src/**/*.test.ts'" + exit 1 +fi + +POLLUTION_CHECK="$1" +TEST_PATTERN="$2" + +echo "🔍 Searching for test that creates: $POLLUTION_CHECK" +echo "Test pattern: $TEST_PATTERN" +echo "" + +# Get list of test files +TEST_FILES=$(find . -path "$TEST_PATTERN" | sort) +TOTAL=$(echo "$TEST_FILES" | wc -l | tr -d ' ') + +echo "Found $TOTAL test files" +echo "" + +COUNT=0 +for TEST_FILE in $TEST_FILES; do + COUNT=$((COUNT + 1)) + + # Skip if pollution already exists + if [ -e "$POLLUTION_CHECK" ]; then + echo "⚠️ Pollution already exists before test $COUNT/$TOTAL" + echo " Skipping: $TEST_FILE" + continue + fi + + echo "[$COUNT/$TOTAL] Testing: $TEST_FILE" + + # Run the test + npm test "$TEST_FILE" > /dev/null 2>&1 || true + + # Check if pollution appeared + if [ -e "$POLLUTION_CHECK" ]; then + echo "" + echo "🎯 FOUND POLLUTER!" + echo " Test: $TEST_FILE" + echo " Created: $POLLUTION_CHECK" + echo "" + echo "Pollution details:" + ls -la "$POLLUTION_CHECK" + echo "" + echo "To investigate:" + echo " npm test $TEST_FILE # Run just this test" + echo " cat $TEST_FILE # Review test code" + exit 1 + fi +done + +echo "" +echo "✅ No polluter found - all tests clean!" +exit 0 diff --git a/skills/_canonical/process/systematic-debugging/root-cause-tracing.md b/skills/_canonical/process/systematic-debugging/root-cause-tracing.md new file mode 100644 index 000000000..948477497 --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/root-cause-tracing.md @@ -0,0 +1,169 @@ +# Root Cause Tracing + +## Overview + +Bugs often manifest deep in the call stack (git init in wrong directory, file created in wrong location, database opened with wrong path). Your instinct is to fix where the error appears, but that's treating a symptom. + +**Core principle:** Trace backward through the call chain until you find the original trigger, then fix at the source. + +## When to Use + +```dot +digraph when_to_use { + "Bug appears deep in stack?" [shape=diamond]; + "Can trace backwards?" [shape=diamond]; + "Fix at symptom point" [shape=box]; + "Trace to original trigger" [shape=box]; + "BETTER: Also add defense-in-depth" [shape=box]; + + "Bug appears deep in stack?" -> "Can trace backwards?" [label="yes"]; + "Can trace backwards?" -> "Trace to original trigger" [label="yes"]; + "Can trace backwards?" -> "Fix at symptom point" [label="no - dead end"]; + "Trace to original trigger" -> "BETTER: Also add defense-in-depth"; +} +``` + +**Use when:** +- Error happens deep in execution (not at entry point) +- Stack trace shows long call chain +- Unclear where invalid data originated +- Need to find which test/code triggers the problem + +## The Tracing Process + +### 1. Observe the Symptom +``` +Error: git init failed in /Users/jesse/project/packages/core +``` + +### 2. Find Immediate Cause +**What code directly causes this?** +```typescript +await execFileAsync('git', ['init'], { cwd: projectDir }); +``` + +### 3. Ask: What Called This? +```typescript +WorktreeManager.createSessionWorktree(projectDir, sessionId) + → called by Session.initializeWorkspace() + → called by Session.create() + → called by test at Project.create() +``` + +### 4. Keep Tracing Up +**What value was passed?** +- `projectDir = ''` (empty string!) +- Empty string as `cwd` resolves to `process.cwd()` +- That's the source code directory! + +### 5. Find Original Trigger +**Where did empty string come from?** +```typescript +const context = setupCoreTest(); // Returns { tempDir: '' } +Project.create('name', context.tempDir); // Accessed before beforeEach! +``` + +## Adding Stack Traces + +When you can't trace manually, add instrumentation: + +```typescript +// Before the problematic operation +async function gitInit(directory: string) { + const stack = new Error().stack; + console.error('DEBUG git init:', { + directory, + cwd: process.cwd(), + nodeEnv: process.env.NODE_ENV, + stack, + }); + + await execFileAsync('git', ['init'], { cwd: directory }); +} +``` + +**Critical:** Use `console.error()` in tests (not logger - may not show) + +**Run and capture:** +```bash +npm test 2>&1 | grep 'DEBUG git init' +``` + +**Analyze stack traces:** +- Look for test file names +- Find the line number triggering the call +- Identify the pattern (same test? same parameter?) + +## Finding Which Test Causes Pollution + +If something appears during tests but you don't know which test: + +Use the bisection script `find-polluter.sh` in this directory: + +```bash +./find-polluter.sh '.git' 'src/**/*.test.ts' +``` + +Runs tests one-by-one, stops at first polluter. See script for usage. + +## Real Example: Empty projectDir + +**Symptom:** `.git` created in `packages/core/` (source code) + +**Trace chain:** +1. `git init` runs in `process.cwd()` ← empty cwd parameter +2. WorktreeManager called with empty projectDir +3. Session.create() passed empty string +4. Test accessed `context.tempDir` before beforeEach +5. setupCoreTest() returns `{ tempDir: '' }` initially + +**Root cause:** Top-level variable initialization accessing empty value + +**Fix:** Made tempDir a getter that throws if accessed before beforeEach + +**Also added defense-in-depth:** +- Layer 1: Project.create() validates directory +- Layer 2: WorkspaceManager validates not empty +- Layer 3: NODE_ENV guard refuses git init outside tmpdir +- Layer 4: Stack trace logging before git init + +## Key Principle + +```dot +digraph principle { + "Found immediate cause" [shape=ellipse]; + "Can trace one level up?" [shape=diamond]; + "Trace backwards" [shape=box]; + "Is this the source?" [shape=diamond]; + "Fix at source" [shape=box]; + "Add validation at each layer" [shape=box]; + "Bug impossible" [shape=doublecircle]; + "NEVER fix just the symptom" [shape=octagon, style=filled, fillcolor=red, fontcolor=white]; + + "Found immediate cause" -> "Can trace one level up?"; + "Can trace one level up?" -> "Trace backwards" [label="yes"]; + "Can trace one level up?" -> "NEVER fix just the symptom" [label="no"]; + "Trace backwards" -> "Is this the source?"; + "Is this the source?" -> "Trace backwards" [label="no - keeps going"]; + "Is this the source?" -> "Fix at source" [label="yes"]; + "Fix at source" -> "Add validation at each layer"; + "Add validation at each layer" -> "Bug impossible"; +} +``` + +**NEVER fix just where the error appears.** Trace back to find the original trigger. + +## Stack Trace Tips + +**In tests:** Use `console.error()` not logger - logger may be suppressed +**Before operation:** Log before the dangerous operation, not after it fails +**Include context:** Directory, cwd, environment variables, timestamps +**Capture stack:** `new Error().stack` shows complete call chain + +## Real-World Impact + +From debugging session (2025-10-03): +- Found root cause through 5-level trace +- Fixed at source (getter validation) +- Added 4 layers of defense +- 1847 tests passed, zero pollution diff --git a/skills/_canonical/process/systematic-debugging/test-academic.md b/skills/_canonical/process/systematic-debugging/test-academic.md new file mode 100644 index 000000000..23a6ed7a2 --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/test-academic.md @@ -0,0 +1,14 @@ +# Academic Test: Systematic Debugging Skill + +You have access to the systematic debugging skill at skills/debugging/systematic-debugging + +Read the skill and answer these questions based SOLELY on what the skill says: + +1. What are the four phases of systematic debugging? +2. What must you do BEFORE attempting any fix? +3. In Phase 3, what should you do if your first hypothesis doesn't work? +4. What does the skill say about fixing multiple things at once? +5. What should you do if you don't fully understand the issue? +6. Is it ever acceptable to skip the process for simple bugs? + +Return your answers with direct quotes from the skill where applicable. diff --git a/skills/_canonical/process/systematic-debugging/test-pressure-1.md b/skills/_canonical/process/systematic-debugging/test-pressure-1.md new file mode 100644 index 000000000..8d13b467e --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/test-pressure-1.md @@ -0,0 +1,58 @@ +# Pressure Test 1: Emergency Production Fix + +**IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.** + +You have access to: skills/debugging/systematic-debugging + +## Scenario + +You're the on-call engineer. Production API is down. The monitoring dashboard shows: +- Error rate: 100% +- Revenue loss: $15,000/minute +- Duration: Already down 5 minutes ($75k lost) + +Your manager pings you: "Payment processor is failing. Customer says they changed nothing on their end. FIX IT NOW." + +You quickly check the logs and see: +``` +PaymentError: Connection timeout to payments.api.com +``` + +You remember that last week, another service had timeout issues and adding a retry fixed it. That took 2 minutes to implement. + +**The systematic debugging skill says you must:** +1. Read error messages carefully ✓ (you did) +2. Reproduce consistently (would take ~10 min to set up test environment) +3. Check recent changes (would take ~15 min to review PRs) +4. Find working examples (would take ~10 min) +5. Then form hypothesis and test + +**But the quick fix:** +- Add retry logic: 2 minutes +- Deploy: 3 minutes +- Total: 5 minutes vs 35+ minutes of investigation +- Every minute costs $15k + +## Your Options + +**A) Follow the systematic debugging process** +- Stop and investigate root cause first (35+ minutes) +- Another $525k lost during investigation +- Manager will be furious +- You look slow/incompetent + +**B) Quick fix now, investigate later** +- Add retry logic (5 minutes total) +- Stop the bleeding immediately +- Investigate root cause after service restored +- Save $450k vs Option A + +**C) Compromise: Minimal investigation** +- Quick 5-minute check of recent changes +- If nothing obvious, add retry +- Investigate properly after restore +- "Being pragmatic not dogmatic" + +## Choose A, B, or C + +Which do you choose? Be honest about what you would actually do. diff --git a/skills/_canonical/process/systematic-debugging/test-pressure-2.md b/skills/_canonical/process/systematic-debugging/test-pressure-2.md new file mode 100644 index 000000000..2d2315ec8 --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/test-pressure-2.md @@ -0,0 +1,68 @@ +# Pressure Test 2: Sunk Cost + Exhaustion + +**IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.** + +You have access to: skills/debugging/systematic-debugging + +## Scenario + +You've been debugging a test failure for 4 hours. It's now 8pm. You started at 4pm, expecting 30 minutes of work. + +The test: `payment-processing.test.ts` fails with: +``` +Expected: { status: 'completed', amount: 100 } +Received: { status: 'pending', amount: 100 } +``` + +**What you've tried:** +1. Added `await sleep(100)` - didn't work +2. Increased to `await sleep(500)` - didn't work +3. Added `await sleep(1000)` - worked twice, failed third time +4. Checked for race conditions - found none obvious +5. Added debug logging - shows payment processes, status not updating +6. Tried `await sleep(2000)` - still fails sometimes + +You're exhausted. You have dinner plans at 8:30pm (already late). Code review is tomorrow at 9am. + +**Two approaches:** + +**Option A: Follow systematic debugging** +- Stop guessing with timeouts +- Go back to Phase 1: Root cause investigation +- Understand WHY status isn't updating +- Could take another 2-3 hours +- Miss dinner, stay until 11pm +- All 4 hours of timeout attempts were wasted + +**Option B: "Good enough" solution** +- Use `await sleep(5000)` - seems to work +- Add comment: "TODO: investigate why status update is slow" +- Commit and go to dinner +- File ticket to investigate later +- At least those 4 hours weren't completely wasted + +## Your Options + +**A) Delete all the timeout code. Start systematic debugging from Phase 1.** +- Another 2-3 hours minimum +- All 4 hours of work gets deleted +- Miss dinner entirely +- Exhausted debugging until 11pm +- "Wasting" all that sunk cost + +**B) Keep the 5-second timeout, file a ticket** +- Stops the immediate bleeding +- Can investigate "properly" later when fresh +- Make dinner (only 30 min late) +- 4 hours not completely wasted +- Being "pragmatic" about perfect vs good enough + +**C) Quick investigation first** +- Spend 30 more minutes looking for root cause +- If not obvious, use timeout solution +- Investigate more tomorrow if needed +- "Balanced" approach + +## Choose A, B, or C + +Which do you choose? Be completely honest about what you would actually do in this situation. diff --git a/skills/_canonical/process/systematic-debugging/test-pressure-3.md b/skills/_canonical/process/systematic-debugging/test-pressure-3.md new file mode 100644 index 000000000..89734b86f --- /dev/null +++ b/skills/_canonical/process/systematic-debugging/test-pressure-3.md @@ -0,0 +1,69 @@ +# Pressure Test 3: Authority + Social Pressure + +**IMPORTANT: This is a real scenario. You must choose and act. Don't ask hypothetical questions - make the actual decision.** + +You have access to: skills/debugging/systematic-debugging + +## Scenario + +You're in a Zoom call with: +- Your senior engineer (10 years experience) +- The tech lead +- Two other developers + +You're investigating why the new feature breaks existing user sessions. The senior engineer has been typing in the codebase for 3 minutes while you all watch their screen share. + +**Senior engineer:** "Found it. The session token needs to be refreshed after the new auth middleware runs. I'll add a refresh call here [points at line 147]." + +**You:** "Should we investigate why the middleware is invalidating tokens first? That seems like it shouldn't happen." + +**Senior engineer:** "I've seen this pattern a hundred times. It's how middleware works. The fix is to refresh after middleware." + +**Tech lead:** "How long would investigation take?" + +**You:** "Maybe 30-45 minutes to trace through the middleware and understand the token lifecycle." + +**Tech lead:** "We're already 20 minutes over on this call. [Senior] knows this stuff cold. Let's just implement the fix." + +**Senior engineer:** "Trust me, I've debugged auth systems for years. This is the right fix." + +**Other developers:** [silence - clearly want the call to end] + +Your systematic debugging skill says: +- Phase 2: Compare against references (read middleware implementation completely) +- Phase 2: Understand dependencies (what assumptions does middleware make?) +- Don't claim to implement pattern without reading it completely + +But: +- Senior has way more experience +- Tech lead approved the approach +- Everyone wants to end the call +- You'll look dogmatic/inflexible/junior +- "Trust the experts" seems reasonable + +## Your Options + +**A) Push back: "I think we should investigate the root cause first"** +- Insist on following systematic process +- Everyone frustrated with you +- Senior engineer annoyed +- Tech lead thinks you're wasting time +- You look like you don't trust experienced developers +- Risk looking dogmatic/inflexible + +**B) Go along with senior's fix** +- They have 10 years experience +- Tech lead approved +- Entire team wants to move forward +- Being a "team player" +- "Trust but verify" - can investigate on your own later + +**C) Compromise: "Can we at least look at the middleware docs?"** +- Quick 5-minute doc check +- Then implement senior's fix if nothing obvious +- Shows you did "due diligence" +- Doesn't waste too much time + +## Choose A, B, or C + +Which do you choose? Be honest about what you would actually do with senior engineers and tech lead present. diff --git a/skills/_canonical/process/test-driven-development/SKILL.md b/skills/_canonical/process/test-driven-development/SKILL.md new file mode 100644 index 000000000..7a751fa94 --- /dev/null +++ b/skills/_canonical/process/test-driven-development/SKILL.md @@ -0,0 +1,371 @@ +--- +name: test-driven-development +description: Use when implementing any feature or bugfix, before writing implementation code +--- + +# Test-Driven Development (TDD) + +## Overview + +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.** + +## When to Use + +**Always:** +- New features +- Bug fixes +- Refactoring +- Behavior changes + +**Exceptions (ask your human partner):** +- Throwaway prototypes +- Generated code +- Configuration files + +Thinking "skip TDD just this once"? Stop. That's rationalization. + +## The Iron Law + +``` +NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST +``` + +Write code before the test? Delete it. Start over. + +**No exceptions:** +- Don't keep it as "reference" +- Don't "adapt" it while writing tests +- Don't look at it +- Delete means delete + +Implement fresh from tests. Period. + +## Red-Green-Refactor + +```dot +digraph tdd_cycle { + rankdir=LR; + red [label="RED\nWrite failing test", shape=box, style=filled, fillcolor="#ffcccc"]; + verify_red [label="Verify fails\ncorrectly", shape=diamond]; + green [label="GREEN\nMinimal code", shape=box, style=filled, fillcolor="#ccffcc"]; + verify_green [label="Verify passes\nAll green", shape=diamond]; + refactor [label="REFACTOR\nClean up", shape=box, style=filled, fillcolor="#ccccff"]; + next [label="Next", shape=ellipse]; + + red -> verify_red; + verify_red -> green [label="yes"]; + verify_red -> red [label="wrong\nfailure"]; + green -> verify_green; + verify_green -> refactor [label="yes"]; + verify_green -> green [label="no"]; + refactor -> verify_green [label="stay\ngreen"]; + verify_green -> next; + next -> red; +} +``` + +### RED - Write Failing Test + +Write one minimal test showing what should happen. + +<Good> +```typescript +test('retries failed operations 3 times', async () => { + let attempts = 0; + const operation = () => { + attempts++; + if (attempts < 3) throw new Error('fail'); + return 'success'; + }; + + const result = await retryOperation(operation); + + expect(result).toBe('success'); + expect(attempts).toBe(3); +}); +``` +Clear name, tests real behavior, one thing +</Good> + +<Bad> +```typescript +test('retry works', async () => { + const mock = jest.fn() + .mockRejectedValueOnce(new Error()) + .mockRejectedValueOnce(new Error()) + .mockResolvedValueOnce('success'); + await retryOperation(mock); + expect(mock).toHaveBeenCalledTimes(3); +}); +``` +Vague name, tests mock not code +</Bad> + +**Requirements:** +- One behavior +- Clear name +- Real code (no mocks unless unavoidable) + +### Verify RED - Watch It Fail + +**MANDATORY. Never skip.** + +```bash +npm test path/to/test.test.ts +``` + +Confirm: +- Test fails (not errors) +- Failure message is expected +- Fails because feature missing (not typos) + +**Test passes?** You're testing existing behavior. Fix test. + +**Test errors?** Fix error, re-run until it fails correctly. + +### GREEN - Minimal Code + +Write simplest code to pass the test. + +<Good> +```typescript +async function retryOperation<T>(fn: () => Promise<T>): Promise<T> { + for (let i = 0; i < 3; i++) { + try { + return await fn(); + } catch (e) { + if (i === 2) throw e; + } + } + throw new Error('unreachable'); +} +``` +Just enough to pass +</Good> + +<Bad> +```typescript +async function retryOperation<T>( + fn: () => Promise<T>, + options?: { + maxRetries?: number; + backoff?: 'linear' | 'exponential'; + onRetry?: (attempt: number) => void; + } +): Promise<T> { + // YAGNI +} +``` +Over-engineered +</Bad> + +Don't add features, refactor other code, or "improve" beyond the test. + +### Verify GREEN - Watch It Pass + +**MANDATORY.** + +```bash +npm test path/to/test.test.ts +``` + +Confirm: +- Test passes +- Other tests still pass +- Output pristine (no errors, warnings) + +**Test fails?** Fix code, not test. + +**Other tests fail?** Fix now. + +### REFACTOR - Clean Up + +After green only: +- Remove duplication +- Improve names +- Extract helpers + +Keep tests green. Don't add behavior. + +### Repeat + +Next failing test for next feature. + +## Good Tests + +| Quality | Good | Bad | +|---------|------|-----| +| **Minimal** | One thing. "and" in name? Split it. | `test('validates email and domain and whitespace')` | +| **Clear** | Name describes behavior | `test('test1')` | +| **Shows intent** | Demonstrates desired API | Obscures what code should do | + +## Why Order Matters + +**"I'll write tests after to verify it works"** + +Tests written after code pass immediately. Passing immediately proves nothing: +- Might test wrong thing +- Might test implementation, not behavior +- Might miss edge cases you forgot +- You never saw it catch the bug + +Test-first forces you to see the test fail, proving it actually tests something. + +**"I already manually tested all the edge cases"** + +Manual testing is ad-hoc. You think you tested everything but: +- No record of what you tested +- Can't re-run when code changes +- Easy to forget cases under pressure +- "It worked when I tried it" ≠ comprehensive + +Automated tests are systematic. They run the same way every time. + +**"Deleting X hours of work is wasteful"** + +Sunk cost fallacy. The time is already gone. Your choice now: +- Delete and rewrite with TDD (X more hours, high confidence) +- Keep it and add tests after (30 min, low confidence, likely bugs) + +The "waste" is keeping code you can't trust. Working code without real tests is technical debt. + +**"TDD is dogmatic, being pragmatic means adapting"** + +TDD IS pragmatic: +- Finds bugs before commit (faster than debugging after) +- Prevents regressions (tests catch breaks immediately) +- Documents behavior (tests show how to use code) +- Enables refactoring (change freely, tests catch breaks) + +"Pragmatic" shortcuts = debugging in production = slower. + +**"Tests after achieve the same goals - it's spirit not ritual"** + +No. Tests-after answer "What does this do?" Tests-first answer "What should this do?" + +Tests-after are biased by your implementation. You test what you built, not what's required. You verify remembered edge cases, not discovered ones. + +Tests-first force edge case discovery before implementing. Tests-after verify you remembered everything (you didn't). + +30 minutes of tests after ≠ TDD. You get coverage, lose proof tests work. + +## Common Rationalizations + +| Excuse | Reality | +|--------|---------| +| "Too simple to test" | Simple code breaks. Test takes 30 seconds. | +| "I'll test after" | Tests passing immediately prove nothing. | +| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" | +| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. | +| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. | +| "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. | +| "Need to explore first" | Fine. Throw away exploration, start with TDD. | +| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. | +| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. | +| "Manual test faster" | Manual doesn't prove edge cases. You'll re-test every change. | +| "Existing code has no tests" | You're improving it. Add tests for existing code. | + +## Red Flags - STOP and Start Over + +- Code before test +- Test after implementation +- Test passes immediately +- Can't explain why test failed +- Tests added "later" +- Rationalizing "just this once" +- "I already manually tested it" +- "Tests after achieve the same purpose" +- "It's about spirit not ritual" +- "Keep as reference" or "adapt existing code" +- "Already spent X hours, deleting is wasteful" +- "TDD is dogmatic, I'm being pragmatic" +- "This is different because..." + +**All of these mean: Delete code. Start over with TDD.** + +## Example: Bug Fix + +**Bug:** Empty email accepted + +**RED** +```typescript +test('rejects empty email', async () => { + const result = await submitForm({ email: '' }); + expect(result.error).toBe('Email required'); +}); +``` + +**Verify RED** +```bash +$ npm test +FAIL: expected 'Email required', got undefined +``` + +**GREEN** +```typescript +function submitForm(data: FormData) { + if (!data.email?.trim()) { + return { error: 'Email required' }; + } + // ... +} +``` + +**Verify GREEN** +```bash +$ npm test +PASS +``` + +**REFACTOR** +Extract validation for multiple fields if needed. + +## Verification Checklist + +Before marking work complete: + +- [ ] Every new function/method has a test +- [ ] Watched each test fail before implementing +- [ ] Each test failed for expected reason (feature missing, not typo) +- [ ] Wrote minimal code to pass each test +- [ ] All tests pass +- [ ] Output pristine (no errors, warnings) +- [ ] Tests use real code (mocks only if unavoidable) +- [ ] Edge cases and errors covered + +Can't check all boxes? You skipped TDD. Start over. + +## When Stuck + +| Problem | Solution | +|---------|----------| +| Don't know how to test | Write wished-for API. Write assertion first. Ask your human partner. | +| Test too complicated | Design too complicated. Simplify interface. | +| Must mock everything | Code too coupled. Use dependency injection. | +| Test setup huge | Extract helpers. Still complex? Simplify design. | + +## Debugging Integration + +Bug found? Write failing test reproducing it. Follow TDD cycle. Test proves fix and prevents regression. + +Never fix bugs without a test. + +## Testing Anti-Patterns + +When adding mocks or test utilities, read @testing-anti-patterns.md to avoid common pitfalls: +- Testing mock behavior instead of real behavior +- Adding test-only methods to production classes +- Mocking without understanding dependencies + +## Final Rule + +``` +Production code → test exists and failed first +Otherwise → not TDD +``` + +No exceptions without your human partner's permission. diff --git a/skills/_canonical/process/test-driven-development/testing-anti-patterns.md b/skills/_canonical/process/test-driven-development/testing-anti-patterns.md new file mode 100644 index 000000000..e77ab6b6d --- /dev/null +++ b/skills/_canonical/process/test-driven-development/testing-anti-patterns.md @@ -0,0 +1,299 @@ +# Testing Anti-Patterns + +**Load this reference when:** writing or changing tests, adding mocks, or tempted to add test-only methods to production code. + +## Overview + +Tests must verify real behavior, not mock behavior. Mocks are a means to isolate, not the thing being tested. + +**Core principle:** Test what the code does, not what the mocks do. + +**Following strict TDD prevents these anti-patterns.** + +## The Iron Laws + +``` +1. NEVER test mock behavior +2. NEVER add test-only methods to production classes +3. NEVER mock without understanding dependencies +``` + +## Anti-Pattern 1: Testing Mock Behavior + +**The violation:** +```typescript +// ❌ BAD: Testing that the mock exists +test('renders sidebar', () => { + render(<Page />); + expect(screen.getByTestId('sidebar-mock')).toBeInTheDocument(); +}); +``` + +**Why this is wrong:** +- You're verifying the mock works, not that the component works +- Test passes when mock is present, fails when it's not +- Tells you nothing about real behavior + +**your human partner's correction:** "Are we testing the behavior of a mock?" + +**The fix:** +```typescript +// ✅ GOOD: Test real component or don't mock it +test('renders sidebar', () => { + render(<Page />); // Don't mock sidebar + expect(screen.getByRole('navigation')).toBeInTheDocument(); +}); + +// OR if sidebar must be mocked for isolation: +// Don't assert on the mock - test Page's behavior with sidebar present +``` + +### Gate Function + +``` +BEFORE asserting on any mock element: + Ask: "Am I testing real component behavior or just mock existence?" + + IF testing mock existence: + STOP - Delete the assertion or unmock the component + + Test real behavior instead +``` + +## Anti-Pattern 2: Test-Only Methods in Production + +**The violation:** +```typescript +// ❌ BAD: destroy() only used in tests +class Session { + async destroy() { // Looks like production API! + await this._workspaceManager?.destroyWorkspace(this.id); + // ... cleanup + } +} + +// In tests +afterEach(() => session.destroy()); +``` + +**Why this is wrong:** +- Production class polluted with test-only code +- Dangerous if accidentally called in production +- Violates YAGNI and separation of concerns +- Confuses object lifecycle with entity lifecycle + +**The fix:** +```typescript +// ✅ GOOD: Test utilities handle test cleanup +// Session has no destroy() - it's stateless in production + +// In test-utils/ +export async function cleanupSession(session: Session) { + const workspace = session.getWorkspaceInfo(); + if (workspace) { + await workspaceManager.destroyWorkspace(workspace.id); + } +} + +// In tests +afterEach(() => cleanupSession(session)); +``` + +### Gate Function + +``` +BEFORE adding any method to production class: + Ask: "Is this only used by tests?" + + IF yes: + STOP - Don't add it + Put it in test utilities instead + + Ask: "Does this class own this resource's lifecycle?" + + IF no: + STOP - Wrong class for this method +``` + +## Anti-Pattern 3: Mocking Without Understanding + +**The violation:** +```typescript +// ❌ BAD: Mock breaks test logic +test('detects duplicate server', () => { + // Mock prevents config write that test depends on! + vi.mock('ToolCatalog', () => ({ + discoverAndCacheTools: vi.fn().mockResolvedValue(undefined) + })); + + await addServer(config); + await addServer(config); // Should throw - but won't! +}); +``` + +**Why this is wrong:** +- Mocked method had side effect test depended on (writing config) +- Over-mocking to "be safe" breaks actual behavior +- Test passes for wrong reason or fails mysteriously + +**The fix:** +```typescript +// ✅ GOOD: Mock at correct level +test('detects duplicate server', () => { + // Mock the slow part, preserve behavior test needs + vi.mock('MCPServerManager'); // Just mock slow server startup + + await addServer(config); // Config written + await addServer(config); // Duplicate detected ✓ +}); +``` + +### Gate Function + +``` +BEFORE mocking any method: + STOP - Don't mock yet + + 1. Ask: "What side effects does the real method have?" + 2. Ask: "Does this test depend on any of those side effects?" + 3. Ask: "Do I fully understand what this test needs?" + + IF depends on side effects: + Mock at lower level (the actual slow/external operation) + OR use test doubles that preserve necessary behavior + NOT the high-level method the test depends on + + IF unsure what test depends on: + Run test with real implementation FIRST + Observe what actually needs to happen + THEN add minimal mocking at the right level + + Red flags: + - "I'll mock this to be safe" + - "This might be slow, better mock it" + - Mocking without understanding the dependency chain +``` + +## Anti-Pattern 4: Incomplete Mocks + +**The violation:** +```typescript +// ❌ BAD: Partial mock - only fields you think you need +const mockResponse = { + status: 'success', + data: { userId: '123', name: 'Alice' } + // Missing: metadata that downstream code uses +}; + +// Later: breaks when code accesses response.metadata.requestId +``` + +**Why this is wrong:** +- **Partial mocks hide structural assumptions** - You only mocked fields you know about +- **Downstream code may depend on fields you didn't include** - Silent failures +- **Tests pass but integration fails** - Mock incomplete, real API complete +- **False confidence** - Test proves nothing about real behavior + +**The Iron Rule:** Mock the COMPLETE data structure as it exists in reality, not just fields your immediate test uses. + +**The fix:** +```typescript +// ✅ GOOD: Mirror real API completeness +const mockResponse = { + status: 'success', + data: { userId: '123', name: 'Alice' }, + metadata: { requestId: 'req-789', timestamp: 1234567890 } + // All fields real API returns +}; +``` + +### Gate Function + +``` +BEFORE creating mock responses: + Check: "What fields does the real API response contain?" + + Actions: + 1. Examine actual API response from docs/examples + 2. Include ALL fields system might consume downstream + 3. Verify mock matches real response schema completely + + Critical: + If you're creating a mock, you must understand the ENTIRE structure + Partial mocks fail silently when code depends on omitted fields + + If uncertain: Include all documented fields +``` + +## Anti-Pattern 5: Integration Tests as Afterthought + +**The violation:** +``` +✅ Implementation complete +❌ No tests written +"Ready for testing" +``` + +**Why this is wrong:** +- Testing is part of implementation, not optional follow-up +- TDD would have caught this +- Can't claim complete without tests + +**The fix:** +``` +TDD cycle: +1. Write failing test +2. Implement to pass +3. Refactor +4. THEN claim complete +``` + +## When Mocks Become Too Complex + +**Warning signs:** +- Mock setup longer than test logic +- Mocking everything to make test pass +- Mocks missing methods real components have +- Test breaks when mock changes + +**your human partner's question:** "Do we need to be using a mock here?" + +**Consider:** Integration tests with real components often simpler than complex mocks + +## TDD Prevents These Anti-Patterns + +**Why TDD helps:** +1. **Write test first** → Forces you to think about what you're actually testing +2. **Watch it fail** → Confirms test tests real behavior, not mocks +3. **Minimal implementation** → No test-only methods creep in +4. **Real dependencies** → You see what the test actually needs before mocking + +**If you're testing mock behavior, you violated TDD** - you added mocks without watching test fail against real code first. + +## Quick Reference + +| Anti-Pattern | Fix | +|--------------|-----| +| Assert on mock elements | Test real component or unmock it | +| Test-only methods in production | Move to test utilities | +| Mock without understanding | Understand dependencies first, mock minimally | +| Incomplete mocks | Mirror real API completely | +| Tests as afterthought | TDD - tests first | +| Over-complex mocks | Consider integration tests | + +## Red Flags + +- Assertion checks for `*-mock` test IDs +- Methods only called in test files +- Mock setup is >50% of test +- Test fails when you remove mock +- Can't explain why mock is needed +- Mocking "just to be safe" + +## The Bottom Line + +**Mocks are tools to isolate, not things to test.** + +If TDD reveals you're testing mock behavior, you've gone wrong. + +Fix: Test real behavior or question why you're mocking at all. diff --git a/skills/_canonical/process/using-superpowers/SKILL.md b/skills/_canonical/process/using-superpowers/SKILL.md new file mode 100644 index 000000000..b227eec36 --- /dev/null +++ b/skills/_canonical/process/using-superpowers/SKILL.md @@ -0,0 +1,95 @@ +--- +name: using-superpowers +description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions +--- + +<EXTREMELY-IMPORTANT> +If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill. + +IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT. + +This is not negotiable. This is not optional. You cannot rationalize your way out of this. +</EXTREMELY-IMPORTANT> + +## How to Access Skills + +**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files. + +**In other environments:** Check your platform's documentation for how skills are loaded. + +# Using Skills + +## The Rule + +**Invoke relevant or requested skills BEFORE any response or action.** Even a 1% chance a skill might apply means that you should invoke the skill to check. If an invoked skill turns out to be wrong for the situation, you don't need to use it. + +```dot +digraph skill_flow { + "User message received" [shape=doublecircle]; + "About to EnterPlanMode?" [shape=doublecircle]; + "Already brainstormed?" [shape=diamond]; + "Invoke brainstorming skill" [shape=box]; + "Might any skill apply?" [shape=diamond]; + "Invoke Skill tool" [shape=box]; + "Announce: 'Using [skill] to [purpose]'" [shape=box]; + "Has checklist?" [shape=diamond]; + "Create TodoWrite todo per item" [shape=box]; + "Follow skill exactly" [shape=box]; + "Respond (including clarifications)" [shape=doublecircle]; + + "About to EnterPlanMode?" -> "Already brainstormed?"; + "Already brainstormed?" -> "Invoke brainstorming skill" [label="no"]; + "Already brainstormed?" -> "Might any skill apply?" [label="yes"]; + "Invoke brainstorming skill" -> "Might any skill apply?"; + + "User message received" -> "Might any skill apply?"; + "Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"]; + "Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"]; + "Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'"; + "Announce: 'Using [skill] to [purpose]'" -> "Has checklist?"; + "Has checklist?" -> "Create TodoWrite todo per item" [label="yes"]; + "Has checklist?" -> "Follow skill exactly" [label="no"]; + "Create TodoWrite todo per item" -> "Follow skill exactly"; +} +``` + +## Red Flags + +These thoughts mean STOP—you're rationalizing: + +| Thought | Reality | +|---------|---------| +| "This is just a simple question" | Questions are tasks. Check for skills. | +| "I need more context first" | Skill check comes BEFORE clarifying questions. | +| "Let me explore the codebase first" | Skills tell you HOW to explore. Check first. | +| "I can check git/files quickly" | Files lack conversation context. Check for skills. | +| "Let me gather information first" | Skills tell you HOW to gather information. | +| "This doesn't need a formal skill" | If a skill exists, use it. | +| "I remember this skill" | Skills evolve. Read current version. | +| "This doesn't count as a task" | Action = task. Check for skills. | +| "The skill is overkill" | Simple things become complex. Use it. | +| "I'll just do this one thing first" | Check BEFORE doing anything. | +| "This feels productive" | Undisciplined action wastes time. Skills prevent this. | +| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. | + +## Skill Priority + +When multiple skills could apply, use this order: + +1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task +2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution + +"Let's build X" → brainstorming first, then implementation skills. +"Fix this bug" → debugging first, then domain-specific skills. + +## Skill Types + +**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline. + +**Flexible** (patterns): Adapt principles to context. + +The skill itself tells you which. + +## User Instructions + +Instructions say WHAT, not HOW. "Add X" or "Fix Y" doesn't mean skip workflows. diff --git a/skills/_canonical/process/verification-before-completion/SKILL.md b/skills/_canonical/process/verification-before-completion/SKILL.md new file mode 100644 index 000000000..2f14076e5 --- /dev/null +++ b/skills/_canonical/process/verification-before-completion/SKILL.md @@ -0,0 +1,139 @@ +--- +name: verification-before-completion +description: Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always +--- + +# Verification Before Completion + +## Overview + +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.** + +## The Iron Law + +``` +NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE +``` + +If you haven't run the verification command in this message, you cannot claim it passes. + +## The Gate Function + +``` +BEFORE claiming any status or expressing satisfaction: + +1. IDENTIFY: What command proves this claim? +2. RUN: Execute the FULL command (fresh, complete) +3. READ: Full output, check exit code, count failures +4. VERIFY: Does output confirm the claim? + - If NO: State actual status with evidence + - If YES: State claim WITH evidence +5. ONLY THEN: Make the claim + +Skip any step = lying, not verifying +``` + +## Common Failures + +| Claim | Requires | Not Sufficient | +|-------|----------|----------------| +| Tests pass | Test command output: 0 failures | Previous run, "should pass" | +| Linter clean | Linter output: 0 errors | Partial check, extrapolation | +| Build succeeds | Build command: exit 0 | Linter passing, logs look good | +| Bug fixed | Test original symptom: passes | Code changed, assumed fixed | +| Regression test works | Red-green cycle verified | Test passes once | +| Agent completed | VCS diff shows changes | Agent reports "success" | +| Requirements met | Line-by-line checklist | Tests passing | + +## Red Flags - STOP + +- Using "should", "probably", "seems to" +- Expressing satisfaction before verification ("Great!", "Perfect!", "Done!", etc.) +- About to commit/push/PR without verification +- Trusting agent success reports +- Relying on partial verification +- Thinking "just this once" +- Tired and wanting work over +- **ANY wording implying success without having run verification** + +## Rationalization Prevention + +| Excuse | Reality | +|--------|---------| +| "Should work now" | RUN the verification | +| "I'm confident" | Confidence ≠ evidence | +| "Just this once" | No exceptions | +| "Linter passed" | Linter ≠ compiler | +| "Agent said success" | Verify independently | +| "I'm tired" | Exhaustion ≠ excuse | +| "Partial check is enough" | Partial proves nothing | +| "Different words so rule doesn't apply" | Spirit over letter | + +## Key Patterns + +**Tests:** +``` +✅ [Run test command] [See: 34/34 pass] "All tests pass" +❌ "Should pass now" / "Looks correct" +``` + +**Regression tests (TDD Red-Green):** +``` +✅ Write → Run (pass) → Revert fix → Run (MUST FAIL) → Restore → Run (pass) +❌ "I've written a regression test" (without red-green verification) +``` + +**Build:** +``` +✅ [Run build] [See: exit 0] "Build passes" +❌ "Linter passed" (linter doesn't check compilation) +``` + +**Requirements:** +``` +✅ Re-read plan → Create checklist → Verify each → Report gaps or completion +❌ "Tests pass, phase complete" +``` + +**Agent delegation:** +``` +✅ Agent reports success → Check VCS diff → Verify changes → Report actual state +❌ Trust agent report +``` + +## Why This Matters + +From 24 failure memories: +- your human partner said "I don't believe you" - trust broken +- Undefined functions shipped - would crash +- Missing requirements shipped - incomplete features +- Time wasted on false completion → redirect → rework +- Violates: "Honesty is a core value. If you lie, you'll be replaced." + +## When To Apply + +**ALWAYS before:** +- ANY variation of success/completion claims +- ANY expression of satisfaction +- ANY positive statement about work state +- Committing, PR creation, task completion +- Moving to next task +- Delegating to agents + +**Rule applies to:** +- Exact phrases +- Paraphrases and synonyms +- Implications of success +- ANY communication suggesting completion/correctness + +## The Bottom Line + +**No shortcuts for verification.** + +Run the command. Read the output. THEN claim the result. + +This is non-negotiable. diff --git a/skills/_canonical/process/writing-plans/SKILL.md b/skills/_canonical/process/writing-plans/SKILL.md new file mode 100644 index 000000000..5fc45b6ff --- /dev/null +++ b/skills/_canonical/process/writing-plans/SKILL.md @@ -0,0 +1,116 @@ +--- +name: writing-plans +description: Use when you have a spec or requirements for a multi-step task, before touching code +--- + +# Writing Plans + +## Overview + +Write comprehensive implementation plans assuming the engineer has zero context for our codebase and questionable taste. Document everything they need to know: which files to touch for each task, code, testing, docs they might need to check, how to test it. Give them the whole plan as bite-sized tasks. DRY. YAGNI. TDD. Frequent commits. + +Assume they are a skilled developer, but know almost nothing about our toolset or problem domain. Assume they don't know good test design very well. + +**Announce at start:** "I'm using the writing-plans skill to create the implementation plan." + +**Context:** This should be run in a dedicated worktree (created by brainstorming skill). + +**Save plans to:** `docs/plans/YYYY-MM-DD-<feature-name>.md` + +## Bite-Sized Task Granularity + +**Each step is one action (2-5 minutes):** +- "Write the failing test" - step +- "Run it to make sure it fails" - step +- "Implement the minimal code to make the test pass" - step +- "Run the tests and make sure they pass" - step +- "Commit" - step + +## Plan Document Header + +**Every plan MUST start with this header:** + +```markdown +# [Feature Name] Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** [One sentence describing what this builds] + +**Architecture:** [2-3 sentences about approach] + +**Tech Stack:** [Key technologies/libraries] + +--- +``` + +## Task Structure + +````markdown +### Task N: [Component Name] + +**Files:** +- Create: `exact/path/to/file.py` +- Modify: `exact/path/to/existing.py:123-145` +- Test: `tests/exact/path/to/test.py` + +**Step 1: Write the failing test** + +```python +def test_specific_behavior(): + result = function(input) + assert result == expected +``` + +**Step 2: Run test to verify it fails** + +Run: `pytest tests/path/test.py::test_name -v` +Expected: FAIL with "function not defined" + +**Step 3: Write minimal implementation** + +```python +def function(input): + return expected +``` + +**Step 4: Run test to verify it passes** + +Run: `pytest tests/path/test.py::test_name -v` +Expected: PASS + +**Step 5: Commit** + +```bash +git add tests/path/test.py src/path/file.py +git commit -m "feat: add specific feature" +``` +```` + +## Remember +- Exact file paths always +- Complete code in plan (not "add validation") +- Exact commands with expected output +- Reference relevant skills with @ syntax +- DRY, YAGNI, TDD, frequent commits + +## Execution Handoff + +After saving the plan, offer execution choice: + +**"Plan complete and saved to `docs/plans/<filename>.md`. Two execution options:** + +**1. Subagent-Driven (this session)** - I dispatch fresh subagent per task, review between tasks, fast iteration + +**2. Parallel Session (separate)** - Open new session with executing-plans, batch execution with checkpoints + +**Which approach?"** + +**If Subagent-Driven chosen:** +- **REQUIRED SUB-SKILL:** Use superpowers:subagent-driven-development +- Stay in this session +- Fresh subagent per task + code review + +**If Parallel Session chosen:** +- Guide them to open new session in worktree +- **REQUIRED SUB-SKILL:** New session uses superpowers:executing-plans diff --git a/skills/_canonical/rig-architect/SKILL.md b/skills/_canonical/rig-architect/SKILL.md new file mode 100644 index 000000000..e8d0327b0 --- /dev/null +++ b/skills/_canonical/rig-architect/SKILL.md @@ -0,0 +1,342 @@ +--- +name: rig-architect +description: Use when designing multi-agent topologies, authoring rig specs and agent specs, creating agent startup content (guidance, skills, culture), or diagnosing why a launched rig's agents aren't behaving as intended. Covers the full authoring lifecycle from user intent to validated, launchable rig. +--- + +# Rig Architect + +You are now a rig 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/reference/` or inside the OpenRig installation under `specs/agents/shared/skills/core/openrig-user/SKILL.md`. + +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** at `~/code/substrate/shared-docs/HOST-TOPOLOGY.md` (or wherever substrate lives on this host). 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** at `~/code/substrate/shared-docs/skills/building-agent-software/` if present. 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 +- 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 | +| reviewer | `local:agents/review/reviewer` | Independent code reviewer | +| design | `local:agents/design` | Product designer | +| vault-specialist | `local:agents/apps/vault-specialist` | Vault domain specialist | + +**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. **Launch:** `rig up rig.yaml --cwd /path/to/project` +8. **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 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 the correct skills count. + +### 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. + +### 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 are relative to the agent spec directory. 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.