Toolshed
Working state that survives sessions and models — but not the task.
Everything in docs/work/<slug>/ dies at close. Survivors are formal genres
(ADR, spec, RFC) authored from deliverable-shaped records.
"BS if we keep it; under the same feature it is gold."
Path stays under docs/: docs/work/<slug>/. The skill name is toolshed.
Name collision (read this)
| Name |
What it is |
Path / surface |
| Toolshed (this skill) |
Mortal task state |
docs/work/<slug>/, skill toolshed, /toolshed |
| Workbench (product) |
Ops app: Slack/highlights/memory + MCP |
altpay/workbench, mcp_servers.workbench |
If the user says "update the workbench" without a slug or docs/work path,
ask which one (product vs toolshed) before writing.
The law (non-negotiable)
The laws bind the agent, not the owner. An owner may waive a law: the
waiver is recorded in docs/work/TOOLSHED.md (the survivor file — never the
mortal folder) as law N waived for <slug>: <reason, date>, and the agent
states the consequence once, then complies. Silent erosion and standoffs
are both failures.
- Mortality. Folder deleted in the closing PR. No archive directory.
Archive of record = the closing PR (final packet/summary in its
description) plus ≥1 commit containing the folder that reached the
default branch. Bare "git history" is not enough: under squash-merge
a folder added and deleted inside one PR leaves zero trace on main.
assert-close.sh enforces the merged-commit precondition; deliverables
still stamp the final SHA.
Why keeping it loses: kept folders drift against the ADRs they duplicate;
STATE becomes a resume surface for a task nobody resumes; and
superseded-but-decided records — correct in a ledger — read as current
guidance once they are permanent docs. Deliverables win by being the only copy.
- Slug identity, ticket optional. Never require a ticket to start.
- Boundary rule. Contract-changing decisions promote to permanent home
the moment decided — not at close, and in the same PR as the change
they govern (after-the-fact ADRs are ratification theater — the
named, documented way this practice dies). A decision made ahead of its
implementation promotes with the PR that implements it: an ADR for a
contract the code does not have is the mirror image of ratification theater.
Toolshed links to them.
Once promoted/accepted, an ADR is immutable — supersede, never edit.
Partial supersession: the amending ADR adds one pointer line to the
amended ADR's header; the amended body stays immutable.
- Evidence self-sufficiency of survivors. ADRs/specs inline dated, graded
evidence + reproduction command when the evidence lives in toolshed.
Evidence may also live in PRs, CI, other skill artifacts — toolshed
does not own all proof; point at it.
- Evidence hygiene. Aggregates, shapes, masked patterns: yes. Payloads,
customer IDs, PII: never.
- Deliverable-shaped records. Decisions are proto-ADRs (options +
flip condition). Close is a transform, not a rewrite.
- Records are upsert-only. Corrections are loud (History lines) — never
silent edits, never deletions; supersede instead.
- One slug = one branch/worktree = one active agent. No published
convention safely handles two agents writing the same
STATE.md
concurrently — don't be the experiment. Parallel agents get parallel
worktrees (and usually parallel slugs); merge via git, not via hope.
- Branch-carried preferred; local-only allowed while testing. Default
long-term: track
docs/work/ on the feature branch and commit as you
go — an uncommitted toolshed protects nothing; it dies with the working
tree. While the flow is under active change, repos may gitignore
docs/work/ — then resume is machine-local; survivors must land in
PR/permanent docs before the machine is disposable. seed.sh warns when
ignored; stale-check.sh flags never-committed and abandoned toolsheds.
- STATE is a resume surface, not a novel. Soft cap ~120 lines for
new toolsheds. No full packet, no E-appendix, no W-registry dump inside
STATE. Ledgers in D/Q/E; optional ship matrix in
packet.md.
Legacy bloated STATE (pre-toolshed / mid-flight): do not force a full
rewrite — use assert-state.sh --soft (warn) until that task closes.
- Understanding before proposal. Template Understanding = not started.
assert-started.sh must pass before design/implementation.
- Freshness. A toolshed untouched for 21+ days is presumed stale —
resume it or close it.
stale-check.sh [--strict] reports (CI-friendly).
Staleness is a smell, not a crime; the response is triage, not archive.
When modifying close/seed helpers, run both sh scripts/acceptance.sh and
python3 scripts/close-regressions.py from the skill directory before and after.
These mutate only isolated fixtures, not the user's working repository.
Close checks require Python 3.9+. A parked question needs one explicit
Home or Promoted field: an existing repo-relative permanent file outside
all docs/work/, or a remote URL. Check that the destination contains the
final question and wake-up trigger; file existence alone does not prove this.
For remote homes, read back the destination before --remote-homes-confirmed;
the flag is an attestation, not an API check.
For ignored/local-only toolsheds, --pr-body-confirmed can clear the Git archive
gate only after reading back a PR body containing the final local records.
A promised future copy, stale snapshot or link into the folder is insufficient.
This does not authorize PR publication or deletion; reuse existing authorization
or request the missing scope. Tracked toolsheds still require their clean final
commit. Keep the source folder whenever preservation remains uncertain.
Evidence grades: MEASURED · CONFIRMED · REPORTED · UNRESOLVED.
Composition (not the whole environment)
Toolshed is one shelf. Do not stuff every activity into it. Discover the skills
and tools available in the current host; the repository distributes the same skill
folders for Claude Code and Codex. If a supporting skill is unavailable, do the
needed work inline using available tools.
| Need |
Use |
| Task resume state |
toolshed |
| Adversarial review |
morpheus |
| ST/QA campaigns |
mean-qa |
| Post-deploy watch |
Project monitoring runbook and live read-only evidence |
| Incident paperwork |
incident-validator |
| Risky ops |
safe-ops |
| Off-repo note |
handoff |
| ADR/spec at close |
spec-adr-builder |
| Slack/memory product |
Workbench app (not this skill) |
| Ship evidence of record |
PR + CI + permanent docs (and/or E-NNN) |
Flows
Start — /toolshed start <slug|TICKET-123> ["goal"]
sh <skill-dir>/scripts/seed.sh <slug> ["goal"]
- Orient (mandatory): fill Understanding (exists @ file:line, assumptions
rated, unverified + how to verify). Summarize it in a progress update;
ask only when a missing decision changes the authorized scope or approach.
sh <skill-dir>/scripts/assert-started.sh <slug> — must pass.
Until it passes, the toolshed is decor. Do not implement. The script only
checks that the sentinel is gone and the section is non-empty; it cannot
judge quality. Step 2 is an evidence check, not a new approval loop for
work the user already authorized.
Work (any session, any model)
- One slug = one branch/worktree = one active agent (law 8). Give a
parallel agent a parallel worktree, and usually a parallel slug.
- Resume: read
STATE.md first, recheck its current branch/build and next
action, then run assert-started.sh. Reuse answered records; amend with a
dated History line only when new evidence changes them.
assert-state.sh <slug> on new/thin trees; use --soft on known legacy
bloated STATE (e.g. long-running EXP-class tasks).
- Tradeoffs →
decisions.md when decided (+ commit hash).
- Functionality questions →
questions.md; contracts → promote + mark
promoted.
- Measurements →
evidence.md or PR/CI/other skill artifact with a
pointer from STATE/E-record.
- Session end (default): follow
references/session-end.md only.
Update Now/Next/Blocked + one session-log line, and record the verify
and behavior changes shipped one-liners. Chat = verdict / blocker /
next gate. Do not emit a full packet.
- Full packet: only per
references/full-packet.md triggers
(explicit ask, close ritual, multi-repo ship gates). Write to packet.md
and/or chat — never into STATE.md.
- Records are upsert-only. Corrections are loud (History lines).
- Never overclaim. A record may not say it carries sources, scripts, or
harnesses unless they are in-tree and runnable — link what exists, name
what does not.
Close — /toolshed close <slug>
assert-close.sh <slug> — must pass: the folder reached the default
branch (final folder contents match it), no open questions, no parked question without
a permanent home, no proposed decisions, no placeholders, clean tree. It
also runs the started gate and assert-state.sh --soft (legacy bloat warns
loudly). --pr-body-confirmed is the only escape from the merged-commit
gate, and asserting it means you read back the actual PR body and it inlines
the final records. Unknown default branch fails closed. The script checks
local refs, not live GitHub or PR contents: pin/fetch the real default branch
first. A flag is a human/agent attestation, not independent archive proof.
- Sweep unpromoted contract decisions (highest-risk failure mode —
assert-close.sh warns when decided records carry no promotion/ADR link).
- Genre-map → ADR / spec delta / RFC / runbook (
spec-adr-builder if available).
Inline load-bearing evidence that lives here; link PR/CI evidence otherwise.
- Stamp deliverables:
Toolshed: <repo>@<sha>, docs/work/<slug>/ — the SHA
the evidence was measured at, plus "this commit" for the deliverable
itself; amending a record to chase your own new SHA is forbidden.
- Inline the final load-bearing records (decisions + key evidence) into
the closing PR description — not just a summary. After squash-merge the
branch's granular edit trail is unreachable from main, and GitHub's
refs/pull/N/head persistence is empirical, not contractual. The PR body
is the archive tier you can actually rely on.
- Optional: full packet for owner validation of multi-gate close — routing
lives in
references/closeout-packet.md
(which is also where older "closeout packet" references land).
- Delete
docs/work/<slug>/ in the closing PR; leave docs/work/TOOLSHED.md
(seed.sh migrates legacy WORKBENCH.md files to the new name).
- Review the final diff. Push or publish the closing PR only if authorized;
reuse existing scoped authorization under
safe-ops. Closing is not merging.
STATE.md shape (hard for new toolsheds)
Allowed sections only:
- Header (goal, ticket, opened, status, verified, behavior changes shipped —
one line each)
- Understanding
- Now / Next / Blocked (short bullets — point at D/Q/E/PR IDs)
- How to verify (runnable commands)
- Session log (one line per session)
Everything else belongs in D/Q/E or packet.md, not in STATE.
assert-state.sh does not parse that section list — it spot-checks the
line count (soft cap 120) and the telltale dump patterns (full-packet headings,
W-NNN registries, E-NNN evidence appendices). Passing it is evidence
against bloat, not proof the shape is right; the list above is the contract.
Template map
| File |
Role |
TOOLSHED.md |
convention once per repo (legacy WORKBENCH.md auto-migrated by seed.sh) |
STATE.md |
resume surface (thin) |
decisions.md |
proto-ADRs D-NNN |
questions.md |
Q-NNN upsert-only |
evidence.md |
E-NNN + reproduce |
packet.md |
optional full ship packet (not seeded) |
Scripts
| Script |
Job |
seed.sh |
create tree + pointers; migrate legacy WORKBENCH.md (v2.1) |
assert-started.sh |
Understanding gate (fail fast) |
assert-state.sh |
STATE shape / anti-novel (--soft for legacy) |
assert-close.sh |
close gate: folder reached the default branch, no open Q / homeless parked Q / proposed D, clean tree; runs started + state (--soft) gates (--pr-body-confirmed waives the merge check) |
stale-check.sh |
freshness report: stale / never-committed toolsheds (--strict for CI) |
acceptance.sh |
self-test: walks seed → gates → close → hostile input in a throwaway repo |
What this skill is not
- Not for work that ends this session. Do not seed for a task that will
plausibly finish this session and produces no contract-changing decision
— use inline notes / the task list. Seed at the first real resume or the
first contract decision, whichever comes first.
- Not the Workbench product/MCP.
- Not an orchestrator or the only place evidence may live.
- Not a program playbook (EXP-class permanent docs win when present).
- Not documentation to keep — write ADR/spec, delete the folder.
- Not a mandatory full closeout engine — session end is thin.
1---2name: toolshed3description: Toolshed — durable, model-agnostic working state for ONE coding task (feature, investigation) as docs/work/SLUG/ under docs/, DELETED at close. Seeds STATE + decisions/questions/evidence with grades and reproduction commands. Use for "start a toolshed", "seed the task", "/toolshed start|resume|session-end|close", or "where were we". Session end = thin STATE update. Full packet only when explicitly requested or on close/ship gates. Evidence may also live in PRs, CI, mean-qa, morpheus, monitoring runbooks — toolshed is a state shelf, not the whole environment. Pair with morpheus, handoff, safe-ops, spec-adr-builder.4---56# Toolshed78Working state that survives sessions and models — but not the task.9Everything in `docs/work/<slug>/` dies at close. Survivors are formal genres10(ADR, spec, RFC) authored from deliverable-shaped records.11*"BS if we keep it; under the same feature it is gold."*1213Path stays under **`docs/`**: `docs/work/<slug>/`. The skill name is **toolshed**.1415## Name collision (read this)1617| Name | What it is | Path / surface |18|---|---|---|19| **Toolshed** (this skill) | Mortal task state | `docs/work/<slug>/`, skill `toolshed`, `/toolshed` |20| **Workbench** (product) | Ops app: Slack/highlights/memory + MCP | `altpay/workbench`, `mcp_servers.workbench` |2122If the user says "update the workbench" without a slug or `docs/work` path,23**ask which one** (product vs toolshed) before writing.2425## The law (non-negotiable)2627The laws bind **the agent, not the owner**. An owner may **waive** a law: the28waiver is recorded in `docs/work/TOOLSHED.md` (the survivor file — never the29mortal folder) as `law N waived for <slug>: <reason, date>`, and the agent30states the consequence **once**, then complies. Silent erosion and standoffs31are both failures.32331. **Mortality.** Folder deleted in the closing PR. No archive directory.34 **Archive of record = the closing PR** (final packet/summary in its35 description) **plus ≥1 commit containing the folder that reached the36 default branch**. Bare "git history" is not enough: under **squash-merge**37 a folder added and deleted inside one PR leaves **zero trace** on main.38 `assert-close.sh` enforces the merged-commit precondition; deliverables39 still stamp the final SHA.40 *Why keeping it loses:* kept folders drift against the ADRs they duplicate;41 STATE becomes a resume surface for a task nobody resumes; and42 superseded-but-decided records — correct in a ledger — read as current43 guidance once they are permanent docs. Deliverables win by being the only copy.442. **Slug identity, ticket optional.** Never require a ticket to start.453. **Boundary rule.** Contract-changing decisions promote to permanent home46 **the moment decided** — not at close, and **in the same PR as the change47 they govern** (after-the-fact ADRs are ratification theater — the48 named, documented way this practice dies). A decision made **ahead** of its49 implementation promotes **with the PR that implements it**: an ADR for a50 contract the code does not have is the mirror image of ratification theater.51 Toolshed links to them.52 Once promoted/accepted, an ADR is **immutable** — supersede, never edit.53 **Partial supersession:** the amending ADR adds one pointer line to the54 amended ADR's **header**; the amended body stays immutable.554. **Evidence self-sufficiency of survivors.** ADRs/specs inline dated, graded56 evidence + reproduction command when the evidence lives in toolshed.57 Evidence may also live in **PRs, CI, other skill artifacts** — toolshed58 does not own all proof; point at it.595. **Evidence hygiene.** Aggregates, shapes, masked patterns: yes. Payloads,60 customer IDs, PII: never.616. **Deliverable-shaped records.** Decisions are proto-ADRs (options +62 **flip condition**). Close is a transform, not a rewrite.637. **Records are upsert-only.** Corrections are loud (History lines) — never64 silent edits, never deletions; supersede instead.658. **One slug = one branch/worktree = one active agent.** No published66 convention safely handles two agents writing the same `STATE.md`67 concurrently — don't be the experiment. Parallel agents get parallel68 worktrees (and usually parallel slugs); merge via git, not via hope.699. **Branch-carried preferred; local-only allowed while testing.** Default70 long-term: track `docs/work/` on the feature branch **and commit as you71 go** — an uncommitted toolshed protects nothing; it dies with the working72 tree. **While the flow is under active change, repos may gitignore73 `docs/work/`** — then resume is machine-local; survivors **must** land in74 PR/permanent docs before the machine is disposable. `seed.sh` warns when75 ignored; `stale-check.sh` flags never-committed and abandoned toolsheds.7610. **STATE is a resume surface, not a novel.** Soft cap ~120 lines for77 **new** toolsheds. No full packet, no E-appendix, no W-registry dump inside78 STATE. Ledgers in D/Q/E; optional ship matrix in `packet.md`.79 **Legacy bloated STATE** (pre-toolshed / mid-flight): do not force a full80 rewrite — use `assert-state.sh --soft` (warn) until that task closes.8111. **Understanding before proposal.** Template Understanding = **not started**.82 `assert-started.sh` must pass before design/implementation.8312. **Freshness.** A toolshed untouched for 21+ days is presumed stale —84 resume it or close it. `stale-check.sh [--strict]` reports (CI-friendly).85 Staleness is a smell, not a crime; the response is triage, not archive.8687When modifying close/seed helpers, run both `sh scripts/acceptance.sh` and88`python3 scripts/close-regressions.py` from the skill directory before and after.89These mutate only isolated fixtures, not the user's working repository.9091Close checks require Python 3.9+. A parked question needs one explicit92`Home` or `Promoted` field: an existing repo-relative permanent file outside93**all** `docs/work/`, or a remote URL. Check that the destination contains the94final question and wake-up trigger; file existence alone does not prove this.95For remote homes, read back the destination before `--remote-homes-confirmed`;96the flag is an attestation, not an API check.9798For ignored/local-only toolsheds, `--pr-body-confirmed` can clear the Git archive99gate only after reading back a PR body containing the **final local records**.100A promised future copy, stale snapshot or link into the folder is insufficient.101This does not authorize PR publication or deletion; reuse existing authorization102or request the missing scope. Tracked toolsheds still require their clean final103commit. Keep the source folder whenever preservation remains uncertain.104105Evidence grades: **MEASURED** · **CONFIRMED** · **REPORTED** · **UNRESOLVED**.106107## Composition (not the whole environment)108109Toolshed is **one shelf**. Do not stuff every activity into it. Discover the skills110and tools available in the current host; the repository distributes the same skill111folders for Claude Code and Codex. If a supporting skill is unavailable, do the112needed work inline using available tools.113114| Need | Use |115|---|---|116| Task resume state | **toolshed** |117| Adversarial review | `morpheus` |118| ST/QA campaigns | `mean-qa` |119| Post-deploy watch | Project monitoring runbook and live read-only evidence |120| Incident paperwork | `incident-validator` |121| Risky ops | `safe-ops` |122| Off-repo note | `handoff` |123| ADR/spec at close | `spec-adr-builder` |124| Slack/memory product | **Workbench app** (not this skill) |125| Ship evidence of record | **PR + CI + permanent docs** (and/or E-NNN) |126127## Flows128129### Start — `/toolshed start <slug|TICKET-123> ["goal"]`1301311. `sh <skill-dir>/scripts/seed.sh <slug> ["goal"]`1322. **Orient (mandatory):** fill Understanding (exists @ file:line, assumptions133 rated, unverified + how to verify). Summarize it in a progress update;134 ask only when a missing decision changes the authorized scope or approach.1353. `sh <skill-dir>/scripts/assert-started.sh <slug>` — must pass.136 Until it passes, the toolshed is decor. Do not implement. The script only137 checks that the sentinel is gone and the section is non-empty; it cannot138 judge quality. Step 2 is an evidence check, not a new approval loop for139 work the user already authorized.140141### Work (any session, any model)142143- **One slug = one branch/worktree = one active agent** (law 8). Give a144 parallel agent a parallel worktree, and usually a parallel slug.145- **Resume:** read `STATE.md` first, recheck its current branch/build and next146 action, then run `assert-started.sh`. Reuse answered records; amend with a147 dated History line only when new evidence changes them.148- `assert-state.sh <slug>` on new/thin trees; use `--soft` on known legacy149 bloated STATE (e.g. long-running EXP-class tasks).150- Tradeoffs → `decisions.md` when decided (+ commit hash).151- Functionality questions → `questions.md`; contracts → promote + mark152 `promoted`.153- Measurements → `evidence.md` **or** PR/CI/other skill artifact with a154 pointer from STATE/E-record.155- **Session end (default):** follow156 [`references/session-end.md`](references/session-end.md) only.157 Update Now/Next/Blocked + one session-log line, and record the **verify**158 and **behavior changes shipped** one-liners. Chat = verdict / blocker /159 next gate. **Do not** emit a full packet.160- **Full packet:** only per161 [`references/full-packet.md`](references/full-packet.md) triggers162 (explicit ask, close ritual, multi-repo ship gates). Write to `packet.md`163 and/or chat — **never into STATE.md**.164- Records are upsert-only. Corrections are loud (History lines).165- **Never overclaim.** A record may not say it carries sources, scripts, or166 harnesses unless they are in-tree and runnable — link what exists, name167 what does not.168169### Close — `/toolshed close <slug>`1701711. `assert-close.sh <slug>` — **must pass**: the folder reached the **default172 branch** (final folder contents match it), no open questions, no `parked` question without173 a permanent home, no `proposed` decisions, no placeholders, clean tree. It174 also runs the started gate and `assert-state.sh --soft` (legacy bloat warns175 loudly). `--pr-body-confirmed` is the only escape from the merged-commit176 gate, and asserting it means you read back the actual PR body and it inlines177 the final records. Unknown default branch fails closed. The script checks178 local refs, not live GitHub or PR contents: pin/fetch the real default branch179 first. A flag is a human/agent attestation, not independent archive proof.1802. Sweep unpromoted contract decisions (highest-risk failure mode —181 `assert-close.sh` warns when decided records carry no promotion/ADR link).1823. Genre-map → ADR / spec delta / RFC / runbook (`spec-adr-builder` if available).183 Inline load-bearing evidence that lives here; link PR/CI evidence otherwise.1844. Stamp deliverables: `Toolshed: <repo>@<sha>, docs/work/<slug>/` — the SHA185 the evidence was **measured** at, plus "this commit" for the deliverable186 itself; amending a record to chase your own new SHA is forbidden.1875. **Inline the final load-bearing records (decisions + key evidence) into188 the closing PR description** — not just a summary. After squash-merge the189 branch's granular edit trail is unreachable from main, and GitHub's190 `refs/pull/N/head` persistence is empirical, not contractual. The PR body191 is the archive tier you can actually rely on.1926. Optional: full packet for owner validation of multi-gate close — routing193 lives in [`references/closeout-packet.md`](references/closeout-packet.md)194 (which is also where older "closeout packet" references land).1957. Delete `docs/work/<slug>/` in the closing PR; leave `docs/work/TOOLSHED.md`196 (`seed.sh` migrates legacy `WORKBENCH.md` files to the new name).1978. Review the final diff. Push or publish the closing PR only if authorized;198 reuse existing scoped authorization under `safe-ops`. Closing is not merging.199200## STATE.md shape (hard for new toolsheds)201202Allowed sections only:2032041. Header (goal, ticket, opened, status, verified, behavior changes shipped —205 one line each)2062. Understanding2073. Now / Next / Blocked (short bullets — point at D/Q/E/PR IDs)2084. How to verify (runnable commands)2095. Session log (one line per session)210211Everything else belongs in D/Q/E or `packet.md`, not in STATE.212213`assert-state.sh` does **not** parse that section list — it spot-checks the214line count (soft cap 120) and the telltale dump patterns (full-packet headings,215`W-NNN` registries, `E-NNN` evidence appendices). Passing it is evidence216against bloat, not proof the shape is right; the list above is the contract.217218## Template map219220| File | Role |221|---|---|222| `TOOLSHED.md` | convention once per repo (legacy `WORKBENCH.md` auto-migrated by `seed.sh`) |223| `STATE.md` | resume surface (thin) |224| `decisions.md` | proto-ADRs `D-NNN` |225| `questions.md` | `Q-NNN` upsert-only |226| `evidence.md` | `E-NNN` + reproduce |227| `packet.md` | optional full ship packet (not seeded) |228229## Scripts230231| Script | Job |232|---|---|233| `seed.sh` | create tree + pointers; migrate legacy `WORKBENCH.md` (v2.1) |234| `assert-started.sh` | Understanding gate (fail fast) |235| `assert-state.sh` | STATE shape / anti-novel (`--soft` for legacy) |236| `assert-close.sh` | close gate: folder reached the default branch, no open Q / homeless parked Q / proposed D, clean tree; runs started + state (`--soft`) gates (`--pr-body-confirmed` waives the merge check) |237| `stale-check.sh` | freshness report: stale / never-committed toolsheds (`--strict` for CI) |238| `acceptance.sh` | self-test: walks seed → gates → close → hostile input in a throwaway repo |239240## What this skill is not241242- **Not for work that ends this session.** Do **not** seed for a task that will243 plausibly finish this session **and** produces no contract-changing decision244 — use inline notes / the task list. Seed at the **first real resume** or the245 **first contract decision**, whichever comes first.246- **Not the Workbench product/MCP.**247- **Not an orchestrator** or the only place evidence may live.248- **Not a program playbook** (EXP-class permanent docs win when present).249- **Not documentation to keep** — write ADR/spec, delete the folder.250- **Not a mandatory full closeout engine** — session end is thin.