# Dirtydishes Skills

Reusable assets for local Codex and agent workflows.

This repository is the source for agent skills, prompt templates, loop scaffolds, schemas, examples, and related operating docs.

## Layout

- `skills/` - Self-contained agent skills.
- `codex-loop-templates/` - Reusable prompt and document scaffolds.
- `catalog/skills.json` - Installable skill catalog and dependencies.
- `bin/skills.js` - `npx`-compatible installer.

## Installer

The npm package is `@dirtydishes/skills` and the Forgejo repo is `dirtydishes/skills`.

```bash
npx @dirtydishes/skills@latest list
npx @dirtydishes/skills@latest add dirtyloops
npx @dirtydishes/skills@latest add fleet-operator
npx @dirtydishes/skills@latest update dirtyloops
npx @dirtydishes/skills@latest sync
npx @dirtydishes/skills@latest doctor dirtyloops
```

With no command, the package opens an interactive picker when stdin/stdout are TTYs. Automation should use explicit commands:

```bash
npx @dirtydishes/skills@latest update dirtyloops --quiet
npx @dirtydishes/skills@latest update --all --quiet
```

The default install target is `~/.agents/skills`. Override it with `--target-dir`.

`doctor` compares every packaged file with the selected install target. Extra, missing, or changed files are reported as stale with the exact `skills update <name>` repair command; the generated install receipt is ignored because its timestamp is expected to differ.

The catalog distinguishes external tools, required skills, and recommended skills. Dirtyloops requires `bd` and `thermo-nuclear-code-quality-review`; it recommends `impeccable` for storyboard closeout.

The installer updates the installed skill package. To migrate generated artifacts already inside a project, invoke `dirtyloops update` in that project.

## Fleet Operator

`fleet-operator` documents and operates the `deltaisland`, `lavender`, `indigo`, and `lilac` fleet. Its dated service map records observed topology, while its snapshot script discovers current tailnet nodes, systemd workloads, Compose projects, containers, listeners, and Tailscale Serve routes before an agent acts.

Install or refresh it with:

```bash
npx @dirtydishes/skills@latest update fleet-operator --quiet
```

Run `skills/fleet-operator/scripts/fleet-snapshot.sh` from deltaisland or Lavender. From Lavender, the script uses the `dit` SSH alias by default.

### Update every managed skill

`sync` updates all skills packaged by `@dirtydishes/skills`, then delegates to the
upstream non-interactive updaters for other globally managed skills:

```bash
npx --yes @dirtydishes/skills@latest sync
```

