Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 69 additions & 5 deletions .agents/skills/feature-close/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,56 @@ owned. There is nothing left for a second refusal to catch.
A refusal here is the workflow working, not a problem to route around. If the user overrides after being
told, say plainly what is being overridden, then proceed.

### Go through the plan's open questions — before anything is written

Read the plan's **§9 Open questions**, and the **Note** column of its ledger. `/feature-implement` surfaced
§9 at activation and nothing has read it since, and **this is the last command that ever will** — after the
`git mv` it is in `context/archive/`, where no command looks.

**What is still open here is an owner check** — an item no gate can close because it needs a person: a
reading in a language nobody on the branch speaks, a screen-reader pass, a judgement about how something
looks, a check on a device this project does not drive. *What happens to a question the plan could not
settle* in [`context/workflow.md`](../../../context/workflow.md) is the standing rule; the ends are here.

**Every item that still needs a person gets one of three:**

- **answered** → write the answer into the item, in the plan, in place. A phase that settled one has
already done this; the user settling one here is the same end.
- **filed** → one issue, wherever this project already files bugs, carrying this project's own labels,
saying what has to be looked at and who it waits on. **Never the backlog label**, and not written up as a
defect — it is a check nobody has run, not a thing known to be wrong. **It is filed as what it is, and
not as a bug**: a pending screen-reader pass recorded as a defect is a defect report nobody can
reproduce. **The person who does the check is what closes it**, and the workflow neither reads it nor
ranks it.
- **waived** → the user says in this turn that it does not matter. Mark the item waived and move on.

**The user picks, item by item, and silence is not a waiver.** Use your runtime's question mechanism if it
has one. **Where this project files bugs nowhere, there are two ends rather than three** — say so, and the
item is answered or waived. Do not invent a store for it, and do not hold up the retirement over it.

**This runs before the writes below** because its result is what the `history.md` row's Why and the archived
document both carry. Nothing afterwards would have anything to amend.

**This adds no status and no fourth phase state.** An owner check is not a phase's and does not gate one:
a phase whose scope landed and whose gates passed is `done` whether or not a person has since looked at
what it produced, and the feature's Outcome stays `shipped` for the same reason.

**Most of §9 is not an owner check.** The filter is one bit — *does this need a person* — applied to a list
the plan already wrote, not a disposition assigned to every line. **This is not the `notes.md` triage
refused further down**, and that refusal stands: that file is a gate's and grows without bound, while §9 is
the plan's and is bounded by it.

**Then say in the report where each one went**, including when the answer is *none*. An empty report reads
as "nobody looked", exactly as it does for documentation and for the release note.

### Then, as one reviewed change

1. **Move the entry into history.** Remove it from `context/roadmap.md` entirely, and append one row to
`context/history.md`: date, name, outcome `shipped`, a one-line why, and a link into `context/archive/`.
One line. That file **indexes** depth, it does not duplicate it — the reasoning stays in the archived
plan.
plan. **Where an owner check was filed, the why names it and the issue that carries it**, and the
outcome stays `shipped` and gains no value — *The history row says what is waiting, in the Why* in
[`context/workflow.md`](../../../context/workflow.md) says why it could not be anything else.
2. **`git mv` the plan** from `context/plans/` to `context/archive/`. Use `git mv`, not `mv` — the file's
history is the record of how the feature was actually built.
3. **Rewrite the document's header to point at the history row.** In the moved document, replace
Expand All @@ -63,6 +107,10 @@ told, say plainly what is being overridden, then proceed.
Add a note if its §-references are cited from source comments. **Do not stamp the outcome and date
into the document.** `history.md` owns them, and a copy in the header is a second place to maintain.
Replacing the old header is what stops a stale status surviving the move.

**§9 travels with it, carrying the ends the step above gave it** — each item answered, marked waived, or
naming the issue it was filed as. That is what makes the archived plan the record for the two ends that
have no other one.
4. **Sweep every reference to its old path**, and **show the sweep for review before committing.**

### The sweep
Expand Down Expand Up @@ -143,10 +191,19 @@ retirement as one reviewable change and hand it over.

