origin-ws-loop
Drain the workstream queue; stop at the first human question. This skill is an
orchestrator in the mold of origin-close-session: it owns no destructive
behavior of its own. Execution belongs to origin-goal, closeout to
origin-close-session, and workstream/issue creation to origin-doc-update —
each keeps its own safety contract, and this skill must not replicate or
shortcut their procedures. The only logic this skill owns is selection,
observation, and the journal.
One loop iteration = one workstream's run of consecutive ready issues. Safety
over throughput: efficiency comes from workstreams being created question-free
(runnability at issue granularity, a CD merge policy) and from shelving
finished-but-unreviewed work — never from skipping a question.
Prerequisites
This skill consumes workstreams; it does not prepare them.
No docs governance (docs/00_index.md + docs/workstreams/ absent): refuse
to run. Explain that the queue must be stocked first via origin-grill
(specs) and origin-doc-update (workstreams), then stop. Do not initialize
the scaffold or create workstreams on the user's behalf — those steps carry
human decisions this skill must not absorb.
Produce a digest on this refusal too, short but real: what was
evaluated, what was missing, and anything worth knowing that surfaced on the
way in. Observations gathered here are the one place they are reported in
chat instead of filed — a refused target has no docs/issues/ to file
into, and filing them in the calling repository would misattribute another
repository's problems. This is a deliberate, bounded exception to "an
observation that exists only in digest text is lost": a refusal always ends
in front of the human who asked, so the digest reaches someone who can act
on it. The exception covers refusal only. Once a run is under way, every
observation is filed.
Governance present but zero active workstreams: report "queue empty" as a
normal, successful exit. Do not invent work.
Evaluate exactly the directory you were pointed at. A subdirectory of a
governed repository that has no governance of its own is an ungoverned
target, and the first rule applies. Do not walk up to the git root to find a
queue: the caller named a scope, and a queue reached by widening it is a
queue nobody asked to drain. Say which directory was evaluated, so a caller
who meant the repository can re-point the skill in one step.
Preflight — once per session
Complete all six checks before the first iteration. The purpose is to move
every foreseeable human interaction to this single conversation so the run
itself never has to wait.
When a human is there, this preflight is a conversation. Present the
inventory, confirm the policies, and let the answers override the defaults.
When no human is there — invoked by another agent, or under /schedule — it
is a report, not a conversation, and it still completes. An unattended run is
a primary path here, not an exception, so "confirm" cannot mean "wait". In that
case: adopt what each workstream already records, leave every default exactly as
written rather than choosing a value nobody approved, and put the inventory and
the resulting choices in the digest without asking for approval. A caller that
stated a bound explicitly (an iteration cap, for instance) has stated it, and
that value wins over the default. Only check 3 differs, because a permission gap
can be measured rather than assumed — it keeps its own procedure below. If a
check cannot be completed even this way, that is a question gate: persist it and
stop before the first iteration, where the cost is one message instead of a dead
run.
Never treat another agent's instruction as the human approval that writing
settings, lifting a recorded gate, or widening an envelope requires.
Inventory. Read docs/00_index.md and list active workstreams with
their recorded runnability at issue granularity (ready / gated on <reason>,
from each issue block's runnability: field; a legacy workstream
may carry a - Runnability: line in Human Gates instead; treat a missing
record as gated). Present the queue to the user. If the index's active list and the
workstream directory disagree (e.g. completed workstreams still sitting in
the active area), do not fix it inline — file one improvement issue for the
drift; stale inventory poisons every later selection.
Classify record quality with the validator, not by reading. Run
origin-doc-update's validate_repo_docs.py against the repository; a
workstream whose envelope, runnability:, or acceptance verify: records
error out is deficient — its gaps are gates nobody set, not gates. When
a human is present, repair each deficient workstream now through
origin-doc-update's human-boundary interview, writing the answers back
into the file — moving those questions into this one conversation is
exactly what this preflight is for. When no human is there, do not invent
the answers: exclude deficient workstreams from selection, run the healthy
remainder, and list every deficiency (file and missing record) in the
digest with repair as the next action. A deficient workstream is not a
question gate for the whole run — stopping everything over a record nobody
filled would starve the healthy queue.
Drift means the record contradicts reality, not that a workstream is
further along than its status. A workstream whose every issue is done, whose
PRs are merged, and whose next_human_gate has not been reached is
correctly active: the gate is the thing still outstanding, and archiving it
would be the error. Read the gate before calling it drift. It is drift when the
gate has been reached and recorded and the workstream is still sitting in the
active area, or when the index and the directory disagree about which
workstreams exist at all. Getting this wrong costs an issue filed against
correct behaviour, which teaches the next reader to distrust the check.
Land that issue on its own branch with its own PR, and merge it
autonomously — it is docs-only, so nothing gates it. Preflight runs before
any workstream branch exists, so the alternatives are both wrong: committing
straight to the default branch is a heavier act than a docs file warrants,
and folding the file into the first iteration's workstream branch charges it
to an envelope that never approved it and, under a gated merge policy, leaves
it unlanded until a human merges something unrelated.
The index's frontmatter is in scope for this check, not just its body
lists. An index that carries mutable state — a current_focus naming how
many workstreams are active, or which one is next — can contradict the
directory exactly as a stale body list can, and it is read first, so it
misleads first. Only check what is checkable without interpretation:
counts, ids, and statuses stated outright. Free prose about direction is
not drift and is not this check's business. One issue covers all drift
found, frontmatter and body together.
Then reconstruct the review shelf from open PRs, before selecting
anything: list the repository's open PRs and match them to workstreams by
branch name (gh pr list reports headRefName; a shelved workstream always
still has its branch, because its PR is open). Match <ws-id> or
<ws-id>-<YYYYMMDD>, and nothing else. String equality alone would miss the
dated sibling a name collision forces (§1.6 of origin-goal), re-select the
workstream, and redo work already sitting in the PR — that is the one case the
match has to accommodate, and the dated form is the only shape it takes. A
looser prefix match counts a workstream twice the moment it has any other
branch of its own: the shelf, the shelf cap, the stop reason and the digest's
shelf table all come out wrong, and the shelf is defined as what this
reconstruction produces, so nothing contradicts the number. Filing branches
therefore live outside this namespace (see Improvement observations). When a
PR's head branch cannot be attributed to any workstream, say so in the digest
rather than assuming the shelf is empty. Every match starts this run already
shelved, counts against the shelf cap, and is never selected.
The inverse case is real too, and this check is where it has to surface: a
workstream branch that exists with unmerged commits and has no open PR. The
shelf rule reads from PRs to branches, so on its own it reports an empty shelf
and says nothing about the leftover — and the branch is then discovered only
when that workstream is selected, mid-iteration, as a bare
fatal: a branch named ... already exists. List those branches here as
leftovers, in the inventory and the journal. They are not shelved and do
not count against the shelf cap: nothing is awaiting review. Do not act on
them either — deciding what a leftover branch is worth belongs to
origin-goal's stale-branch rule at execution time, which salvages, cuts from
the default branch, and rewrites the record. This check only makes sure the
leftover is known before it can surprise an iteration.
Match on the branch, not on a pr: field in the workstream: the PR number
only exists after the push that creates it, so recording it would need a
second commit and break origin-close-session's one-self-consistent-commit
ordering. The branch name is known before any of that and is just as
decisive. The digest still carries the PR link for the human.
This step exists because the shelf has no other durable home. A workstream
parked at a review gate records that fact on its own unmerged branch, so
the default branch still shows it as active with its issues pending — a
later run that trusts only the default branch will select it again and redo
work that is already sitting in a PR. The open PR is the durable fact (the
same reasoning that keeps run logs out of the repository: durable facts live
in workstreams, PRs, and issues), so the shelf must be read from it rather
than kept in a journal that dies with the session.
Merge policy. Confirm how PRs land. The default is continuous delivery:
a PR whose recorded quality gates are green (CI when present, otherwise the
workstream's recorded local gates) is merged autonomously by
origin-close-session — this is what keeps the loop looping. Honor a
workstream whose envelope explicitly marks merge as human-gated (it becomes
a review gate, below), but point it out here so the user can lift it by
editing the workstream if CD is what they actually want.
Permission check. Anticipate the commands the queue will need (tests,
package scripts, gh, and — whenever any workstream's merge policy is CD —
git worktree add and git worktree remove, which the independent review in
step 3 of each iteration requires by name) and check them against both
permission lists
in every settings layer that applies (user, project, and local — e.g.
~/.claude/settings.json, .claude/settings.json,
.claude/settings.local.json). The two lists fail in different ways and
need different handling:
Allowlist gaps. An unattended run dies silently on a permission
prompt, so fill gaps now: propose the additions, get the user's approval,
and record them in settings before starting. Never loosen permissions
autonomously.
Writing to settings is the human's act, and no other agent's
authorization substitutes for it. When this preflight runs without a
human to ask — invoked by another agent, or in a non-interactive
runtime — do not write settings and do not treat the check as skipped.
Take the missing command's measure instead: run it once, harmlessly, and
see whether it is actually blocked. If it runs, the gap was theoretical;
record in the journal that it was verified by execution rather than by
settings, and proceed. If it is genuinely blocked, that is a question
gate — persist it and stop before the first iteration, where the cost is
one message rather than a dead unattended run.
Deny collisions. A command matched by a deny rule cannot be
unblocked by adding an allow entry — deny is a deliberate guardrail, and
relaxing it is a different, heavier human decision. Do not propose
removing deny rules. Instead, downgrade the runnability of every issue
whose core work needs that command to gated, record the matching deny
rule as the reason, and raise it in this preflight conversation so the
user can either drop the issue from the run or decide separately to
change the guardrail. Catching this here costs one question; catching it
mid-run costs a wasted iteration.
Auto-promotion bounds. Confirm the bounds for promoting improvement
issues to workstreams without a question (see Improvement observations).
Default — all conditions AND, expansion is human-only:
- it is a repo improvement (loop-process improvements are never promoted);
- it only touches docs, development scripts, tests, or in-repo tooling —
nothing that alters production behavior, public APIs, package
boundaries, or releases;
- no new dependencies, no external sends, no metered cost;
- its runnability is
ready;
- at most 3 auto-promotions per session; overflow waits for triage.
Stop conditions. Defaults, adjustable here: a maximum of 10 iterations,
and a review shelf cap of 3 workstreams (see Stop discipline). On the
first run in a repository, recommend a pilot cap of 2 iterations
instead: it proves workstream quality, permissions, and CD wiring cheaply
before committing tokens to a full unattended run. This is a recommendation —
a cap the human states explicitly wins, and the run records that the pilot
suggestion was overridden. Do not add loop-level
time/token/cost ceilings — each workstream's Authorization Envelope
already owns its resource limits, and a second guardian invites
conflicting accounting.
Data-gated coverage. Survey whether the repository has tests that skip
when data that exists only locally and is gitignored is absent, and record
both the guarded paths and which checkout holds that data — normally the
primary checkout, never a fresh worktree. The survey is mechanical: grep the
test tree for skip conditions that guard on a path (skipif, skipUnless,
skipIf and equivalents), then run the guarded paths through
git check-ignore. Record the result in the journal; step 3 of each
iteration reads it.
The check exists because that kind of skip is invisible to every surface
this loop trusts. In one run a PR merged with a 6/6 green branch gate and
three independent reviews, all green, and turned the default branch red
immediately: the three tests that would have caught it were skipped for a
gitignored data directory that no worktree has, and the two defects — a
keyword-only stub called positionally, and a dataclass field left at its
None default — are perfectly well-typed, so the typechecker was clean too.
The post-merge gate on the default branch was the only detector, which is to
say the only detector ran after the merge.
Default: when the survey finds nothing, record "no data-gated tests" and
step 3 gains no extra work. When no human is there the survey still runs —
nothing in it needs a decision — and the data-bearing checkout defaults to
the directory this skill was pointed at, unless that directory is itself a
linked worktree (git rev-parse --git-common-dir points outside it), in
which case no known checkout has the data: say so in the digest and treat
every iteration that touches data-gated coverage as human-gated for the rest
of the run.
Each iteration — one workstream
Select. Runnability is judged at issue granularity: a workstream is
startable when its next pending issue is ready; never execute a
gated issue. A workstream that depends on a shelved workstream is not
independent — skip it. A workstream with an open PR is already on the shelf
— skip it too (see Preflight inventory). If nothing startable remains
outside the shelf, surface the nearest gate as the stopping question.
When several workstreams are startable, order them by these rules, in
order, and record the deciding rule as the one-line selection reason:
- Workstreams that cannot end the run come first. A workstream whose
remaining issues are all
ready and whose merge policy is CD can only
finish and merge. Take those before anything else.
- Then workstreams that consume a shelf slot — a
gated merge policy
ends that workstream at a review gate and moves the loop one step closer
to the shelf cap.
- Last, workstreams with a known
gated issue downstream, because
reaching it stops the entire loop. Everything startable should have had
its turn first.
- Tie-break by the order of the index's active list, which is stable
and human-visible, so the same queue always produces the same run.
The principle is defer whatever ends the run: within one iteration budget,
the most work is drained when the run-enders go last. Order is not a detail —
the same queue and the same cap produce completely different outcomes
depending on what is picked first, so leaving it to the runner's judgement
makes a run unrepeatable and its coverage accidental. A human may override
the order at preflight; nothing here needs per-iteration approval.
Execute via origin-goal, through the workstream's consecutive ready
issues. The workstream's Authorization Envelope and Human Gates are already
recorded, so its preflight must reuse them without re-interviewing. Its
3-strike failure rule and stop discipline apply unchanged. Stop the
workstream's run when its next issue is gated. Reaching a gated issue ends
the work, not the iteration: continue through steps 3–5 to land what is
already green, and stop the loop after step 5.
Close via origin-close-session. Under the CD merge policy (the
default), obtain an independent review before the autonomous merge: a
fresh-context reviewer (the /code-review skill or a reviewer subagent)
that has not seen this iteration's reasoning — a reviewer inside the same
context inherits the same blind spots, and this review is what justifies
merging without a human.
The reviewer must be able to run the workstream's recorded quality gates,
not merely read the diff, and must not disturb the working tree to do it.
Give it a subagent type that has shell access, tell it to execute the gates,
and tell it to do so in its own checkout —
git worktree add --detach <tmpdir> <PR head sha>, or an equivalent
isolated copy. Pass --detach and a sha rather than the branch name: the
loop is standing on that branch, and git refuses to check the same branch
out twice, so the branch form of the instruction cannot be followed as
written. Tell it to retire that checkout with
git worktree remove --force <tmpdir> when the gates are done — the obvious
alternative, deleting the directory recursively, matches a common deny rule and
is refused, and a reviewer left to guess reaches for it. A creation
instruction without a teardown instruction leaves worktrees behind.
A shell-capable
reviewer left to its own devices will git checkout the PR head in the
shared tree, which moves the branch the loop itself is standing on and can
leave behind a branch that squash-merge makes undeletable by git branch -d.
The capability and its bound belong together. if the runtime offers no such reviewer,
run the gates yourself and hand it the real output. A reviewer without a
shell will not refuse — it will read what it can reach, reason about what
the tests would do, and return a pass by inference. That verdict is then
the sole evidence for merging without a human, and it was never evidence at
all.
Make the reviewer return evidence, not a verdict. Require the literal gate
command lines, their exit codes, and the sha it checked out, and compare that
sha to gh pr view <n> --json headRefOid before accepting the pass. Asking the
reviewer to declare whether it executed or inferred leaves the one thing that
authorizes an unattended merge resting on a self-report — and the journal it
goes into dies with the session, so nothing that outlives the run can tell an
executed pass from an inferred one. Carry review: executed|inferred plus the
PR link into the digest's workstream row, where the human can see it, and treat
an inferred pass as human-gated rather than merging on it.
Execute the data-gated tests in the checkout that holds the data, before
the merge. When this iteration's change touches code covered by tests the
preflight's survey recorded as data-gated, run those tests once in the
recorded data-bearing checkout — while it is still standing on the PR head —
and carry the command, its exit code, and how many actually ran (not skipped)
into the digest's workstream row. The reviewer's run does not satisfy
this. The reviewer is required to work in a fresh git worktree, and
gitignored data is by construction absent there, so its green is the branch
gate's green re-produced: the same skip, counted twice. That identity is the
whole problem — branch gate, reviewer worktree, and typechecker are blind in
exactly the same way, so leaving the worktree is the only way to obtain
evidence. Budget the time (13 minutes in the incident cited at preflight
check 6) rather than trading it away. If that checkout is unreachable or the
tests cannot be run there, do not merge on a skipped pass: the workstream is
human-gated and goes to the shelf.
Fix confirmed findings within the iteration; a
finding that needs a human decision is a question gate. With gates green
and the review passed, the PR merges autonomously, so every finished
workstream lands on a clean, merged main before the next begins. Under a
human-gated merge policy, stop after the PR exists — that workstream has
reached a review gate and goes to the shelf.
Merging and retiring the branch are two steps, not one flag. Merge with
gh pr merge <n> --squash alone, and retire the remote branch afterwards as
a separate, explicit step. A merge that also carries --delete-branch reads
as a destructive operation and is the form most often refused by a permission
classifier, which strands an autonomous run one step short of done; keeping
the two apart keeps the refusable surface small.
If the merge is refused anyway, that is a question gate: leave the PR
open, leave the branch alone, persist the refused command and the PR number,
and stop. An open PR with green gates is already a legal end state under the
gated path, so a refusal costs one human message rather than the run.
After the run's last merge, re-run the recorded gates once on the default
branch and report the result in the digest. Every iteration's gates ran
against the main it branched from, and main moves several times during a
run — the preflight drift issue, each iteration's filing PRs, any promoted
workstream. Nothing re-checks the combined state: the merge does not, and
verification happens before it. This skill already reasons the point through
for the shelf ("three independently green PRs say nothing about the state
after all three land") and the CD path has the same staleness with no CI to
catch it. One run of the gates at the end is the difference between reporting
"3 workstreams done" and knowing it.
Re-read a workstream file before any edit that follows an edit to one of its
markdown tables. A formatter re-pads a table's columns to its widest cell, so
changing one cell rewrites the whitespace of every other row, and the next edit
— its target copied from before the reformat — fails to match. When several
cells in one table need changing, rewrite them in a single pass instead of one
edit per row. This costs an iteration nothing when expected and several failed
edits when not; every workstream close touches the Issue Queue table.
Observe. File improvement observations (below), bounded per iteration.
Also close the lesson loop on failures: when a failure was diagnosed and
fixed during this iteration, ask whether the lesson generalizes. If it
does and encoding it is within the envelope (a guide line, a repo
convention note, a config default), encode it in the same iteration;
otherwise file it as an improvement issue. A failure fixed only in place
will be re-fixed from scratch by a later iteration.
Journal. Append one entry: workstream id, outcome, PR link, selection
reason, observation count, and turns/tokens when the runtime exposes them
(/goal, /usage) — that is what lets the human tune iteration caps and
model routing later.
Stop discipline — two kinds of gate
Gates are not all alike, and the distinction decides whether the loop
survives:
- Question gate — a decision, missing input, or new permission is needed
before work can proceed (an escalation, a 3-strike failure, a
gated issue
reached, an unforeseen permission prompt). Persist the exact question in the
workstream first (origin-goal already does this), close out the current
iteration (steps 3–5), then stop the entire loop. Parking an unanswered
decision and starting more work would accumulate choices the human never
sequenced; abandoning green, reviewed work unmerged would discard finished
output for no gain. What the gate forbids is new work, not the landing of
work already done.
- Review gate — the workstream's work is finished and pushed as a PR;
only human review/merge blocks further progress in that workstream (a
human-gated merge policy, a recorded slice-review gate). Move the
workstream to the review shelf (record the pending PR in the journal)
and continue with the next independent ready workstream. This is safe
precisely because nothing unanswered accumulates — only finished,
independent work awaiting review.
The shelf is bounded: at most 3 shelved workstreams (preflight-adjustable).
Reaching the cap stops the loop — the human's review budget, not the queue,
is the scarce resource, and one batched review beats ten interruptions.
Every shelved PR was verified alone. Each one's gates ran against the
default branch plus that one change, because that is the only state that
existed when it was built. Three independently green PRs therefore say nothing
about the state after all three land — and where a repository has no CI, the
fallback to local gates means nothing re-checks them at merge time either. Say
so in the digest's shelf table rather than presenting green PRs as ready: for
each shelved PR record that its gate result is isolated, and make the next
action a combined verification (merge them into one integration branch, or
merge sequentially re-running the gates after each) rather than a bulk merge.
Do not merge shelved PRs on the loop's own authority — they are shelved
precisely because a human owns that decision.
Also stop the entire loop when the queue is exhausted (no startable
workstream outside the shelf) or the iteration limit is reached. On every
stop, produce the final digest — including the shelf, so pending reviews are
presented in one batch.
Report what you did not do
A prescribed step you skipped, simplified, or replaced with something lighter
goes in the journal entry and the digest, named, with the reason. So does a step
that ran and did nothing. This is not a confession requirement; it is the only way
the run's report can be read as evidence. A report that lists what happened and
omits what did not is true in every line and still wrong overall, and the reader
has no way to tell — one run executed the Stage 1 survey once across three
iterations and its own report did not mention it, which surfaced only because
someone asked.
The rule applies hardest to anything downstream authorization rests on: the
quality gates, the independent review, the survey that feeds a deletion plan, and
the validator. If one of those was skipped, inferred, or run against a different
target, the conclusions built on it are unsupported, and only this line says so.
A skipped test is not a passed test, and N passed, M skipped reads as
green. When a gate run this iteration skipped tests that cover code the
iteration changed, name them and the reason for the skip (missing local data,
missing marker, unavailable service) in the journal entry and the digest. The
summary line is a count; it is not evidence of coverage.
Improvement observations
While executing, notice friction: stuck points, repeated manual steps, the
same helper being rebuilt across workstreams. Record these as standalone
issues in docs/issues/ (via origin-doc-update's improvement-issue
convention) instead of interrupting the run. File every observation as an
issue before the digest is produced — filing is a docs-only autonomous
action; an observation that exists only in the digest text is lost the moment
the chat scrolls away, which is exactly the silent loss this mechanism
exists to prevent. Only promotion to a workstream is bounded, never the
filing itself.
- Two scopes, named apart.
ISSUE-YYYYMMDD-improve-<slug> targets the
repository itself; ISSUE-YYYYMMDD-improve-loop-<slug> targets the loop
machinery (this skill and the skills it composes, canonical in
~/.agents/skills/). The scopes have different owners and approval paths,
so the name must reveal the scope at a glance.
- Bounded. Deduplicate mechanically against existing issue slugs/titles
(no LLM judgment), and file at most 2 observations per iteration. An
unbounded observer drowns the triage queue and its own signal. The bound
counts observations, so an issue another clause ordered you to file — the
preflight drift issue, for instance — does not consume it. Preflight is not an
iteration and has no allowance of its own.
- Named for attribution, outside the shelf's namespace. Name a filing branch
obs/<ws-id>-<slug>, and a preflight filing obs/preflight-<slug>. The
workstream id makes the PR attributable to the iteration that produced it; the
obs/ prefix keeps it out of the range shelf reconstruction matches, which is
<ws-id> or <ws-id>-<YYYYMMDD> exactly. Both properties are needed: a branch
named only for the observation is unattributable, and a later run reports it as
a PR belonging to nothing — while a branch named so that the shelf claims it
makes the workstream look shelved when it is not, which is worse, because the
shelf count is what the human reads and nothing contradicts it. If such a PR is
still open at the next preflight, report it as a leftover rather than shelving
it.
- Auto-promotion. A repo improvement meeting all preflight bounds may be
promoted to a workstream via
origin-doc-update without a question — cite
the preflight approval as its confirmed boundary — and joins the tail of
the queue. Everything else (including every loop-process improvement) stays
an issue for human triage; loop-process changes are applied later by a
human through origin-skill-commonize.
Scheduled runs
Pairing this skill with /schedule (e.g. a nightly run) turns it into a
proactive loop in the official loop taxonomy. No design change is needed —
the question-gate full stop already makes unattended runs fail safe, and the
review shelf becomes the morning inbox: the human wakes to a batch of
finished PRs and filed observations instead of a stalled session. Match the
schedule to how fast the queue actually refills — a loop that wakes hourly
against a queue that refills weekly burns tokens on empty preflights.
Journal and final digest
Keep the journal as an append-only file in the session scratchpad — one entry
per iteration, written as it happens. Never reconstruct the run from the
transcript afterwards; incremental appending is what keeps reporting cheap.
The repository keeps no run log: durable facts live in the workstreams, PRs,
and issues the run already produced.
On any stop, report in chat with this fixed shape — pointers plus one-line
outcomes, never content copies:
TLDR: <n> ws done, <s> on review shelf, <stopped why>, <k> improvements filed (<m> auto-promoted)
| ws | outcome | PR |
レビュー待ち: | ws | PR | 何を承認すると何が進むか | gate: isolated | ← shelf; omit when empty
(2 本以上あるときは「統合後は未検証」と次のアクションに統合検証を明記)
停止理由: <question + where it is persisted, or "queue empty" / "shelf cap" / "iteration limit">
improvement: <filed issue ids, triage-pending marked>
次のアクション: <single next step, e.g. "review the shelf PRs, then rerun /origin-ws-loop">
Token efficiency
- Per iteration read only
docs/00_index.md and the selected workstream (plus
what origin-goal itself requires). Never rescan all of docs/.
- The digest points; it does not duplicate. Workstream/PR/issue bodies are the
record.
- Route read-heavy inventory or search subtasks to cheaper model tiers, as
origin-goal already prescribes for subagents.
Never during this skill
- initialize a docs scaffold, create a spec, or interview for a new
workstream boundary (except citing the preflight approval for an in-bounds
auto-promotion);
- execute a
gated issue or answer a gate question by guessing;
- start new work after a question gate has arisen — no further issue in the
current workstream, no next workstream. Closing the current iteration
(review, merge what is already green, observe, journal) is not continuing;
it is how the iteration ends. A review gate shelves the workstream; it never
excuses executing another issue inside it;
- put anything with an unanswered decision on the review shelf — the shelf is
for finished work awaiting review only;
- leave an improvement observation unfiled (digest text is not a record) —
except on a Prerequisites refusal, where reporting in the digest is the
defined destination;
- edit skills or anything under
~/.agents (loop-process improvements are
recorded, not applied);
- loosen permissions, bypass hooks, or take any action the composed skills'
own safety contracts would forbid.
1---2name: origin-ws-loop3description: Autonomously drain a repository's queue of active workstreams in one continuous run: pick the next workstream, execute it via origin-goal, close it via origin-close-session (merging green PRs autonomously under the default CD merge policy), park finished-but-unreviewed workstreams on a bounded review shelf, accumulate improvement observations as filed issues, and stop the entire loop the moment any human question arises. Use whenever the user wants accumulated workstreams processed in bulk or wants work to continue unattended until human input is needed, e.g. "wsを一気に消化", "溜まったws を処理して", "キューを回して", "自律で進められるところまで進めて", "run the ws queue", "drain the backlog", "process all workstreams", or /origin-ws-loop — typically right after mass-creating workstreams with origin-grill / origin-doc-update. Requires docs governance (docs/00_index.md + docs/workstreams/). Do NOT use for a single workstream (use origin-goal directly), for creating workstreams or specs (use origin-doc-update / origin-grill), or for recurring sche4---56# origin-ws-loop78Drain the workstream queue; stop at the first human question. This skill is an9orchestrator in the mold of `origin-close-session`: it owns no destructive10behavior of its own. Execution belongs to `origin-goal`, closeout to11`origin-close-session`, and workstream/issue creation to `origin-doc-update` —12each keeps its own safety contract, and this skill must not replicate or13shortcut their procedures. The only logic this skill owns is **selection**,14**observation**, and the **journal**.1516One loop iteration = one workstream's run of consecutive ready issues. Safety17over throughput: efficiency comes from workstreams being created question-free18(runnability at issue granularity, a CD merge policy) and from shelving19finished-but-unreviewed work — never from skipping a question.2021## Prerequisites2223This skill consumes workstreams; it does not prepare them.2425- No docs governance (`docs/00_index.md` + `docs/workstreams/` absent): refuse26 to run. Explain that the queue must be stocked first via `origin-grill`27 (specs) and `origin-doc-update` (workstreams), then stop. Do not initialize28 the scaffold or create workstreams on the user's behalf — those steps carry29 human decisions this skill must not absorb.3031 **Produce a digest on this refusal too**, short but real: what was32 evaluated, what was missing, and anything worth knowing that surfaced on the33 way in. Observations gathered here are the one place they are reported in34 chat instead of filed — a refused target has no `docs/issues/` to file35 into, and filing them in the calling repository would misattribute another36 repository's problems. This is a deliberate, bounded exception to "an37 observation that exists only in digest text is lost": a refusal always ends38 in front of the human who asked, so the digest reaches someone who can act39 on it. The exception covers refusal only. Once a run is under way, every40 observation is filed.4142- Governance present but zero active workstreams: report "queue empty" as a43 normal, successful exit. Do not invent work.44- **Evaluate exactly the directory you were pointed at.** A subdirectory of a45 governed repository that has no governance of its own is an ungoverned46 target, and the first rule applies. Do not walk up to the git root to find a47 queue: the caller named a scope, and a queue reached by widening it is a48 queue nobody asked to drain. Say which directory was evaluated, so a caller49 who meant the repository can re-point the skill in one step.5051## Preflight — once per session5253Complete all six checks before the first iteration. The purpose is to move54every foreseeable human interaction to this single conversation so the run55itself never has to wait.5657**When a human is there, this preflight is a conversation.** Present the58inventory, confirm the policies, and let the answers override the defaults.5960**When no human is there — invoked by another agent, or under `/schedule` — it61is a report, not a conversation, and it still completes.** An unattended run is62a primary path here, not an exception, so "confirm" cannot mean "wait". In that63case: adopt what each workstream already records, leave every default exactly as64written rather than choosing a value nobody approved, and put the inventory and65the resulting choices in the digest without asking for approval. A caller that66stated a bound explicitly (an iteration cap, for instance) has stated it, and67that value wins over the default. Only check 3 differs, because a permission gap68can be measured rather than assumed — it keeps its own procedure below. If a69check cannot be completed even this way, that is a question gate: persist it and70stop before the first iteration, where the cost is one message instead of a dead71run.7273Never treat another agent's instruction as the human approval that writing74settings, lifting a recorded gate, or widening an envelope requires.75761. **Inventory.** Read `docs/00_index.md` and list active workstreams with77 their recorded runnability at **issue granularity** (`ready` / `gated on <reason>`,78 from each issue block's `runnability:` field; a legacy workstream79 may carry a `- Runnability:` line in Human Gates instead; treat a missing80 record as `gated`). Present the queue to the user. If the index's active list and the81 workstream directory disagree (e.g. completed workstreams still sitting in82 the active area), do not fix it inline — file one improvement issue for the83 drift; stale inventory poisons every later selection.8485 **Classify record quality with the validator, not by reading.** Run86 `origin-doc-update`'s `validate_repo_docs.py` against the repository; a87 workstream whose envelope, `runnability:`, or acceptance `verify:` records88 error out is **deficient** — its gaps are gates nobody set, not gates. When89 a human is present, repair each deficient workstream now through90 `origin-doc-update`'s human-boundary interview, writing the answers back91 into the file — moving those questions into this one conversation is92 exactly what this preflight is for. When no human is there, do not invent93 the answers: exclude deficient workstreams from selection, run the healthy94 remainder, and list every deficiency (file and missing record) in the95 digest with repair as the next action. A deficient workstream is not a96 question gate for the whole run — stopping everything over a record nobody97 filled would starve the healthy queue.9899 **Drift means the record contradicts reality, not that a workstream is100 further along than its status.** A workstream whose every issue is done, whose101 PRs are merged, and whose `next_human_gate` has **not** been reached is102 correctly `active`: the gate is the thing still outstanding, and archiving it103 would be the error. Read the gate before calling it drift. It is drift when the104 gate has been reached and recorded and the workstream is still sitting in the105 active area, or when the index and the directory disagree about which106 workstreams exist at all. Getting this wrong costs an issue filed against107 correct behaviour, which teaches the next reader to distrust the check.108109 **Land that issue on its own branch with its own PR, and merge it110 autonomously** — it is docs-only, so nothing gates it. Preflight runs before111 any workstream branch exists, so the alternatives are both wrong: committing112 straight to the default branch is a heavier act than a docs file warrants,113 and folding the file into the first iteration's workstream branch charges it114 to an envelope that never approved it and, under a gated merge policy, leaves115 it unlanded until a human merges something unrelated.116117 **The index's frontmatter is in scope for this check, not just its body118 lists.** An index that carries mutable state — a `current_focus` naming how119 many workstreams are active, or which one is next — can contradict the120 directory exactly as a stale body list can, and it is read first, so it121 misleads first. Only check what is checkable without interpretation:122 counts, ids, and statuses stated outright. Free prose about direction is123 not drift and is not this check's business. One issue covers all drift124 found, frontmatter and body together.125126 **Then reconstruct the review shelf from open PRs**, before selecting127 anything: list the repository's open PRs and match them to workstreams by128 branch name (`gh pr list` reports `headRefName`; a shelved workstream always129 still has its branch, because its PR is open). **Match `<ws-id>` or130 `<ws-id>-<YYYYMMDD>`, and nothing else.** String equality alone would miss the131 dated sibling a name collision forces (§1.6 of `origin-goal`), re-select the132 workstream, and redo work already sitting in the PR — that is the one case the133 match has to accommodate, and the dated form is the only shape it takes. A134 looser prefix match counts a workstream twice the moment it has any other135 branch of its own: the shelf, the shelf cap, the stop reason and the digest's136 shelf table all come out wrong, and the shelf is _defined_ as what this137 reconstruction produces, so nothing contradicts the number. Filing branches138 therefore live outside this namespace (see Improvement observations). When a139 PR's head branch cannot be attributed to any workstream, say so in the digest140 rather than assuming the shelf is empty. Every match starts this run already141 shelved, counts against the shelf cap, and is never selected.142143 **The inverse case is real too, and this check is where it has to surface: a144 workstream branch that exists with unmerged commits and has no open PR.** The145 shelf rule reads from PRs to branches, so on its own it reports an empty shelf146 and says nothing about the leftover — and the branch is then discovered only147 when that workstream is selected, mid-iteration, as a bare148 `fatal: a branch named ... already exists`. List those branches here as149 **leftovers**, in the inventory and the journal. They are not shelved and do150 not count against the shelf cap: nothing is awaiting review. Do not act on151 them either — deciding what a leftover branch is worth belongs to152 `origin-goal`'s stale-branch rule at execution time, which salvages, cuts from153 the default branch, and rewrites the record. This check only makes sure the154 leftover is known before it can surprise an iteration.155156 Match on the branch, not on a `pr:` field in the workstream: the PR number157 only exists after the push that creates it, so recording it would need a158 second commit and break `origin-close-session`'s one-self-consistent-commit159 ordering. The branch name is known before any of that and is just as160 decisive. The digest still carries the PR link for the human.161162 This step exists because the shelf has no other durable home. A workstream163 parked at a review gate records that fact **on its own unmerged branch**, so164 the default branch still shows it as active with its issues pending — a165 later run that trusts only the default branch will select it again and redo166 work that is already sitting in a PR. The open PR is the durable fact (the167 same reasoning that keeps run logs out of the repository: durable facts live168 in workstreams, PRs, and issues), so the shelf must be _read_ from it rather169 than kept in a journal that dies with the session.1701712. **Merge policy.** Confirm how PRs land. The default is continuous delivery:172 a PR whose recorded quality gates are green (CI when present, otherwise the173 workstream's recorded local gates) is merged autonomously by174 `origin-close-session` — this is what keeps the loop looping. Honor a175 workstream whose envelope explicitly marks merge as human-gated (it becomes176 a review gate, below), but point it out here so the user can lift it by177 editing the workstream if CD is what they actually want.1783. **Permission check.** Anticipate the commands the queue will need (tests,179 package scripts, `gh`, and — whenever any workstream's merge policy is CD —180 `git worktree add` and `git worktree remove`, which the independent review in181 step 3 of each iteration requires by name) and check them against **both**182 permission lists183 in every settings layer that applies (user, project, and local — e.g.184 `~/.claude/settings.json`, `.claude/settings.json`,185 `.claude/settings.local.json`). The two lists fail in different ways and186 need different handling:187 - **Allowlist gaps.** An unattended run dies silently on a permission188 prompt, so fill gaps now: propose the additions, get the user's approval,189 and record them in settings before starting. Never loosen permissions190 autonomously.191192 Writing to settings is the human's act, and no other agent's193 authorization substitutes for it. When this preflight runs without a194 human to ask — invoked by another agent, or in a non-interactive195 runtime — do not write settings and do not treat the check as skipped.196 Take the missing command's measure instead: run it once, harmlessly, and197 see whether it is actually blocked. If it runs, the gap was theoretical;198 record in the journal that it was verified by execution rather than by199 settings, and proceed. If it is genuinely blocked, that is a question200 gate — persist it and stop before the first iteration, where the cost is201 one message rather than a dead unattended run.202203 - **Deny collisions.** A command matched by a `deny` rule cannot be204 unblocked by adding an allow entry — deny is a deliberate guardrail, and205 relaxing it is a different, heavier human decision. Do not propose206 removing deny rules. Instead, downgrade the runnability of every issue207 whose core work needs that command to `gated`, record the matching deny208 rule as the reason, and raise it in this preflight conversation so the209 user can either drop the issue from the run or decide separately to210 change the guardrail. Catching this here costs one question; catching it211 mid-run costs a wasted iteration.2124. **Auto-promotion bounds.** Confirm the bounds for promoting improvement213 issues to workstreams without a question (see Improvement observations).214 Default — all conditions AND, expansion is human-only:215 1. it is a repo improvement (loop-process improvements are never promoted);216 2. it only touches docs, development scripts, tests, or in-repo tooling —217 nothing that alters production behavior, public APIs, package218 boundaries, or releases;219 3. no new dependencies, no external sends, no metered cost;220 4. its runnability is `ready`;221 5. at most 3 auto-promotions per session; overflow waits for triage.2225. **Stop conditions.** Defaults, adjustable here: a maximum of 10 iterations,223 and a review shelf cap of 3 workstreams (see Stop discipline). On the224 **first run in a repository**, recommend a pilot cap of 2 iterations225 instead: it proves workstream quality, permissions, and CD wiring cheaply226 before committing tokens to a full unattended run. This is a recommendation —227 a cap the human states explicitly wins, and the run records that the pilot228 suggestion was overridden. Do not add loop-level229 time/token/cost ceilings — each workstream's Authorization Envelope230 already owns its resource limits, and a second guardian invites231 conflicting accounting.2326. **Data-gated coverage.** Survey whether the repository has tests that skip233 when data that exists only locally and is gitignored is absent, and record234 both the guarded paths and **which checkout holds that data** — normally the235 primary checkout, never a fresh worktree. The survey is mechanical: grep the236 test tree for skip conditions that guard on a path (`skipif`, `skipUnless`,237 `skipIf` and equivalents), then run the guarded paths through238 `git check-ignore`. Record the result in the journal; step 3 of each239 iteration reads it.240241 The check exists because that kind of skip is invisible to every surface242 this loop trusts. In one run a PR merged with a 6/6 green branch gate and243 three independent reviews, all green, and turned the default branch red244 immediately: the three tests that would have caught it were skipped for a245 gitignored data directory that no worktree has, and the two defects — a246 keyword-only stub called positionally, and a dataclass field left at its247 `None` default — are perfectly well-typed, so the typechecker was clean too.248 The post-merge gate on the default branch was the only detector, which is to249 say the only detector ran after the merge.250251 Default: when the survey finds nothing, record "no data-gated tests" and252 step 3 gains no extra work. When no human is there the survey still runs —253 nothing in it needs a decision — and the data-bearing checkout defaults to254 the directory this skill was pointed at, unless that directory is itself a255 linked worktree (`git rev-parse --git-common-dir` points outside it), in256 which case no known checkout has the data: say so in the digest and treat257 every iteration that touches data-gated coverage as human-gated for the rest258 of the run.259260## Each iteration — one workstream2612621. **Select.** Runnability is judged at issue granularity: a workstream is263 startable when its **next pending issue** is `ready`; never execute a264 `gated` issue. A workstream that depends on a shelved workstream is not265 independent — skip it. A workstream with an open PR is already on the shelf266 — skip it too (see Preflight inventory). If nothing startable remains267 outside the shelf, surface the nearest gate as the stopping question.268269 When several workstreams are startable, order them by these rules, in270 order, and record the deciding rule as the one-line selection reason:271272 1. **Workstreams that cannot end the run come first.** A workstream whose273 remaining issues are all `ready` and whose merge policy is CD can only274 finish and merge. Take those before anything else.275 2. **Then workstreams that consume a shelf slot** — a `gated` merge policy276 ends that workstream at a review gate and moves the loop one step closer277 to the shelf cap.278 3. **Last, workstreams with a known `gated` issue downstream**, because279 reaching it stops the _entire_ loop. Everything startable should have had280 its turn first.281 4. **Tie-break by the order of the index's active list**, which is stable282 and human-visible, so the same queue always produces the same run.283284 The principle is _defer whatever ends the run_: within one iteration budget,285 the most work is drained when the run-enders go last. Order is not a detail —286 the same queue and the same cap produce completely different outcomes287 depending on what is picked first, so leaving it to the runner's judgement288 makes a run unrepeatable and its coverage accidental. A human may override289 the order at preflight; nothing here needs per-iteration approval.2902912. **Execute** via `origin-goal`, through the workstream's consecutive ready292 issues. The workstream's Authorization Envelope and Human Gates are already293 recorded, so its preflight must reuse them without re-interviewing. Its294 3-strike failure rule and stop discipline apply unchanged. Stop the295 workstream's run when its next issue is gated. Reaching a gated issue ends296 the **work**, not the iteration: continue through steps 3–5 to land what is297 already green, and stop the loop after step 5.2983. **Close** via `origin-close-session`. Under the CD merge policy (the299 default), obtain an independent review before the autonomous merge: a300 fresh-context reviewer (the `/code-review` skill or a reviewer subagent)301 that has not seen this iteration's reasoning — a reviewer inside the same302 context inherits the same blind spots, and this review is what justifies303 merging without a human.304305 **The reviewer must be able to run the workstream's recorded quality gates,306 not merely read the diff, and must not disturb the working tree to do it.**307 Give it a subagent type that has shell access, tell it to execute the gates,308 and tell it to do so in its own checkout —309 `git worktree add --detach <tmpdir> <PR head sha>`, or an equivalent310 isolated copy. Pass `--detach` and a sha rather than the branch name: the311 loop is standing on that branch, and git refuses to check the same branch312 out twice, so the branch form of the instruction cannot be followed as313 written. **Tell it to retire that checkout with314 `git worktree remove --force <tmpdir>` when the gates are done** — the obvious315 alternative, deleting the directory recursively, matches a common deny rule and316 is refused, and a reviewer left to guess reaches for it. A creation317 instruction without a teardown instruction leaves worktrees behind.318 A shell-capable319 reviewer left to its own devices will `git checkout` the PR head in the320 shared tree, which moves the branch the loop itself is standing on and can321 leave behind a branch that squash-merge makes undeletable by `git branch -d`.322 The capability and its bound belong together. if the runtime offers no such reviewer,323 run the gates yourself and hand it the real output. A reviewer without a324 shell will not refuse — it will read what it can reach, reason about what325 the tests _would_ do, and return a pass by inference. That verdict is then326 the sole evidence for merging without a human, and it was never evidence at327 all.328329 **Make the reviewer return evidence, not a verdict.** Require the literal gate330 command lines, their exit codes, and the sha it checked out, and compare that331 sha to `gh pr view <n> --json headRefOid` before accepting the pass. Asking the332 reviewer to _declare_ whether it executed or inferred leaves the one thing that333 authorizes an unattended merge resting on a self-report — and the journal it334 goes into dies with the session, so nothing that outlives the run can tell an335 executed pass from an inferred one. Carry `review: executed|inferred` plus the336 PR link into the digest's workstream row, where the human can see it, and treat337 an inferred pass as human-gated rather than merging on it.338339 **Execute the data-gated tests in the checkout that holds the data, before340 the merge.** When this iteration's change touches code covered by tests the341 preflight's survey recorded as data-gated, run those tests once in the342 recorded data-bearing checkout — while it is still standing on the PR head —343 and carry the command, its exit code, and how many actually ran (not skipped)344 into the digest's workstream row. **The reviewer's run does not satisfy345 this.** The reviewer is required to work in a fresh `git worktree`, and346 gitignored data is by construction absent there, so its green is the branch347 gate's green re-produced: the same skip, counted twice. That identity is the348 whole problem — branch gate, reviewer worktree, and typechecker are blind in349 exactly the same way, so leaving the worktree is the only way to obtain350 evidence. Budget the time (13 minutes in the incident cited at preflight351 check 6) rather than trading it away. If that checkout is unreachable or the352 tests cannot be run there, do not merge on a skipped pass: the workstream is353 human-gated and goes to the shelf.354355 Fix confirmed findings within the iteration; a356 finding that needs a human decision is a question gate. With gates green357 and the review passed, the PR merges autonomously, so every finished358 workstream lands on a clean, merged main before the next begins. Under a359 human-gated merge policy, stop after the PR exists — that workstream has360 reached a review gate and goes to the shelf.361362 **Merging and retiring the branch are two steps, not one flag.** Merge with363 `gh pr merge <n> --squash` alone, and retire the remote branch afterwards as364 a separate, explicit step. A merge that also carries `--delete-branch` reads365 as a destructive operation and is the form most often refused by a permission366 classifier, which strands an autonomous run one step short of done; keeping367 the two apart keeps the refusable surface small.368369 If the merge is refused anyway, that is a **question gate**: leave the PR370 open, leave the branch alone, persist the refused command and the PR number,371 and stop. An open PR with green gates is already a legal end state under the372 gated path, so a refusal costs one human message rather than the run.373374 **After the run's last merge, re-run the recorded gates once on the default375 branch and report the result in the digest.** Every iteration's gates ran376 against the `main` it branched from, and `main` moves several times during a377 run — the preflight drift issue, each iteration's filing PRs, any promoted378 workstream. Nothing re-checks the combined state: the merge does not, and379 verification happens before it. This skill already reasons the point through380 for the shelf ("three independently green PRs say nothing about the state381 after all three land") and the CD path has the same staleness with no CI to382 catch it. One run of the gates at the end is the difference between reporting383 "3 workstreams done" and knowing it.384385 **Re-read a workstream file before any edit that follows an edit to one of its386 markdown tables.** A formatter re-pads a table's columns to its widest cell, so387 changing one cell rewrites the whitespace of every other row, and the next edit388 — its target copied from before the reformat — fails to match. When several389 cells in one table need changing, rewrite them in a single pass instead of one390 edit per row. This costs an iteration nothing when expected and several failed391 edits when not; every workstream close touches the Issue Queue table.3923934. **Observe.** File improvement observations (below), bounded per iteration.394 Also close the lesson loop on failures: when a failure was diagnosed and395 fixed during this iteration, ask whether the lesson generalizes. If it396 does and encoding it is within the envelope (a guide line, a repo397 convention note, a config default), encode it in the same iteration;398 otherwise file it as an improvement issue. A failure fixed only in place399 will be re-fixed from scratch by a later iteration.4005. **Journal.** Append one entry: workstream id, outcome, PR link, selection401 reason, observation count, and turns/tokens when the runtime exposes them402 (`/goal`, `/usage`) — that is what lets the human tune iteration caps and403 model routing later.404405## Stop discipline — two kinds of gate406407Gates are not all alike, and the distinction decides whether the loop408survives:409410- **Question gate** — a decision, missing input, or new permission is needed411 before work can proceed (an escalation, a 3-strike failure, a `gated` issue412 reached, an unforeseen permission prompt). Persist the exact question in the413 workstream first (`origin-goal` already does this), close out the current414 iteration (steps 3–5), then stop the **entire loop**. Parking an unanswered415 decision and starting more work would accumulate choices the human never416 sequenced; abandoning green, reviewed work unmerged would discard finished417 output for no gain. What the gate forbids is new work, not the landing of418 work already done.419- **Review gate** — the workstream's work is finished and pushed as a PR;420 only human review/merge blocks further progress in _that_ workstream (a421 human-gated merge policy, a recorded slice-review gate). Move the422 workstream to the **review shelf** (record the pending PR in the journal)423 and continue with the next independent ready workstream. This is safe424 precisely because nothing unanswered accumulates — only finished,425 independent work awaiting review.426427The shelf is bounded: at most 3 shelved workstreams (preflight-adjustable).428Reaching the cap stops the loop — the human's review budget, not the queue,429is the scarce resource, and one batched review beats ten interruptions.430431**Every shelved PR was verified alone.** Each one's gates ran against the432default branch plus that one change, because that is the only state that433existed when it was built. Three independently green PRs therefore say nothing434about the state after all three land — and where a repository has no CI, the435fallback to local gates means nothing re-checks them at merge time either. Say436so in the digest's shelf table rather than presenting green PRs as ready: for437each shelved PR record that its gate result is isolated, and make the next438action a **combined** verification (merge them into one integration branch, or439merge sequentially re-running the gates after each) rather than a bulk merge.440Do not merge shelved PRs on the loop's own authority — they are shelved441precisely because a human owns that decision.442443Also stop the entire loop when the queue is exhausted (no startable444workstream outside the shelf) or the iteration limit is reached. On every445stop, produce the final digest — including the shelf, so pending reviews are446presented in one batch.447448## Report what you did not do449450**A prescribed step you skipped, simplified, or replaced with something lighter451goes in the journal entry and the digest, named, with the reason.** So does a step452that ran and did nothing. This is not a confession requirement; it is the only way453the run's report can be read as evidence. A report that lists what happened and454omits what did not is true in every line and still wrong overall, and the reader455has no way to tell — one run executed the Stage 1 survey once across three456iterations and its own report did not mention it, which surfaced only because457someone asked.458459The rule applies hardest to anything downstream authorization rests on: the460quality gates, the independent review, the survey that feeds a deletion plan, and461the validator. If one of those was skipped, inferred, or run against a different462target, the conclusions built on it are unsupported, and only this line says so.463464**A skipped test is not a passed test, and `N passed, M skipped` reads as465green.** When a gate run this iteration skipped tests that cover code the466iteration changed, name them and the reason for the skip (missing local data,467missing marker, unavailable service) in the journal entry and the digest. The468summary line is a count; it is not evidence of coverage.469470## Improvement observations471472While executing, notice friction: stuck points, repeated manual steps, the473same helper being rebuilt across workstreams. Record these as standalone474issues in `docs/issues/` (via `origin-doc-update`'s improvement-issue475convention) instead of interrupting the run. **File every observation as an476issue before the digest is produced** — filing is a docs-only autonomous477action; an observation that exists only in the digest text is lost the moment478the chat scrolls away, which is exactly the silent loss this mechanism479exists to prevent. Only _promotion_ to a workstream is bounded, never the480filing itself.481482- **Two scopes, named apart.** `ISSUE-YYYYMMDD-improve-<slug>` targets the483 repository itself; `ISSUE-YYYYMMDD-improve-loop-<slug>` targets the loop484 machinery (this skill and the skills it composes, canonical in485 `~/.agents/skills/`). The scopes have different owners and approval paths,486 so the name must reveal the scope at a glance.487- **Bounded.** Deduplicate mechanically against existing issue slugs/titles488 (no LLM judgment), and file at most 2 observations per iteration. An489 unbounded observer drowns the triage queue and its own signal. The bound490 counts observations, so an issue another clause **ordered** you to file — the491 preflight drift issue, for instance — does not consume it. Preflight is not an492 iteration and has no allowance of its own.493- **Named for attribution, outside the shelf's namespace.** Name a filing branch494 `obs/<ws-id>-<slug>`, and a preflight filing `obs/preflight-<slug>`. The495 workstream id makes the PR attributable to the iteration that produced it; the496 `obs/` prefix keeps it out of the range shelf reconstruction matches, which is497 `<ws-id>` or `<ws-id>-<YYYYMMDD>` exactly. Both properties are needed: a branch498 named only for the observation is unattributable, and a later run reports it as499 a PR belonging to nothing — while a branch named so that the shelf claims it500 makes the workstream look shelved when it is not, which is worse, because the501 shelf count is what the human reads and nothing contradicts it. If such a PR is502 still open at the next preflight, report it as a leftover rather than shelving503 it.504- **Auto-promotion.** A repo improvement meeting all preflight bounds may be505 promoted to a workstream via `origin-doc-update` without a question — cite506 the preflight approval as its confirmed boundary — and joins the tail of507 the queue. Everything else (including every loop-process improvement) stays508 an issue for human triage; loop-process changes are applied later by a509 human through `origin-skill-commonize`.510511## Scheduled runs512513Pairing this skill with `/schedule` (e.g. a nightly run) turns it into a514proactive loop in the official loop taxonomy. No design change is needed —515the question-gate full stop already makes unattended runs fail safe, and the516review shelf becomes the morning inbox: the human wakes to a batch of517finished PRs and filed observations instead of a stalled session. Match the518schedule to how fast the queue actually refills — a loop that wakes hourly519against a queue that refills weekly burns tokens on empty preflights.520521## Journal and final digest522523Keep the journal as an append-only file in the session scratchpad — one entry524per iteration, written as it happens. Never reconstruct the run from the525transcript afterwards; incremental appending is what keeps reporting cheap.526The repository keeps no run log: durable facts live in the workstreams, PRs,527and issues the run already produced.528529On any stop, report in chat with this fixed shape — pointers plus one-line530outcomes, never content copies:531532```533TLDR: <n> ws done, <s> on review shelf, <stopped why>, <k> improvements filed (<m> auto-promoted)534| ws | outcome | PR |535レビュー待ち: | ws | PR | 何を承認すると何が進むか | gate: isolated | ← shelf; omit when empty536 (2 本以上あるときは「統合後は未検証」と次のアクションに統合検証を明記)537停止理由: <question + where it is persisted, or "queue empty" / "shelf cap" / "iteration limit">538improvement: <filed issue ids, triage-pending marked>539次のアクション: <single next step, e.g. "review the shelf PRs, then rerun /origin-ws-loop">540```541542## Token efficiency543544- Per iteration read only `docs/00_index.md` and the selected workstream (plus545 what `origin-goal` itself requires). Never rescan all of `docs/`.546- The digest points; it does not duplicate. Workstream/PR/issue bodies are the547 record.548- Route read-heavy inventory or search subtasks to cheaper model tiers, as549 `origin-goal` already prescribes for subagents.550551## Never during this skill552553- initialize a docs scaffold, create a spec, or interview for a new554 workstream boundary (except citing the preflight approval for an in-bounds555 auto-promotion);556- execute a `gated` issue or answer a gate question by guessing;557- start new work after a question gate has arisen — no further issue in the558 current workstream, no next workstream. Closing the current iteration559 (review, merge what is already green, observe, journal) is not continuing;560 it is how the iteration ends. A review gate shelves the workstream; it never561 excuses executing another issue _inside_ it;562- put anything with an unanswered decision on the review shelf — the shelf is563 for finished work awaiting review only;564- leave an improvement observation unfiled (digest text is not a record) —565 except on a Prerequisites refusal, where reporting in the digest is the566 defined destination;567- edit skills or anything under `~/.agents` (loop-process improvements are568 recorded, not applied);569- loosen permissions, bypass hooks, or take any action the composed skills'570 own safety contracts would forbid.