Skip to content
Merged
2 changes: 1 addition & 1 deletion plugins/work-items/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "work-items",
"version": "0.17.2",
"version": "0.18.0",
"description": "Manages development work items through a provider-neutral tracker seam that ships with the plugin (bundled dispatcher plus github and local-markdown adapters; seam plugin-dir canonical, adapters consumer-local-first): dashboard, taxonomy-labeled creation, a race-safe assignee-plus-lease claim protocol, recurring-schedule checks, TODO scanning, stale-lease auditing, plan decomposition into vertical-slice items, and raw-intake triage (issues and unsolicited PRs through raw, verified, briefed, autonomous-eligible states). The re-runnable setup skill binds the provider (.work-item-tracker.json), seeds the recurring-schedule seam (.github/recurring-schedule.json), and remaps canonical role labels.",
"author": {
"name": "Melodic Software",
Expand Down
25 changes: 25 additions & 0 deletions plugins/work-items/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,31 @@
All notable changes to the `work-items` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.18.0]

Extract the cross-lane self-observation filing rule ("file what you will not fix: dedupe → categorize
→ fixed shape → `needs-triage`") into one shared reference surface so the lanes reference it instead
of each absorbing a private, drift-prone copy (`#540`).

### Added

- **Shared self-observation filing contract — `reference/dogfood-filing.md`.** The rule that an
autonomous lane files a problem it will not fix in-cycle is cross-lane-identical, so the absorption
umbrellas (`#477`/`#478`/`#479`) must not each absorb a private copy. The new reference is the single
in-repo source of truth: it composes the existing mechanics by pointer — the *Search items* dedupe
read and body template `track add` owns, the `create-item` seam write, and the `needs-triage` status
label — and adds only the self-observation policy (when to file vs the `tracker-seam.md` "Default =
fix, not file" posture, the mechanical-vs-model split, autonomous authorization, and the AI
disclaimer). No new script: the mechanical core is already the seam + adapter + `track add`
machinery, so the doc references it rather than forking the template and search mechanics.

### Changed

- **`work`, `triage`, and `scan-todos` now reference the shared filing contract at their filing
sites** — the `work` post-green deferred-finding follow-up, the `triage` follow-up-work creation,
and the `scan-todos` "file a work item" branch each point at `reference/dogfood-filing.md` for the
dedupe → categorize → fixed shape → `needs-triage` sequence instead of leaving it implicit.

## [0.17.2]

### Changed
Expand Down
88 changes: 88 additions & 0 deletions plugins/work-items/reference/dogfood-filing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Self-observation filing — the shared dogfood contract

When an autonomous lane hits a problem it will **not** fix in the current cycle — a bug, a gap, a
piece of orthogonal drift — it files that problem as a tracker item so the lane's own findings feed
the same queue everyone else works from. That filing rule is **cross-lane-identical**: `work`,
`triage`, `scan-todos`, and the external standing-loop lanes (`source-control:babysit-prs`,
control-tower, enrichment) all file the same way. This document is the single source of truth for
*how*, so each lane references it once instead of restating the rule and letting the copies drift.

The mechanics it composes already live in this plugin — the seam `create-item` verb, the bound
adapter's *Search items* operation, the `track add` body template, and the label taxonomy. This
contract does not re-implement any of them; it **points** at each and adds only the self-observation
policy that binds them into one sequence.

## When it applies — file what you will not fix, nothing else

The default posture is **fix, not file** ([`tracker-seam.md`](tracker-seam.md) "Default = fix, not
file"): Boy-Scout-scope drift discovered while working belongs in the current change, not the
tracker. Self-observation filing is the **narrow exception** — a problem is filed only when it is
genuinely orthogonal to the current item, large enough to need its own planning pass, or needs
research this lane is not positioned to do. `work`'s post-green review already draws this line for a
VALID-but-deferred finding ([`../skills/work/SKILL.md`](../skills/work/SKILL.md) "Post-green review
pass"); the same test governs every lane.

## The sequence

Four beats, in order. The two **mechanical** beats reuse existing machinery verbatim; the two
**judgment** beats stay with the model.

1. **Dedupe first (mechanical search + model sameness).** Before creating anything, run the
search-before-create pre-flight — the bound adapter's *Search items* operation over `--state all`,
the same read `track add` performs ([`../skills/track/actions/add.md`](../skills/track/actions/add.md)
"Duplicate check"). Whether a hit is *the same problem* is a model judgment, not a string match:
compare by underlying cause, not wording. A match against an **open** item means comment on it
instead of opening a second one. A match against a **closed** item is different: closed items are
absent from the triage attention view, so commenting there buries a still-live or regressed
observation where no lane will pick it up — reopen the closed item (or open a fresh active item
that links it) so the problem re-enters the queue. Where the consuming repo keeps a rejected-concept
ledger
(`docs/out-of-scope/`), the same step's ledger check applies — do not re-file a settled rejection.

2. **Categorize (model judgment).** Classify bug vs enhancement first — it steers everything
downstream — then the type and priority, following triage's classification rule
([`../skills/triage/SKILL.md`](../skills/triage/SKILL.md) "Recommend category + state") and the
label grammar ([`label-taxonomy.md`](label-taxonomy.md)). A self-filed item is raw intake: the
filer records what it observed, not a verified diagnosis.

3. **File with the fixed shape (mechanical).** File through the canonical `track add` path, which
owns the body template (Context / Proposed work / Acceptance criteria / References / Metadata) and
the argv-safe `create-item` write ([`../skills/track/actions/add.md`](../skills/track/actions/add.md)
"Build body", "Create the item"). The shape is not restated here — `track add` is its source of
truth, so a change to the template lands in one place.

4. **Label `needs-triage`, then hand off (mechanical label + policy).** Apply `status:needs-triage`
([`label-taxonomy.md`](label-taxonomy.md) status axis) so the item lands in the triage attention
view for evaluation ([`../skills/triage/SKILL.md`](../skills/triage/SKILL.md) "Attention view").
Comment thread
kyle-sexton marked this conversation as resolved.
**The filer does not self-triage** — filing surfaces the problem into raw intake; triage verifies,
categorizes definitively, and routes it. Auto-application of `needs-triage` to a fresh item lacking
a priority label is tracked separately (`#506`); until it lands, the filing lane applies the label.
Comment thread
kyle-sexton marked this conversation as resolved.

## Mechanical core is already scripted — reference it, do not duplicate

The "mechanical core" of this contract (dedupe search, filing-template emission, the `create-item`
write) is not a new script to author — it is the existing seam + bound-adapter + `track add`
machinery above. Duplicating it into a standalone wrapper would fork the very template and search
mechanics this document exists to keep single-sourced. The judgment core (sameness, category) is
model work by nature and is not scriptable. A lane composes the two by following the sequence, not by
calling a new binary.

## Autonomous authorization and the AI disclaimer

Model-initiated filing is gated: on the interactive path a lane drafts the item and asks before
creating it ([`../skills/track/actions/add.md`](../skills/track/actions/add.md) "Authorization
gate"). On an **autonomous lane** — a `/loop` or `/schedule` session whose standing rules already
authorize tracker mutations — those standing rules **are** the authorization, the same resolution
triage's direction gate makes ([`../skills/triage/SKILL.md`](../skills/triage/SKILL.md) "Direction
gate"). An autonomous lane prefixes every item and comment it creates with an AI disclaimer —
triage's ([`../skills/triage/SKILL.md`](../skills/triage/SKILL.md) "AI disclaimer") section is the
canonical form, but a non-triage lane names its own lane rather than inheriting triage's literal
`during triage` wording, so the provenance phase stays accurate. A lane-neutral disclaimer SSOT that
collapses this to a single pointer is tracked in `#768`.

## Reconciliation note

The authoritative wording of this rule currently also lives in the external v4 standing-loop prompts,
where `source-control:babysit-prs` has not yet absorbed its lane rules (`#477`). This document is the
in-repo surface those prompts and the lane-absorption skills reference; when the remaining absorption
lands, its self-observation wording reconciles against this contract rather than adding a fourth copy.
2 changes: 1 addition & 1 deletion plugins/work-items/skills/scan-todos/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ git -C "${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel)}" grep -nE '\b(TO
1. **For each marker**, read context (10 lines before/after), then classify:

- **Resolve now** — small fix; do the work, remove the marker
- **File a work item + remove marker** — significant work; create via `/work-items:track add`, remove the inline marker (do not leave `TODO` as a stand-in for the item)
- **File a work item + remove marker** — significant work; create via `/work-items:track add` following the shared self-observation contract ([`${CLAUDE_PLUGIN_ROOT}/reference/dogfood-filing.md`](${CLAUDE_PLUGIN_ROOT}/reference/dogfood-filing.md): dedupe → categorize → fixed shape → `needs-triage`), remove the inline marker (do not leave `TODO` as a stand-in for the item)
- **Remove (already done)** — work completed; delete the comment
- **False positive** — structured grammar or external upstream citation misclassified; fix the exclusion if systemic, otherwise note it in the PR

Expand Down
2 changes: 1 addition & 1 deletion plugins/work-items/skills/triage/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ For a PR, the outcome addresses the attached code explicitly: adopt the diff (br

The canonical-role labels applied by these outcomes (autonomous-eligible default `agent-ready`, human-gated default `needs-human`) are **resolved from the binding's `config.role_labels` at action entry**, never hardcoded — warn loudly when a role defaults because `.work-item-tracker.json` or the entry is absent rather than applying the default string silently (a repo that remapped roles would otherwise be mislabeled), and stop on a malformed/empty/non-string value ([`${CLAUDE_PLUGIN_ROOT}/reference/label-taxonomy.md`](${CLAUDE_PLUGIN_ROOT}/reference/label-taxonomy.md) "Canonical roles").

Label edits, comments, and closes route through the adapter's write mechanics (adapter: "Edit labels / assignees", "Comment on item / edit a comment", "Close item"); the gather + attention-view reads are bare. Item creation, when triage spawns follow-up work, goes through the seam `create-item` verb (`/work-items:track add` is the canonical path).
Label edits, comments, and closes route through the adapter's write mechanics (adapter: "Edit labels / assignees", "Comment on item / edit a comment", "Close item"); the gather + attention-view reads are bare. When triage spawns follow-up work — a fresh, orthogonal problem it surfaces but will not fix this pass, distinct from the item under evaluation and from work it has already scoped and routed — item creation goes through the seam `create-item` verb (`/work-items:track add` is the canonical path) and follows the shared self-observation contract ([`${CLAUDE_PLUGIN_ROOT}/reference/dogfood-filing.md`](${CLAUDE_PLUGIN_ROOT}/reference/dogfood-filing.md): dedupe → categorize → fixed shape → `needs-triage`). That new item is genuinely raw intake, so `needs-triage` is correct for it; the item triage is *evaluating* is never sent back to raw intake — its raw marker is cleared by the closing invariant below — and follow-up whose scope triage has already decided is routed through the outcome labels above, not filed as a self-observation.

**Closing invariant — no outcome leaves a re-selectable raw item.** The attention view lists *open* items and re-selects anything still carrying the raw marker, so every outcome must leave the item unre-selectable:

Expand Down
2 changes: 1 addition & 1 deletion plugins/work-items/skills/work/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ On user confirmation ("yes"):

1. **High-blast-radius diff gate (pre-PR).** Before a PR is opened, the orchestrator does a **full-diff read** when the diff touches skill frontmatter descriptions or trigger keywords, cross-plugin contracts, or hooks. This complements the worker scope-fence: the scope-fence bounds what a worker *may* touch, this gate is the orchestrator's own read of what the worker *did* touch before the change leaves the lane.

1. **Post-green review pass, then hand off.** After CI is green, run one review pass. The fetch-once → validate → classify → threaded-reply → react → resolve-bot-thread loop is owned by `/source-control:pull-request`; this skill adds only the sequencing and the work-item linkage: fix branch-owned findings via the **owning subagent** (the orchestrator still never edits source), and a **VALID-but-deferred finding requires a filed follow-up issue** — file it via `/work-items:track add`, then cite that issue **both** in the classification reply **and** in the PR's `## Related` section; a deferred finding cannot be resolved without it. Then hand the PR off to `/source-control:babysit-prs` (fleet loop, owned there).
1. **Post-green review pass, then hand off.** After CI is green, run one review pass. The fetch-once → validate → classify → threaded-reply → react → resolve-bot-thread loop is owned by `/source-control:pull-request`; this skill adds only the sequencing and the work-item linkage: fix branch-owned findings via the **owning subagent** (the orchestrator still never edits source), and a **VALID-but-deferred finding requires a filed follow-up issue** — file it via `/work-items:track add` following the shared self-observation contract ([`${CLAUDE_PLUGIN_ROOT}/reference/dogfood-filing.md`](${CLAUDE_PLUGIN_ROOT}/reference/dogfood-filing.md): dedupe → categorize → fixed shape → `needs-triage`), then cite that issue **both** in the classification reply **and** in the PR's `## Related` section; a deferred finding cannot be resolved without it. Then hand the PR off to `/source-control:babysit-prs` (fleet loop, owned there).

1. **Never-merge boundary.** This skill's lane ends at PR creation and the handoff above (review pass, then babysit). **Merging is the babysit lane or a human, never `work`** — consistent with `/source-control:babysit-prs`'s safe default never merging (its opt-in `worker`/`autopilot` tiers merge only behind a deterministic readiness gate) and `/source-control:pull-request` merges being human-gated.

Expand Down
Loading