**Without it, this command writes the note and stops.** That is the default and it is the right one.
[`context/workflow.md`](../../../context/workflow.md) forbids running what bumps, tags, publishes or
deploys, with one exception — *when the user asks for it in that turn* — and **this flag is what that
asking looks like.** So it is never inferred: not from "and ship it" earlier in the session, not from a
plan, not from the notes looking ready, and not from a release being obviously due. A sentence is not a
flag.
deploys, with one exception — *when the user asks for it in that turn* — and **this flag is one of the two
shapes that asking takes.** So it is never inferred: not from "and ship it" earlier in the session, not
from a plan, not from the notes looking ready, and not from a release being obviously due. A sentence is
not a flag.

**The other shape is `/release`, and it is the one to name when the user has not typed this flag.** This
flag **fuses** the release into the feature's own merge: one branch, one pull request, and a diff where the
version move sits among the feature's code. `/release` separates them — the note waits on the default
branch with everybody else's, and the release is cut later on a branch of its own, which is where a reader
can see that the version move is the whole of the change. Neither is the better answer in general: this one
suits a repository that releases about as often as it merges, and the separated one suits a repository
where notes accumulate. **If the user asked for a release and typed no flag, name `/release` rather than
assuming this one.**

Read [`context/release.md`](../../../context/release.md) and run **the script its Bump wire names**. That
file says what it is; naming a tool here would be wrong in half the repositories this command runs in.
Expand Down Expand Up @@ -213,6 +270,12 @@ ended by then.
For an entry that will not be built. **There is no ledger check in this mode** — unfinished phases are
expected.

**The open-questions pass still runs, and it still runs first**, by the rule the release note already
follows at the end of this mode: an owner check belongs to the code that landed, not to the outcome the
feature was later given. So an item about a phase that landed is an owner check like any other, and an item
about work that was never written is **waived by construction** — say that in one line rather than walking
it. A feature with no landed phase has nothing here at all.

1. Append a `context/history.md` row with outcome `dropped` (or `superseded by <name>`) and **the reason
the user gave**, verbatim in substance, not softened. That row is what stops the idea being re-proposed,
so a vague reason makes it worthless.
Expand All @@ -222,6 +285,7 @@ expected.
stamped outcome, same rule as Mode 1), and sweep.
4. **Delete `context/notes.md`** if it exists, per *Delete `context/notes.md`* above. A feature that will
not be built has nothing its notes should outlive.

**`--release` is refused in this mode**, and not as a technicality: there is no note, so there is nothing
this retirement would be releasing. If a release is due anyway, that is its own act and not this one's.

Expand Down
8 changes: 8 additions & 0 deletions .agents/skills/feature-close/tracker.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ phase finished — and so is everything about pushing.
| `git mv` the plan to `archive/` | nothing moves; the issue keeps its body and its whole thread |
| rewrite the document header | nothing — a closed issue does not claim to be open |
| the reference sweep | **nothing to sweep.** No path changed, so no link broke |
| the plan's §9, read out of the document | **unchanged** — §9 is a section of the body, and the body is the plan |
| answered or waived, written into the item | a body edit like any other |
| the why names the filed issue | the closing comment names it, by number — both issues are in one tracker, so it is a reference rather than a path |
| delete `context/notes.md` | **unchanged** — it is a file in a working tree under either answer, and it is deleted the same way |

**The archive is the closed issue**, and it is more than the file it replaces: the plan, the discussion
Expand All @@ -42,6 +45,11 @@ This is the only place `git.md`'s answer changes what this command does, and it
[`context/tracking.md`](../../../context/tracking.md) recommends pairing this substrate with the push
answer rather than requiring it.

**A filed owner check is an issue here like anywhere else, and it stays outside the one bit.** No backlog
label, no planned label, and **no `blocked by` relationship** — that primitive is between features, and an
owner check is not one. It carries this project's own labels and whatever assignee the person who will do
the check has, and nothing in the workflow reads it again.

