plugins/dev/skills/ticket-compound/SKILL.md
Compound-engineering capture + curation for a finished ticket — the engineering feedback loop. Harvests the Friction sections that phase agents left in their artifacts plus the git diff, writes a structured entry to the shared learnings store (thoughts/shared/learnings/), prunes/amends stale notes there autonomously, captures new domain vocabulary to thoughts/shared/CONCEPTS.md, and PROPOSES (for human approval) any ADR change. Non-blocking — runs after a ticket ships or fails, never on the critical path. Use when the user says "compound this ticket", "capture learnings", "what did we learn", or run as /catalyst-dev:ticket-compound <TICKET> [mode:headless].
npx skillsauth add coalesce-labs/catalyst ticket-compoundInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Capture what a ticket taught us into the shared store (thoughts/ + ADRs), so future agents on
any machine make better decisions. This is research-curate evolved from inventory to action.
Read reference.md (this dir) for the learnings-store schema before writing anything.
Two authority levels (hard rule):
thoughts/shared/learnings/ and
thoughts/shared/CONCEPTS.md, and prune stale notes in thoughts/shared/{research,plans}/.docs/adrs.md. Never edit an ADR directly; queue
it for the morning ritual to approve./catalyst-dev:ticket-compound <TICKET> [mode:headless]
<TICKET> — Linear key (e.g. CTL-619). If omitted, detect from the branch / CATALYST_TICKET.mode:headless — non-interactive: apply all unambiguous autonomous actions silently, mark
ambiguous learnings status: stale, never block on a prompt, end with the sentinel line. This is
what the morning ritual (and, later, the daemon) use. Default is interactive.For <TICKET>, collect:
## Friction / friction: block the phase agents left in their artifacts:
thoughts/shared/{research,plans}/*<TICKET>*.md and the worker signal files
~/catalyst/workers/<TICKET>/*.json.
thoughts/shared/friction/<TICKET>.md — the dedicated per-phase friction log (primary friction source).git log --oneline origin/main..HEAD and git diff --stat origin/main..HEAD
(or the merged SHA from phase-monitor-merge.json).linearis skill's "Reading Linear" section.~/catalyst/events/YYYY-MM.jsonl.Capture learnings from failed/abandoned tickets too — the dead-ends are high-signal ("what didn't work" is a first-class section).
Spawn via Task, all at once. Each returns text to you; you do the single write in Step 3 (avoids partial-write races):
problem_type, category (subdir), component, severity, and a filename slug. Returns the
frontmatter skeleton (validate against reference.md).rg -li "<keywords>" thoughts/shared/learnings/**/*.md, read the
frontmatter of hits, and score overlap (problem, root cause, component, files, prevention). Returns
HIGH (4–5) / MODERATE (2–3) / LOW (0–1) plus the matched paths.last_updated:),
rather than creating a near-duplicate. This is the anti-bloat rule.thoughts/shared/learnings/<category>/<slug>.md.Then validate frontmatter (fail loud on the YAML traps in reference.md):
bash "${CLAUDE_PLUGIN_ROOT:-plugins/dev}/scripts/compound/validate-learnings.sh" "<written-path>"
For the related entries the Finder surfaced, classify and act — autonomously (this is the
thoughts/ layer):
| Outcome | When | Action |
|---|---|---|
| Keep | accurate, refs valid | none |
| Update | core correct, refs/paths drifted | targeted in-place edit |
| Consolidate | 2+ heavily overlap, both correct | merge into the canonical, delete the subsumed |
| Replace | core guidance now misleading | write successor, delete old |
| Delete | implementation gone AND domain gone AND no inbound links | remove (git history preserves) |
Same five-outcome pass applies to stale thoughts/shared/{research,plans}/ notes this ticket
contradicted (the "off-track context that got us redirected"). In mode:headless, only act on
unambiguous cases; mark the rest status: stale + stale_reason.
Scan the diff + friction for Catalyst domain terms not yet in thoughts/shared/CONCEPTS.md (e.g. "reclaim",
"revive-budget", "orphan", "signal ownership"). Append concise definitions. Create the file if absent.
If a learning rises to a standing rule (something every agent must always do/avoid), do NOT edit
docs/adrs.md. Append a proposal to the approval queue:
thoughts/shared/compound/pending/<TICKET>.md
Each proposal: the target ADR (new / amend ADR-NNN / supersede ADR-NNN), the exact proposed text,
and a one-line rationale + evidence (ticket + learning path). The morning ritual surfaces these; a
human approves via briefing-followup's action-compound handler, which is the only thing that
writes docs/adrs.md.
Confirm CLAUDE.md teaches agents that the learnings store exists, its shape, and when to grep it. If
not, propose (interactive) / apply (headless) a minimal pointer — never the learnings themselves:
thoughts/shared/learnings/ — past problem→solution entries (grep by component/tags/problem_type).
Search before implementing or debugging in a known area. Curated by /catalyst-dev:ticket-compound.
✓ ticket-compound complete (headless)
ticket: CTL-619
entry: thoughts/shared/learnings/orchestrator-issues/daemon-false-dead-first-commit.md (created)
curated: 1 updated, 0 deleted ; concepts: +2 ; adr-proposals: 1 (pending approval)
ticket-compound complete
monitor-deploy (manual / morning-ritual triggered for now).compound-estimate owns estimation numbers).ticket-retro (the cross-ticket view — separate slice).development
Migrate a single-harness repo to the dual-harness layout so both Claude Code and Codex load the same instructions and skills — AGENTS.md as the portable canonical doc, a thin CLAUDE.md `@AGENTS.md` bridge, and a `.agents/skills` dir with a `.claude/skills` symlink onto it. Use when asked to migrate to dual-harness, make this repo work in both Claude and Codex, or for agent metadata cleanup.
tools
Goal-driven senior-engineer pipeline-unstick sweep (CTL-1176 rung 3). Given the stuck/failed/needs-human set (or ONE ticket handed by the recovery router), its GOAL is to get the pipeline MOVING again — not to fix one ticket's review findings (that is phase-remediate). It runs AFTER the eyes (diagnostician evidence) and the hands (deterministic unstuck-sweep seams) have already tried, and it CONSUMES their output from a recovery-pass.json brief rather than re-diagnosing or redoing their narrow work. It acts like a senior engineer with full tool access — it resolves merge conflicts, rebases, force-pushes, merges green PRs, and re-dispatches stalled phases AUTONOMOUSLY — and escalates to the operator ONLY for a genuine value judgment / something that degrades other functionality / a real cost-benefit trade-off / a serious architecture change / an ADR conflict. On escalation it AUTHORS the operator inbox row + the push notification (executive-voiced). Dispatched as a `claude --bg` job by phase-agent-dispatch via slash command, AND invocable bare by the operator as a sweep — hence `user-invocable: true`. Ships behind CATALYST_RECOVERY_PASS (off by default — no live behavior change until shadow/enforce).
tools
Diagnose and fix Catalyst setup issues. Validates tools, database, config, OTel, direnv, and thoughts. Automatically fixes what it can — creates directories, initializes the database, sets WAL mode, runs migrations. Use for new installs, upgrades, or when something isn't working.
tools
--- name: phase-triage description: Phase agent that triages a Linear ticket — expands acronyms, classifies (feature/bug/docs/refactor/chore), identifies genuine blockers (a semantic second-pass over the backlog — NOT a prose scrape; CTL-838), estimates scope, writes triage.json, and posts a triage analysis comment to Linear. Triage completion is signaled by that comment plus the local triage.json — there is no `triaged` label. Emits phase.triage.complete.<TICKET> on success and phase.triage.fai