Teardown
Safely delete orchestrator runtime artifacts (runs directory + worktrees) after archiving
them to ~/catalyst/archives/{orchId}/ and recording them in the SQLite index. The goal: once
an orchestrator is finished, its artifacts survive even when worktrees and runtime directories
are reaped.
When to run
- After a completed orchestrator, once
orchestratePhase 7 has run the archive sweep. The sweep is automatic; teardown is explicit — the user invokes it when they no longer need the live worktree and runs directory. - Manually:
claude /catalyst-dev:teardown <orchId>to clean up a finished orchestrator. - During disk cleanup: teardown refuses to delete unless the archive exists, so running it against an un-archived orchestrator is safe (it will archive first, then delete).
Preconditions
An orchestrator is teardown-safe when ALL of these are true:
~/catalyst/runs/{orchId}/state.jsonexists and reportsstatusin{done, complete, failed}.- The archive sweep has succeeded:
~/catalyst/archives/{orchId}/metadata.jsonexists and the SQLite row for{orchId}is present inorchestrators. - No worker signal file has
status: "in_progress"or analivePID.
Use --force to bypass the preconditions (you own the consequences).
Procedure
-
Arguments
/catalyst-dev:teardown <orchId> [--force] [--dry-run]<orchId>— required. Must match/^[A-Za-z0-9._-]+$/.--force— skip safety checks.--dry-run— print what would be deleted without deleting.
-
Archive sweep (prerequisite)
Before deleting anything, run the sweep to make sure artifacts are persisted:
bun plugins/dev/scripts/orch-monitor/catalyst-archive.ts sweep "<orchId>"If the sweep exits non-zero AND
--forceis not set, abort with a message that explains what's missing. The sweep is idempotent, so re-running it is safe. -
Enumerate deletion candidates
- Runtime directory:
~/catalyst/runs/<orchId>/ - Worktrees: anything listed in
git worktree list --porcelainwhose branch name contains<orchId>.
Print the candidates.
- Runtime directory:
-
Safety gate
For each candidate, verify:
- The directory exists.
- For worktrees:
git -C <worktree> status --porcelainis clean (or--force). - For the runs dir: no
workers/*.jsonhasstatus: "in_progress"oralive: true(or--force).
-
Stop background jobs (CTL-567)
A
phase-agentsrun spawns oneclaude --bgjob per phase; a completed bg job keeps its process alive until the ~1h supervisor reaper. Before deleting the runtime directory,claude stopevery remaining job of the run:plugins/dev/scripts/phase-agent-watch-bg reap \ --orch-dir ~/catalyst/runs/<orchId> --scope all--scope allis correct here — the run is terminal, so the mid-run exemptions (failed-pending-revive, turn-cap-exhausted) no longer apply. Preferclaude stopoverclaude rm: phase agents for one ticket share a worktree, soclaude rmcould delete a live sibling's worktree. With--dry-run, pass--dry-runthrough. A missing run directory orphase-agent-watch-bgis non-fatal — skip and continue. -
Delete
git worktree remove <path>for each worktree (add--forceif step 4 flagged dirty state AND user passed--force).rm -rf ~/catalyst/runs/<orchId>/for the runs directory.
-
Verify
-
Re-run the archive listing to confirm the orchestrator is still discoverable:
bun plugins/dev/scripts/orch-monitor/catalyst-archive.ts list --orch "<orchId>" --json -
The SQLite row must still exist and
archive_pathmust still point to a real directory.
-
Output
On success, print a summary:
Teardown complete for <orchId>
archived to: ~/catalyst/archives/<orchId>/
bg jobs stopped: <N>
deleted:
runs: ~/catalyst/runs/<orchId>/
worktrees: <paths...>
On refusal (preconditions failed and no --force), print what's blocking and exit non-zero.
Related
/catalyst-legacy:orchestratePhase 7 — runs the sweep automatically when orchestration ends.bun plugins/dev/scripts/orch-monitor/catalyst-archive.ts— the archive CLI withsweep|sync|prune|list|showsubcommands.- See
docs/architecture.md§ "Artifact Persistence" for the end-to-end lifecycle.