**The release note is unchanged.** It is an artifact of the change rather than workflow state, so it is a
file in this repository under both of [`context/tracking.md`](../../../context/tracking.md)'s answers —
written, confirmed and committed exactly as above, and carried by the same pull request that closes the
Expand Down
62 changes: 52 additions & 10 deletions .agents/skills/feature-implement/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ description: "Activate a planned feature and run the next phase of its plan —
# /feature-implement

Owns the transition from *has a plan* to *being worked*, **and** the phases within it. One invocation runs
**one phase**: pick it, do it, gate it, close out its ledger row. `--all` (step 14) runs that same loop
back to back instead of stopping after the first.
**one round**: pick a phase, do it, gate it, close out its ledger row — and where phases of this plan are
independent of each other, up to the cap in [`context/executors.md`](../../../context/executors.md) of them
side by side, per [`parallel.md`](parallel.md). `--all` (step 14) runs that same loop back to back instead
of stopping after the first.

Read [`context/workflow.md`](../../../context/workflow.md) for the tier model, the one-active-feature rule
and the gate contract. This skill cites those rather than restating them.
Expand Down Expand Up @@ -76,12 +78,25 @@ entries are all `done`.**

If it is already `in progress`, **read its Note and resume from there — do not restart it.**

**Then see what can run beside it.** Where this phase and another runnable one are both `not started` —
every `Depends on` `done` — and share **no path** on their **Files:** lines, prose included, the two can
run at the same time, each with its own coder, up to the cap in
[`context/executors.md`](../../../context/executors.md). Where that is true, read
[`parallel.md`](parallel.md) beside this file before step 6: it holds how the round is formed,
every line that makes it fall back to one phase at a time, and how the work comes back. **No flag asks for
this and none turns it on** — it is this command's own decision, each round, and a round of one phase is
the ordinary run the steps below describe.

## 4. Read the row you are about to work

If the phase you picked reads `blocked`, its Note says what stopped it. **That is the work** — clear it
before starting anything new, or say plainly why it cannot be cleared and stop. A `blocked` row is the only
durable record a previous run left, so it is read rather than overwritten.

**If the Note names a tree, this phase's work is already in it** — a round left it there. Read
[`parallel.md`](parallel.md) and land that tree before briefing anybody; a coder re-run over finished work
throws it away.

## 5. Stop on disagreement

If the ledger's claim contradicts the repo — a phase marked `done` whose **Files:** do not exist, or work
Expand All @@ -97,8 +112,9 @@ cancelled — leaves a working tree with half a phase in it. A row still reading
run into step 5's disagreement stop, or into redoing work that is already there.

One token and one Note, in the row that is already there — do not move the entry, restructure the table, or
write a summary anywhere else. If the row is already `in progress` because you are resuming it, leave it
alone; step 11 rewrites the Note.
write a summary anywhere else. **One line**, by the same rule step 11 applies: what is underway, so a
session arriving after an interruption knows where it landed. If the row is already `in progress` because
you are resuming it, leave it alone; step 11 rewrites the Note.

**This write is not a change of its own.** Leave it in the working tree — it lands with the phase's work
under either answer in [`context/git.md`](../../../context/git.md). Never commit it on its own.
Expand All @@ -113,6 +129,15 @@ paths are on the same **Files:** line as the code. Per the standing rule in
phase. If the work turned out differently from the plan and made something *else* untrue — a README the
plan never listed — fix that too and say so; the sweep happened before the code existed.

**An open question this phase settles is answered in the plan's §9, by this phase** — in place, in the
item it settles, riding the same change as the ledger row. Same rule as the documentation rows above and
the same reason: the answer is cheapest to write while the work that produced it is still in front of you,
and `/feature-close` goes through that section before the plan is archived and has to give whatever is left
an end. **Leave the items this phase did not settle alone**, and do not invent an answer to close one — an
honest open question is what that section is for, and the one no phase could finish is exactly what the
retirement is there to catch. Settling one is not part of this phase's scope and step 11 does not test for
it.

