---
name: skill-ops-retro
type: skill
description: Turn friction observed while running the operator's skills, tasks, and routines into ready-to-add canon artefacts — a new or updated skill, task, routine, convention, or agent profile the operator saves. Use this whenever running the skill-ops-retro routine, or when the operator asks to review, tidy, retro, or improve the skills/routines, asks "what could be better about how Claude is run", or pastes a transcript and asks what could be fixed or optimised. Also use it as the final step of any other skill, to capture that run's friction. Has two modes — capture (file a FRICTION note to the Pulse queue) and drain (turn the queue into ready-to-save artefacts). Proposes only for canon — never edits a SKILL.md, never applies a canon change via a ticket, never routes a canon edit to Forge; it does file the repo-lane ticket for a repo-native dependency of a drained change. Apply this rather than ad hoc tinkering, so improvements land as artefacts the operator can add.
---

# skill-ops-retro

A retro routine for the operating system itself. It turns friction — encountered while running a skill, or spotted when reviewing one — into improvements to the operating canon. It works in **two modes: capture files a `FRICTION:` note to the Pulse queue; drain turns that queue into a ready-to-save canon artefact.** It never edits canon in place — the operator is the gate (per convention-linear, detected drift or a proposed change is raised for the operator, never applied silently).

**The drain's only canon output is a ready-to-add canon artefact** — a new or updated skill, task, routine, convention, or agent profile that the operator adds in one step. Capture, by contrast, *does* file a Linear note and produces no artefact: "only output is an artefact" describes the drain's canon output, and is never a reason to skip filing in capture mode. The drain may *also* file a repo-lane delivery ticket where a drained canon change needs a matching repo edit (see step 4a) — that is the repo half, not a canon-apply ticket. Claude is canon; the claude-ops repo is a downstream mirror that ops-sync brings up to canon afterwards.

## Two modes, one purpose

The work splits into **capture** and **drain**, because the surface that *spots* friction is rarely the surface where a `.skill` can be *saved*. Filing a Linear note is the one capture action every surface can do — including Claude Code, which can write Linear but cannot save to the skills store. So friction is always captured to the Pulse queue first, and the artefact is produced later, on the drain pass, where the save button works. Centralising through the queue also fixes two failures of per-session saves: a `.skill` buried in one of many sessions is easy for the operator to miss, and concurrent autonomous sessions each saving canon would clobber one another's changes. The queue is the single point where all intake collects; the batch drain is the single point where it is consolidated and saved.

**The Pulse queue** is the friction inbox: `FRICTION:`-prefixed Backlog tickets in Apps / os.Claude carrying `agent:PUL-5E` (see convention-linear). It is capture, not application — a note records an observation; it is never a proposal to "change canon", and never routes a canon edit to Forge.

### Capture mode

Triggered as the final step of another skill, mid-run when friction is spotted, or by a headless / Claude Code / scheduled run that cannot reach the save button. **File a `FRICTION:` note to the Pulse queue** — do not attempt to produce or surface a `.skill` here.

1. **Spot.** Identify friction worth capturing: a redundant or wrong query, a dead-end, a wrong assumption, a missing convention, an ambiguous instruction, a place the wording could be tightened. A single observation is a small note, not a redesign — record what was seen, not a fix.
2. **Check for an existing ticket.** Search os.Claude Backlog for a matching `FRICTION:` ticket. If one exists, add a comment noting the recurrence with today's date instead of opening a new one (recurrence count is the signal that escalates scope at drain).
3. **File the note** in Apps / os.Claude (per convention-linear):
   - **Title** — `FRICTION:` prefix, specific not generic (names the skill/area and the friction).
   - **Observed friction** — one or two sentences: what happened, in which skill/run, and the instance count if known.
   - **Light notes** — any pointer the drain pass would want (a candidate target artefact, a suspected cause). Not a prescribed fix — drain assesses against current canon, not against this note.
   - Labels: `type:task` + `work:configuration`. Executor: **`agent:PUL-5E`** (not the Backlog default `agent:R3-LAY` — this is what keeps it out of the Relay→Forge loop). State: Backlog. Unassigned.
4. **Note it.** When embedded, a one-line note that friction was queued, so it does not bury the host skill's output. A clean run captures nothing.

### Drain mode

Triggered by the scheduled `task-pulse-retro`, or on demand ("run skill-ops-retro", "drain the queue", or a pasted transcript). **Turn the queue into ready-to-save artefacts.**