This updates Dirtyloops and thermo-nuclear review from this package, skills
tracked in `~/.agents/.skill-lock.json` (including Matt Pocock's skills) through
`skills@latest`, and Impeccable through its own updater. Impeccable runs from the
home directory with `--no-hooks`, so a scheduled refresh does not modify a
project's hook manifests. Use `sync --dry-run` to print the update plan.

Run the same command on another machine directly:

```bash
ssh -o BatchMode=yes di 'npx --yes @dirtydishes/skills@latest sync'
```

For unattended updates, schedule that exact command weekly. On macOS use a
LaunchAgent; on Linux use a persistent user systemd timer. The command is safe
to launch outside a project because each upstream updater is explicitly run
against the global skill installation, and failures return a non-zero exit code
for the scheduler to record.

For local development:

```bash
node bin/skills.js list
node bin/skills.js add dirtyloops --source-dir .
node bin/skills.js doctor dirtyloops
```

## Dirtyloops 2.2

Dirtyloops is a portable implementation-loop control plane for Codex and Pi. The accepted plan, Beads state, phase contracts, review evidence, CI state, and closeout remain harness-neutral; one explicit binding selects the runtime adapter.

Earlier dirtyloops versions encoded orchestration as fixed choreography: users selected a workflow, child roles were predetermined, reasoning defaults were pinned, and large swarms were mandatory. That compensated for weaker orchestration, but it also occupied the decision space GPT-5.6 Sol now handles substantially better. It could duplicate native multi-agent behavior, force expensive reasoning onto simple missions, and preserve one topology after the phase evidence no longer justified it.

Version 2.2 treats dirtyloops as a **control plane with explicit ownership profiles**:

- accepted outcomes, constraints, Beads state, checkout ownership, launch safety, review, CI, and completion evidence stay deterministic
- `adaptive` lets the run-time orchestrator choose ownership topology
- `orchestrator-callback` keeps the control thread orchestrator-only and requires separate implementation and review owners with concrete final callbacks
- inside either profile, stage owners choose model tier, reasoning effort, evidence-driven helper missions, concurrency, and coordination from certified capabilities
- implementation and review strongly encourage useful helper agents, capped at 20 missions per stage and bounded by configured/runtime capacity
- Terra and Luna can be selected for bounded missions when their cost, speed, and capability fit better
- native multi-agent modes are valid execution adapters rather than something dirtyloops layers mandatory swarms over
- every phase gets a new orchestration brief, so the strategy can change as evidence changes

The model choice is deliberately not encoded as a permanent Sol/Terra/Luna role table. The GPT-5.6 tiers and their capabilities can evolve independently. Dirtyloops records the run-time choice and rationale while keeping user-specified model, effort, cost, or concurrency constraints authoritative.

### Planning Is Outside Dirtyloops

Dirtyloops does not replace planning.

```text
Planning
  -> investigate the repository and problem
  -> resolve consequential product and architecture decisions
  -> produce or accept a decision-complete, implementation-open PLAN.md

dirtyloops create from PLAN.md       # Codex by default
dirtyloops create pi from PLAN.md    # explicitly Pi
dirtyloops create orchestrator-callback for codex from PLAN.md
  -> validate the accepted plan
  -> compile it into Beads, phase docs, turn docs, schemas, and one run prompt
  -> stop before implementation

dirtyloops run
  -> validate the persisted harness binding and certified adapter
  -> inspect current evidence and runtime capabilities
  -> record a phase-specific orchestration brief
  -> execute adaptively until complete or blocked
```

`create` may clarify structure, but it may not invent intent. If a plan lacks outcomes, constraints, consequential decisions, independently verifiable phases, acceptance evidence, dependencies, or replanning triggers, `create` returns a validation report and sends the work back to planning before mutating Beads.

### Commands

- `dirtyloops help` - Explain the planning -> create -> run flow.
- `dirtyloops create from PLAN.md` - Validate and materialize an adaptive Codex-bound loop.
- `dirtyloops create orchestrator-callback for codex from PLAN.md` - Materialize a Codex loop whose control thread must delegate implementation and review through callbacks.
- `dirtyloops create codex from PLAN.md` - Select Codex explicitly.
- `dirtyloops create pi from PLAN.md` - Select Pi explicitly.
- `dirtyloops convert codex` / `dirtyloops convert pi` - Transactionally change an idle v2 loop's harness binding.
- `dirtyloops run` - Execute ready phases using adaptive orchestration.
- `dirtyloops run --once` - Execute and close out one phase.
- `dirtyloops update` - Conservatively migrate an existing loop to the v2 contract.
- `dirtyloops inspect` - Report state without mutation.
- `dirtyloops closeout` - Verify completion and generate the storyboard.

The omitted harness defaults to Codex; the omitted execution profile defaults to `adaptive`. Harness and execution profile are orthogonal: the harness selects the runtime adapter, while the profile selects ownership topology. Unknown create arguments fail before mutation.

Dirtyloops deliberately does not assume a default subagent limit such as 6. Each implementation and review stage may define up to 20 useful helper missions, while active concurrency is bounded by the user's configured limit, the certified runtime limit, and currently available slots. The durable roles are only orchestrator, implementation owner, and independent review owner; codebase scouts, test designers, security critics, and similar helpers are generated dynamically from evidence rather than fixed as personas.

Before `create` materializes or `run` mutates a phase, Dirtyloops audits whether the phase has one acceptance boundary, a bounded module surface, and an independently reviewable diff. Unsafe roadmap chapters return `requires-reslice`; missing boundary information returns `needs-clarification`. The audit reports actionable reasons and authored hashes but never rewrites the plan. `update` and `convert` include the same report while preserving authored phases byte-for-byte.

Generated control-plane files are installed as one deterministic generation. `create`, `update`, and `convert` stage the run prompt, binding, optional Pi policy, current schemas, resume mirror, and implementation index behind one recovery lock; `runtime/generation.json` records their hashes and adapter identity. Failure restores the prior files and Beads metadata instead of leaving a mixed generation active.

### Harness Contract

Every loop has `runtime/binding.json`, mirrored in Beads and `loop-state.md`. `run` asks the active certified adapter for a runtime manifest and fails closed if the harness, adapter contract, or required capabilities disagree. Generated loop files never branch on child-system generations, experimental labels, or product versions.

| Surface | Codex | Pi |
|---|---|---|
| Default at `create` | yes | no |
| Direct execution | yes | yes |
| Durable child session | when currently certified | vanilla `AgentSession`, parent-linked |
| Bounded delegate | when currently certified | vanilla by default |
| Optional plugin | none required | Nicobailon's `pi-subagents` only after exact RPC v1 handshake, packaged read-only evidence scouts only |
| Dynamic workflow plugin | not applicable | optional and advisory; never owns Beads or phase advancement |

Pi support ships as a Pi package extension exposing `dirtyloops_runtime` and `dirtyloops_child`. It uses vanilla Pi for the baseline. Durable implementation and review children are persistent, parent-linked Pi sessions; bounded delegates are parent-linked in-memory sessions. Both are distinct from plugin-provided subagents.

Pi can therefore run callback-style coordination: a child records a structured completion, emits it to the parent with a handle and nonce, and triggers the next parent turn. The parent acknowledges that exact pair with the owning loop's absolute `doc_root` before another launch; dropped first emissions retry with durable loop ownership from session state after loss or resume. In the `orchestrator-callback` profile this ownership topology is mandatory; in `adaptive` it remains a run-time option.

That structured callback is the normal path: coordinators do not poll status or run sleep/wait loops. `recover` and the legacy `status` alias require a certified reason, use adapter-observed activity or pending-delivery evidence, are rate-limited, and persist telemetry. Only `delivery-recovery` can force completion re-emission; it first anchors non-rewindable degradation in `runtime/activation.json`, then blocks ordinary launches until ownership is renewed. Operator-request cannot bypass that renewal boundary.

Material loop creation, refresh, or harness conversion writes `runtime/activation.json`. A fresh Pi session must match the generated runtime-closure hash and pass one ordinary vanilla child completion plus acknowledgement; reloading the source Pi session is intentionally insufficient. Codex has no injected Dirtyloops adapter closure, so its generation is immediately activation-ready, while every run still revalidates the live first-party manifest and blocks when the selected profile requires capabilities that are not currently certified.

Pi also uses this activation sidecar for safe coordinator renewal. At a boundary with no active child or pending completion, the current coordinator records the Beads phase, turn doc, PR, symbolic branch, checkout head and dirtiness, plus the recovery or context-pressure evidence. A different Pi session must pass the activation probe before work resumes. Context-pressure renewal is deliberately adaptive: Dirtyloops defines no fixed coordinator lifetime, context threshold, model, or topology.

Sol, Terra, and Luna are model choices, not harnesses or adapters. When they are available through Pi, the orchestrator may select among them per mission without baking a permanent role table into the loop.

#### Install the Pi Harness

Install Dirtyloops as a user-level Pi package:

```bash
pi install npm:@dirtydishes/skills
```

For local development, install this checkout instead:

```bash
pi install /absolute/path/to/agents
```

Vanilla Pi is sufficient, but the recommended Pi setup also installs [Nicobailon's `pi-subagents`](https://github.com/nicobailon/pi-subagents):

```bash
pi install npm:pi-subagents
```

You may also install [`pi-dynamic-workflows`](https://github.com/QuintinShaw/pi-dynamic-workflows) for its native Pi commands and tools:

```bash
pi install npm:@quintinshaw/pi-dynamic-workflows
```

That plugin has its own parent-session keyword trigger. To prevent ordinary discussion of Dirtyloops workflows from arming it, give the trigger a distinct name inside Pi:

```text
/workflows-trigger set pi-workflow
```

Use `/workflows-trigger off` instead if you want only explicit `/workflows run ...` activation.

If Pi is already running, use `/reload`, then verify the installed packages from a shell:

```bash
pi list
```

The three installation profiles have deliberately different Dirtyloops behavior:

| Installed Pi packages | Dirtyloops behavior |
|---|---|
| Dirtyloops only | Full vanilla baseline: direct execution, bounded delegates, and persistent parent-linked sessions |
| Dirtyloops + `pi-subagents` | Same baseline; the plugin is used only when explicitly requested, its RPC v1 handshake certifies async spawn/status/stop, and the mission uses the packaged `dirtyloops.scout` profile with only `read`, `grep`, `find`, and `ls` |
| Dirtyloops + `pi-dynamic-workflows` | No automatic integration today; the plugin remains available to the parent Pi session and may respond to its own commands or trigger, but Dirtyloops does not detect it, invoke it, or delegate loop ownership to it |

Dirtyloops never treats plugin presence as permission to change an existing loop's harness, adapter, or execution strategy. Vanilla Dirtyloops children load with extensions disabled. Nicobailon-backed scouts use the package's versioned event-bus RPC and machine-readable lifecycle files rather than terminal scraping or active polling. A future dynamic-workflows integration must arrive as an explicit, tested, certified adapter capability; installation alone will never enable it. Even then, Beads state, checkout ownership, phase advancement, review, CI, and closeout remain owned by Dirtyloops.

Codex remains the default only when `create` omits a harness. Pi-bound loops do not call Codex child APIs, and the shared contract never branches on Codex subagent generations such as v1 or v2. To move an existing idle loop, use `dirtyloops convert pi` at the safe boundary described below rather than rebuilding it or editing the binding by hand.

### What `create` Generates

A loop lives under `docs/implementation/<stream>/`:

- `IMPLEMENT.md` - Accepted goal, constraints, phase ledger, gates, and control-plane invariants.
- `00-roadmap.md` - Phase graph, decisions, open questions, risks, and replanning triggers.
- `NN-phase-name.md` - Decision-complete, implementation-open phase contracts.
- `loop-state.md` - Mutable compact resume sidecar; Beads remains canonical, and routine phase updates do not alter deterministic runtime generation identity.
- `turn-docs/` - One evidence record per phase.
- `prompts/run-loop.md` - One adaptive run prompt.
- `runtime/binding.json` - Explicit Codex or Pi binding and required adapter capabilities.
- `runtime/adapter.json` - Generated Pi adapter policy, present only for Pi-bound loops.
- `schemas/` - Strategy-neutral execution summaries plus optional callback contracts.
- `storyboard-post-run-mm-dd-yyyy.html` - Final closeout artifact.

Version 2 no longer generates selector, closeout-selector, implementation-swarm, worker-thread, or reviewer-thread prompts at creation time. If the run-time orchestrator delegates, it creates bounded instructions from the current phase and the certified adapter surface.

### The Orchestration Brief

Before broad work, the orchestrator records:

- phase and risk
- direct, bounded-delegate, durable-session, native-multi-agent, or hybrid strategy
- implementation owner and review independence
- delegation missions
- model and effort rationale
- required evidence and user constraints

The brief is an audit surface, not an immutable script. The orchestrator revises it when evidence changes and records why.

### Durable Invariants

Adaptive does not mean unconstrained:

- Beads owns status, ordering, dependencies, blockers, ownership, and completion.
- Accepted outcomes and constraints cannot drift silently.
- One actor owns each mutable checkout or branch at a time.
- Children that mutate or review code start in the intended repo, worktree, and symbolic branch/ref.
- Detached HEAD or wrong placement is a launch failure, not something the child repairs with `cd`.
- Completion targets, when used, bind to the concrete run-time orchestrator session before launch.
- Structured completion is callback-driven in normal operation; status, sleep, and wait polling are not coordination strategies.
- Reasoned recovery is exceptional, evidence-based, rate-limited, and durable; degraded delivery requires safe coordinator renewal.
- Review remains independent enough to challenge implementation.
- Review preserves every role required by the accepted phase. Thermonuclear reviewers use `thermo-nuclear-code-quality-review`; adversarial reviewers must not invoke or consult it.
- Phase-defined combined repairs use one shared pass count across all required reviewers. Dirtyloops stops and asks the user when the accepted limit is exhausted.
- CI reaches green, repaired-and-green, unavailable-with-evidence, or blocked-with-cause.
- Every phase has one shared turn doc covering orchestration, implementation, review, CI, repairs, PR state, Beads updates, and closeout.
- Adjacent work becomes Beads follow-ups instead of hidden scope expansion.
- `run` continues phase-by-phase unless complete, blocked, interrupted, unresolved, or explicitly `--once`.

Fragile launcher and callback behavior belongs in adapters, schemas, hooks, and validators. Prompt prose explains those invariants but is not treated as if it configured the launcher.

### Converting Harnesses

Conversion is allowed only at a safe boundary: no child owns the mutable checkout, no completion is pending, no execution strategy is active, and CI is not unresolved. Always dry-run first:

```bash
node ~/.agents/skills/dirtyloops/scripts/convert-harness.mjs \
  --doc-root docs/implementation/<stream> \
  --to pi \
  --authored-path CONTEXT.md \
  --dry-run
```

Apply removes no authored content. The helper archives the old generated binding, adapter policy, and resume mirror; writes the destination binding and Pi adapter policy atomically; updates Beads metadata; verifies protected hashes; and compensates files and Beads on failure. Re-running the same target is idempotent.

Repeat `--authored-path` for support files outside the conventional roadmap, numbered-phase, turn-doc, and storyboard paths. These explicit files are hash-protected; any undeclared ambiguous path still blocks the transaction.

### Updating Existing Loops

Run `dirtyloops update` after installing a new Dirtyloops release. For v1 loops, migration preserves an explicit `orchestrator-callback` workflow as the mandatory callback ownership profile, defaults other historical loops to `adaptive`, replaces fixed actor/reasoning/swarm metadata with evidence-driven helper policy, replaces `swarm_summary` with `execution_summary`, and consolidates workflow-specific prompts into one profile-aware run prompt. For existing v2 Pi loops, it also replaces stale or missing plugin policy with the Nicobailon RPC v1 adapter configuration.

Migration preserves authored phase intent, turn-doc history, code, branches, PRs, Beads issue state and dependencies, loop-state history, and storyboards unless wider changes are explicitly authorized. Obsolete generated prompts are removed only after confirming they contain no unique authored decisions.

`update` runs the bundled migration helper in dry-run mode first, then applies only after classification succeeds:

```bash
node ~/.agents/skills/dirtyloops/scripts/migrate-v2.mjs \
  --doc-root docs/implementation/<stream> \
  --epic <epic-id> \
  --plan-source PLAN.md \
  --authored-path CONTEXT.md \
  --dry-run

node ~/.agents/skills/dirtyloops/scripts/migrate-v2.mjs \
  --doc-root docs/implementation/<stream> \
  --epic <epic-id> \
  --plan-source PLAN.md \
  --authored-path CONTEXT.md
```

The helper archives v1 generated artifacts, rewrites the active generated contract, installs v2 schemas, refreshes the generated Pi adapter policy when the binding is Pi, hashes protected plan/history files, and writes `migration-v2-report.json`. Running it again must return `already-v2` with no actions. The dirtyloops agent then migrates Beads contract metadata separately using the commands supported by that repository's installed `bd` version.

### Examples And System Map

- `skills/dirtyloops/examples/adaptive/` - Generated v2 loop.
- `skills/dirtyloops/plan.html` - Human-readable planning, harness binding, run, conversion, review, and closeout map.

## Conventions

- Keep skill entrypoints short and route deeper behavior through references.
- Prefer repo-relative paths in generated prompts and docs.
- Treat Beads as canonical for durable implementation state.
- Keep model-sensitive execution policy adaptive and mechanical safety rules enforceable.

## Publishing

The repo is published as `dirtydishes/skills` and the npm package as `@dirtydishes/skills`.

### 2.1.3

Dirtyloops 2.1.3 hardens the lifecycle behind adaptive execution without prescribing a model or topology:

- generated updates and harness conversions install one recoverable, content-addressed contract while preserving authored plan and turn history
- existing v2 loops remain v2 when protected history names an older orchestration path, and an explicitly stopped loop is recognized as a safe conversion boundary
- execution-readiness blocks oversized implementation or review units until the user approves re-slicing, then recognizes explicit bounded Beads leaves without rewriting their shared authored phase doc
- Pi completion is durable, acknowledged, retryable, and restored after resume
- material runtime changes require a different coordinator to pass a live vanilla completion probe
- structured completion is the zero-poll normal path; reasoned recovery is exceptional, rate-limited, non-rewindable, and followed by safe coordinator renewal when delivery degrades
- vanilla durable sessions remain distinct from optional read-only `pi-subagents` scouts