**Read [`context/release.md`](../../../context/release.md) and find out whether this phase owes a release
note.** That file answers per path and at one granularity, and only one of its two granularity answers
reaches this step:
Expand Down Expand Up @@ -159,11 +184,17 @@ the first answer and implements in-host; that is a fallback, not a failure, and
coder produced. A coder that reports its own success has reported nothing — that is what step 11 means by
refusing `done` on a self-report.

The brief **cites paths, it does not paste files.** Point at the phase's own section in the plan — its
`Files:`, and its `Standards:` line, which is the plan's one traversal of `context/standards/README.md` and
what the coder loads instead of the table — and at `context/stack.md`. Anything that can read this
repository can open them, and a brief that inlines them is a brief that goes stale. A plan written before
phases carried a `Standards:` line has none; then say to load per that README's conditional table.
The brief **cites paths, it does not paste files, and it names the phase rather than the plan.** Point at
the phase's own §6.2 section — its `Files:`, its `Standards:` line, which is the plan's one traversal of
`context/standards/README.md` and what the coder loads instead of the table, and its `Decisions:` line,
which is the plan's one traversal of §3 — and at `context/stack.md`. Anything that can read this repository
can open them, and a brief that inlines them is a brief that goes stale.

**A whole-plan read is the fallback, not the route.** Plans in the field run tens of thousands of
characters and three readers open one on every phase; the §6.2 section plus the two lines is what a coder
needs, and a brief that says *read the plan* spends the rest on §1, §5 and the phases that are already
`done`. A plan written before phases carried these lines has neither: then say to load per that README's
conditional table, and to read §3 for the decisions that bind this phase.

Describe **what** needs to happen, never **how** to code it. Scope each delegated task to specific files.

Expand All @@ -185,7 +216,9 @@ Dispatch per [`context/executors.md`](../../../context/executors.md), which hold
The last is the fallback and the weakest — the session that wrote the code judging whether the code is good
— so **say which one you ran**, every time. The first is the cheapest real independence available: a
reader that never saw the implementation being written, only what it produced. Brief it with the phase's
section — its `Files:`, its review expectations and its `Standards:` line — and the diff. Where the runtime
§6.2 section — its `Files:`, its review expectations, its `Standards:` line and its `Decisions:` line —
and the diff. **The section, not the plan**, for the reason step 7 gives; a reviewer judging whether the
change honoured a decision needs the decisions the phase cites, not all of §3. Where the runtime
has no such mechanism, fall back to reviewing the diff yourself against the plan's review expectations and
the standards, and say that is what happened.

Expand Down Expand Up @@ -242,6 +275,12 @@ The row is part of the same change as the work — never a separate step afterwa
- **Some landed** → stays `in progress`, Note rewritten to name exactly what remains.
- **A gate hit its cap, or something external blocks it** → `blocked`, with the blocker in the Note.

**The Note is one line**, per §6.1 of the plan itself: what a later session needs in order to understand
or resume the Status beside it, and nothing else. **Gate 1's output, the test counts and the measurements
do not go in it.** They go in the commit message that carries the row, under
[`context/git.md`](../../../context/git.md)'s answer, or in step 13's report. The ledger is read in a hurry
by a session that has just arrived, and a Note that has become a phase log is one it cannot skim.

**Never mark `done` on a coder's self-report** — the gate output is the evidence. A blocking item that was
not fixed means the gate did not pass, and a gate that did not pass means the phase is not `done` — there
is no second check to run, because `done` already says both gates passed.
Expand Down Expand Up @@ -283,6 +322,9 @@ side-effect of the last phase finishing.
Without the flag, this invocation is over at step 13. With it, **go back to step 3 and run the next
phase**, and keep going until the stop list below says otherwise.

**The unit is step 3's round.** This flag decides whether there is a next one, never how wide one is —
that is [`parallel.md`](parallel.md)'s, and it is decided again each time step 3 runs.

Phase to phase is not a tier boundary — this command already owns "activation, and the phases within a
plan" — so the flag crosses nothing. What it removes is the pause where a user reads a phase's report
before the next one builds on it, and everything below exists to replace that pause with something
Expand Down
Loading
Loading