1. **Read the queue.** Query Apps / os.Claude Backlog for issues carrying agent value `PUL-5E` — the `FRICTION:` notes. Treat them as inputs alongside any session-observed friction or a pasted transcript. (Reading-safety traps in convention-linear: the agent-group filter takes the bare value `PUL-5E`; a Backlog filter also returns Refinement, so re-check each ticket's state name.) **Also re-read any previously *surfaced* PUL-5E notes** — those a prior drain parked in **Blocked**, or assigned to the Owner (step 5's third disposition) — and check whether their blocker has cleared: if it has, the note re-enters this drain as authorable; if not, leave it surfaced. A note reaches **Done** only once it is incorporated or assessed-not-warranted, never merely because it was deferred, so a warranted-but-blocked note stays visible across drains until it can actually be authored.
2. **Group by target, then assess against current canon.** Group all queued notes (and any session-observed friction or pasted transcript) by the artefact they target, so each target is assessed and changed exactly once across the batch. For each target, read the **live** SKILL.md — never the fix suggested in the note, never the claude-ops mirror — and decide what the canon actually warrants. That may be nothing.
3. **Classify.** Identify **which canon artefact the fix lands in** — a skill, convention, agent or operator profile, task, or routine — and whether it is **new** or an **edit**. That decides how it is handed over (step 4).
4. **Produce one consolidated artefact per target, matched to where it lives.** Produce the **full new or updated artefact** (not a diff or fragment) — when several notes target the same artefact, fold them into a single update rather than one package per note. Build it from a fresh read of current canon, and **re-read the live SKILL.md immediately before packaging**: autonomous sessions run concurrently, so a target may have been re-saved since the queue was read, and a stale base would silently revert that newer change (worked case: skill-coordinate, 2026-06-25). Then package it for the right surface:
   - **Skill, convention, agent or operator profile** → a saveable **`.skill`** file (a zip of the skill directory containing SKILL.md, named exactly as the target skill, no `-v2`/`-updated`/`-new` suffix), so it presents a one-click Save into the skills store.
   - **Routine or task** → the `routine-*` / `task-*` artefact is saved as a `.skill` like any other canon; its **loader config** (the one-line `Read .claude/skills/<artefact>/SKILL.md and follow it verbatim`) is the only pasted-block exception — name the exact Cloud Routine / Cowork target and the repo render-source path under `.claude/routines|tasks/` where a config edit is genuinely needed.
