From kata-flight
Use for a read-only kata flow dashboard or stuck-state report. Shows lifecycle depth, inbox, batch depth, and illegal/stale states without mutating git or kata. Trigger for backlog status, stuck katas, or $kata-flow-ops.
How this skill is triggered — by the user, by Claude, or both
Slash command
/kata-flight:kata-flow-ops --dashboard | --reap [--days N]--dashboard | --reap [--days N]The summary Claude sees in its skill listing — used to decide when to auto-load this skill
A read-only operator lens over the ship-flow state machine. The single-valued
A read-only operator lens over the ship-flow state machine. The single-valued
lifecycle:* namespace (see the label-vocabulary reference) makes the whole flow's state
queryable and illegal states greppable — this skill renders both.
Read-only, full stop. Both modes only kata list/kata labels and report.
Neither mutates git or the tracker: the dashboard counts, the reaper surfaces
(it never kata assign/label rm/close). Acting on what it finds is a human
decision (see the per-row next-step in the ship-flow-state-machine reference).
/kata-flow-ops --dashboard # funnel depth: lifecycle:* counts + inbox + batch:* depth
/kata-flow-ops --reap # surface illegal/stuck states (does NOT fix them)
/kata-flow-ops --reap --days N # stale-reviewed threshold (default 7)
kata list --json .issues[].labels[] — they are bare
strings there. Do not use kata show --json .issue.labels: it reports
null even when labels exist (the ship-flow-state-machine reference §5.2). Every query
below feeds off kata list … --json. For one-issue reads (owner/labels/links)
prefer engine scripts/kata-q.sh helpers; they encode these shapes null-safe.lifecycle:* is single-valued — exactly one per kata is legal; zero or two
is an illegal state the reaper catches.owner != null is the real "in-flight" signal; lifecycle:resolving|refining|shipping
is the labelled twin. They must agree — disagreement is the orphaned/abandoned defect.--dashboard — the funnel depth (§4.2)One snapshot of open work. Pull every open kata once, bucket by namespace.
kata list --status open --json > /tmp/kfo-open.json
# lifecycle:* depth (filed = open kata with NO lifecycle:* label)
jq -r '
.issues
| map(.labels // [])
| (map(select(any(startswith("lifecycle:"))|not)) | length) as $filed
| "filed \($filed)",
"queued \([.[]|select(any(.=="lifecycle:queued"))]|length)",
"reviewed \([.[]|select(any(.=="lifecycle:reviewed"))]|length)",
"resolving \([.[]|select(any(.=="lifecycle:resolving"))]|length)",
"refining \([.[]|select(any(.=="lifecycle:refining"))]|length)",
"shipping \([.[]|select(any(.=="lifecycle:shipping"))]|length)"
' /tmp/kfo-open.json
# human inbox: inbox:* ∪ kind:rdr-seed
jq -r '
.issues | map(.labels // [])
| "inbox:needs-review \([.[]|select(any(.=="inbox:needs-review"))]|length)",
"inbox:hold \([.[]|select(any(.=="inbox:hold"))]|length)",
"kind:rdr-seed \([.[]|select(any(.=="kind:rdr-seed"))]|length)"
' /tmp/kfo-open.json
# waiting on an in-flight RDR (not inbox): defect trackers, close when the RDR implements
jq -r '"kind:rdr-tracked \([.issues[]|select((.labels//[])|any(.=="kind:rdr-tracked"))]|length)"' /tmp/kfo-open.json
# seed funnel depth (WIP-limit view): split rdr-seeds into DOMAIN vs TOOLING so
# the real domain-RDR pressure isn't inflated by kata/flow tooling seeds. A seed
# whose area:* names a tooling surface (flow/kata/process) is tooling; the rest
# are domain. A standing DOMAIN backlog is the stale-seed risk Stage-2 re-validate
# exists for — report the count so a deep funnel is visible, not silent.
jq -r '
[.issues[] | select((.labels//[])|any(.=="kind:rdr-seed"))] as $seeds
| ($seeds | map(select((.labels//[])|any(test("^area:(flow|kata|process|tooling)")))) | length) as $tool
| "rdr-seed:tooling \($tool)",
"rdr-seed:domain \(($seeds|length) - $tool) (the real domain-RDR pressure)"
' /tmp/kfo-open.json
# per batch:* depth (one row per drainable group)
jq -r '
[.issues[].labels[]? | select(startswith("batch:"))]
| group_by(.) | map({k:.[0], n:length}) | sort_by(-.n)[]
| "\(.k) \(.n)"
' /tmp/kfo-open.json
Report the three blocks under headers lifecycle:, inbox:, batch:. filed + queued + reviewed + resolving + refining + shipping should equal the open count
minus any kata carrying two lifecycle:* — a mismatch is itself a finding;
point the reader at --reap.
--reap — the stuck-state sweep (§4.3)Surface illegal states. These are the exact §4 stuck-state queries (each reads
.issues[].labels, bare strings). The reaper lists short_ids and the rule each
tripped — it does not act. Each row's remedy is a human move per
the ship-flow-state-machine reference "Next steps".
# orphaned claim: a SHIP LOCK (owner kata-ship/*) with no phase label —
# a crashed/abandoned ship. A human-held kata (owner is a person, e.g. a
# manual `kata assign`) is NOT orphaned — exempt non-kata-ship/* owners so the
# reaper doesn't nag work a person is deliberately holding. (Shake-out finding.)
kata list --status open --json | jq -r '.issues[]|select((.owner // "" | startswith("kata-ship/")) and ((.labels//[])|any(test("^lifecycle:(resolving|refining|shipping)$"))|not))|.short_id'
# abandoned mid-ship: phase label but no owner (lock vanished mid-flight)
kata list --status open --json | jq -r '.issues[]|select(.owner==null and ((.labels//[])|any(test("^lifecycle:(resolving|refining|shipping)$"))))|.short_id'
# illegal: two lifecycle:* at once (a non-atomic rm+add transition crashed)
kata list --status open --json | jq -r '.issues[]|select((.labels//[]|map(select(startswith("lifecycle:")))|length)>1)|.short_id'
# stale: lifecycle:reviewed older than N days, never shipped (default N=7)
kata list --status open --label lifecycle:reviewed --json | jq -r --argjson days 7 '
(now - ($days*86400)) as $cut
| .issues[] | select(((.updated_at // .created_at) | sub("\\.[0-9]+Z$";"Z") | fromdateiso8601) < $cut) | .short_id'
# stale seed: kind:rdr-seed idle longer than the seed threshold (default 14 days,
# 2x reviewed) — a seed that sits between Seed and Propose long enough for its
# references/scope to go stale (the exact gap Stage-2 "re-validate the seed"
# covers). Surface it so the funnel stays a WIP-limited queue, not a roach motel.
kata list --status open --label kind:rdr-seed --json | jq -r --argjson days 14 '
(now - ($days*86400)) as $cut
| .issues[] | select(((.updated_at // .created_at) | sub("\\.[0-9]+Z$";"Z") | fromdateiso8601) < $cut) | .short_id'
# tracker drift: for each kind:rdr-tracked kata, read its `tracks: cli/NNNN`
# comment (kata show --json .comments[].body — comments DO return on show,
# unlike labels) and the named RDR's `**Status**:` line. Surface: Implemented
# (close overdue — Stage 8's close step was missed), Demoted/Abandoned/
# Superseded (defect lost its RDR → kata-scope-review), or no tracks: line
# (mislabeled). Draft/Final = healthy in-flight, stays quiet.
kata list --status open --label kind:rdr-tracked --json | jq -r '.issues[].short_id'
# stop-reason tally: count flights that ended `stopped:*` grouped by reason,
# from the machine-prefixed comment (kata show --json .comments[].body — comments
# DO return on show, unlike labels). Reads stop evidence without scraping prose.
for id in $(kata list --json | jq -r '.issues[].short_id'); do
kata show "$id" --json | jq -r '.comments[]?.body | capture("^flight:stopped:(?<r>[a-z0-9-]+)").r // empty'
done | sort | uniq -c | sort -rn
Report one section per rule: the rule name, the short_ids, and the canonical human remedy (re-stamp lifecycle / reclaim or release the lock / drop the extra label / re-ship or close the stale review / re-validate or close the stale seed). A clean sweep reports "no stuck states." Surface only; never mutate.
Notes:
lifecycle:reviewedcarries no timestamp in its label (labels can't hold a value — the label-vocabulary reference); the stale query uses the kata'supdated_atas the staleness proxy. If a date-bearingreviewed-at:comment exists it is the truer signal, but the comment read is optional and stays read-only.
| Condition | Action |
|---|---|
kata list fails / not configured | Refuse; surface (cannot read the tracker). |
kata show tempting for labels | Don't — use kata list --json .issues[].labels (the §5.2 labels:null gotcha). |
| A query returns rows | List them; never auto-fix. The reaper surfaces; a human acts. |
| Counts don't reconcile to the open total | Report it as a finding and point at --reap (likely a double lifecycle:*). |
lifecycle:*
single-valued, inbox:*/kind:rdr-seed as the human inbox, batch:* ephemeral./kata-flight — the primary drain; this skill is its natural read-only preflight.npx claudepluginhub cwensel/kata-flight --plugin kata-flightCreates, edits, and verifies skills using a test-driven development approach with pressure scenarios and subagents.