4a. **File the repo-lane ticket for a repo-native dependency — by default.** Where a drained canon change **creates a matching repo-native edit** (a new artefact `type` that `build-manifest.ts` must learn, a site-render change, a `CLAUDE.md` update), **file the repo-lane delivery ticket rather than only naming it**: an `OPS:`/`FIX:` Backlog ticket on **`agent:R3-LAY`** in Apps / os.Claude (the routing in convention-linear and skill-optimisation-review), with acceptance criteria, linked to the canon change it depends on. This is the **repo lane**, not the forbidden canon-apply ticket — the canon still saves via the button; only the repo half is a ticket, and it flows through Forge normally (worked case: the `operator` type needed `build-manifest.ts` support, filed as APP-407, 2026-07-01). A repo-native problem *unrelated* to a drained canon change is `skill-issue-capture`'s remit, not this. The one thing still never filed is a ticket to **apply the canon change itself** via Forge.
5. **Close or surface each note — never leave a live one silently in Backlog.** Each drained note takes exactly one of three dispositions:
   - **Incorporated** → comment the outcome — into `<artefact>`, plus any repo-lane ticket filed with its ID — then move it to **Done**.
   - **Assessed, not warranted** → comment one line why, then move it to **Done**.
   - **Warranted but not authorable yet** (it waits on an Owner prerequisite, separate work, or a decision the drain can't take unattended) → **surface it to the Owner; do not close it and do not leave it unmarked in Backlog.** A buried Backlog ticket gives the operator no cue that it needs him — the deferral is invisible. Surface per convention-linear's state semantics:
     - *Blocked by separate work* — a prerequisite that other work must clear (a setup, a baseline, a dependency): move it to **Blocked** and add a **blocked-by** relation to that work. If the prerequisite is not yet a ticket, file it (Owner-assigned where it's his to do) and relate to it. Assign the Owner, and set priority **Urgent**, where the Owner's own action is the blocker.
     - *Waits only on the Owner's decision or answer* — an elicitation, a design call the drain must not guess: move it to **Blocked**, set priority **Urgent**, **assign the Owner**, and comment the specific question. **Blocked + Urgent is the standing "this needs you" signal** — it surfaces the note in the daily brief's Blocked bucket and the os.Claude canon sweep (`task-daily-report`), which a Backlog-assigned note does not reach. This is the deliberate canon-decision exception to convention-linear's "a decision-only item is In Review, not Blocked": canon intake has no In-Review build stage, so Blocked + Urgent is the agreed Owner-surface (decision: Aled, 2026-07-07).
     Keep the `agent:PUL-5E` executor either way, so the note returns to the drain (via step 1's surfaced-note re-read) once the blocker clears or the decision is made.

   Once the operator saves an authored artefact, ops-sync detects Claude is ahead and raises the publish ticket to the repo.
6. **Report.** Short summary: artefacts produced (which, what changed, save or paste), repo-lane tickets filed (IDs), notes drained to Done, **notes surfaced (which, and what they now wait on)**, any non-canon observations named for the operator, anything skipped. No preamble, no sign-off.

## Guardrails

- **Capture is a note, not a fix; drain produces the artefact.** The only ticket capture ever touches is a `FRICTION:` note in the Pulse queue. Drain never files a **canon-change** ticket and never routes a canon edit through the delivery loop — that downstream-first inversion is what this skill exists to avoid. A `FRICTION:` note records an observation for retro to assess; the canon change is still produced as a `.skill` and **saved by the operator**, and **Forge never executes a canon edit**.
- **A deferred note is surfaced, not buried — and reaches the Owner's brief, not just the board.** *Warranted but not yet authorable* is a real third outcome beside incorporated and not-warranted. When the drain defers such a note it moves it to **Blocked** with a **blocked-by** relation to the prerequisite (prerequisite-blocked), or to **Blocked + Urgent, assigned to the Owner** with the open question (decision-pending) — never leaves it unmarked in Backlog, where the operator has no cue it needs him. Blocked + Urgent is the signal `task-daily-report` reads, so canon-needing-the-Owner is as loud in the morning brief as delivery-needing-the-Owner; a Backlog-assigned note is invisible to the brief (root cause: os.Claude is gated out of the brief unless a canon item is Blocked/assigned; fixed with the paired `task-daily-report` canon sweep). It keeps `agent:PUL-5E` and returns to a later drain when the blocker clears. A note is **Done** only when incorporated or assessed-not-warranted. (Worked case: the APP-428 planning-and-time family and APP-438 surfaced to Blocked with blocked-by relations, APP-442 to Blocked + Urgent assigned to the Owner, 2026-07-07.)
- **Repo-native dependencies are filed, not just named.** When a drained canon change needs a matching repo edit (a new `type` in `build-manifest.ts`, a render change, a `CLAUDE.md` update), file the repo-lane Forge ticket (`OPS:`/`FIX:`, `agent:R3-LAY`) by default and link it to the canon change. This is not the forbidden canon-apply ticket — the canon still saves via the button; only the *repo* half is a ticket. The distinction is the three-lane split in `core-operating-model`: canon saves, repo is a PR.
- **FRICTION vs FIX/OPS/DRIFT.** A `FRICTION:` note (Pulse queue, `agent:PUL-5E`) is canon-improvement intake, drained into a save-ready artefact. A runtime or repo problem unrelated to a drained canon change — a defect, a tool error, an artefact missing from the repo — is `skill-issue-capture`'s remit (`FIX:`/`OPS:`/`DRIFT:`, routed to Forge or the operator), not this.
- **Assess against current canon, not the note.** The drain proposes whatever a fresh read of the live SKILL.md warrants, which may be nothing — not whatever fix the note suggested.
- **Propose canon, never apply it** — Claude never edits canon itself. The canon output is a proposal the operator saves; only the repo-lane half is filed as a ticket.
- **Match the artefact to where it lives.** A skill, convention, agent or operator profile installs as a `.skill`; a routine or task also saves as a `.skill`, with only its one-line loader config as a pasted exception.
- **One opportunity per artefact.** Don't bundle unrelated fixes; don't split one fix across several.
- **Consolidate per target; build on the very latest canon.** All canon-improvement intake funnels through the Pulse queue and is drained in batch, so the operator saves a consolidated set in one place rather than hunting saves scattered across sessions. Several notes touching one artefact merge into one update, and the live canon is re-read just before packaging so a concurrent save is never clobbered.
- **Calibrate to evidence.** A single observation is a small wording fix, not a redesign. Count instances (including recurrence comments on the note) before escalating scope.
- **Nothing to fix produces nothing.** A clean run captures no note; an empty queue produces no artefact.

## Tone

Calm, precise, sentence case, British spelling, no exclamation marks, outcome before adjective. (cos.tov.)

## Setup (scheduled drain)

- The drain runs as `task-pulse-retro` — a Cowork scheduled task (cloud). Weekly, or after a known batch of runs.
- **Connectors:** Linear (read the queue, comment, move to Done, surface a deferral to Blocked / assign the Owner, wire blocked-by relations, file any repo-lane ticket) + the skills store (save the artefacts the operator approves).
- Capture needs only Linear, so every surface — including Claude Code routines — can file a `FRICTION:` note.

## Embedding in other skills

Add one line as the final step of a skill: "On finish, run skill-ops-retro capture on this run's friction: file a FRICTION note to the Pulse queue for the drain pass to assess." Keep the rules here, not in each skill. Only paste a compact version into a skill that runs where skill-ops-retro won't be loaded alongside it.
