SKP
June 10, 2026 · View on GitHub
Status: ✅ SHIPPED (2026-06-01). Fifth in the genericization series, and the first to address workflow rather than a syscall (SCV → WCR → RND → ADM → SKP → DOS-HOME). Built on the now-landed WCR
[paths]/[lanes]read-back. Five generic screenplays ship in the wheel undersrc/dos/skills/{dos-next-up,dos-dispatch,dos-dispatch-loop,dos-replan,dos-replan-loop}/SKILL.md, driven entirely bydosverbs (incl. the two new ones,dos doctor --json+dos gate) anddos.tomldata; each names no host path/lane/convention. The seam ledger (74-seam-ledger.md) maps every POLICY line to its data/hook home; the friction log (74-friction-log.md) records the three open seams (packet template, evidence sources, the heavy leasing tier). Pinned bytests/test_skill_pack_{generic,dispatch,replan,litmus}.py. Method was dissection-by-observation: port one skill as a vertical slice, prove each kernel/host seam against a foreign repo, record what resisted genericization rather than forcing it.
The gap this closes
DOS ships the mechanism the dispatch workflow leans on — verify, refuse,
arbitrate, the typed gate, the correlation spine — and HACKING.md makes four
axes of it hackable (reasons, gate concepts, admission predicates, renderers).
But the workflow that sequences those syscalls — the Claude Code skills
next-up / dispatch / replan / dispatch-loop / replan-loop — lives
only in the host's own skills, is 100% host-shaped, and is explicitly
framed everywhere as "host concern, not a prerequisite" (next-stage-plan.md
North Star; CLAUDE.md layer table).
The result: a stranger who pip install dos-kernel (the dist name — the bare
dos PyPI name is an unrelated package) gets honest syscalls and no way to
drive them. They must reverse-engineer five large screenplays (the reference app's
dispatch/SKILL.md is 88 KB, dispatch-loop 140 KB) and the fat host
orchestrators behind them (next_up_render.py, replan_autoclose.py,
fanout_state.py) before DOS does anything end-to-end. examples/dos_ext/ shows
how to add a reason or a renderer; nothing shows how to run a plan-and-ship
cycle.
This plan ships a generic skill pack with the package — a baseline screenplay
that drives the kernel against any repo, with all host specifics in dos.toml
(WCR data) or an optional driver hook (code). Adopting it is not required to get
value from DOS; it is the reference workflow, the way BASE_REASONS is the
reference refusal vocabulary and examples/dos_ext is the reference plugin.
Why this is a real axis, not a contradiction of the layer contract
CLAUDE.md says the phased-plan workflow is host concern. That stays true: the
owner of a workspace's policy is still the host. What SKP adds is a
distinction the layer table currently collapses —
- Workflow policy (which lanes, which plan grammar, the commit-subject
template, the packet sections) — host's, declared in
dos.toml/driver. - Workflow mechanism (the shape of "snapshot the portfolio → audit each
pick against
verify→ render a dispatch packet → gate the empty case → take a lane lease → archive") — domain-free, and identical across hosts.
The second is as liftable as the syscalls were. The reference app's skills prove the shape
works; SKP extracts the shape, leaves the policy as data, and ships the result so
a new host fills in a dos.toml instead of authoring 300 KB of prose. This is
Axis 5 — workflow in HACKING.md's frame: not data (dos.toml), not behavior
(entry_points), but the screenplay that calls the syscalls in order. DOS ships
a reference one; a host may use it, fork it, or ignore it.
Design laws this plan must honor
- A generic skill names no host path, lane, or commit convention. Every
literal the reference app's skills hardcode —
docs/_plans/,output/next-up/,apply/tailor/discovery,docs/dispatch:— comes fromdos doctor --json(paths/lanes, via WCR) ordos.toml [stamp]/[render](grammar/template). A grep of a shipped generic skill fordocs/_plansorapplyreturns nothing. This is the skill analogue of "kernel imports no host." - The skill shells out to
dos, never to a host's fat scripts. Where a reference-app skill runspython scripts/next_up_render.py, the generic skill runs adossubcommand. New kernel verbs (dos doctor --json, and a generic renderer entry) are the seam; the screenplay carries no Python of its own. - Battle-scarred correctness is preserved, not rewritten. The reference app's skills encode hard-won fixes (FQ-77 bookkeeping exclusion, the empty-packet gate, the hard-locked pathspec discipline). Genericization relocates these into the kernel/config, it does not relax them. Each phase proves the relocated behavior matches the reference app's behavior before its prose is touched.
- Minimal diff, prove-then-move. Per the operator's method: change as little as possible per step, pull apart one seam, validate it against a throwaway foreign repo, and write any genericization insight that doesn't yet have a home into this plan's "Observed friction" log (Phase 5) rather than coding ahead of proof.
North-star acceptance (the whole plan is done when)
pip install -e . # the skill pack ships under dos/skills/
dos init /tmp/svc && cd /tmp/svc # scaffold dos.toml (lanes/paths/stamp)
# ... a repo with a couple of `planning/*.md` plans and real commits ...
# The generic next-up skill, driven entirely by dos verbs + dos.toml:
claude -p "/dos-next-up" # writes a dispatch packet under the
# configured next_packets path, with
# each pick's status from `dos verify`,
# and NO reference to docs/_plans or
# host lanes anywhere in the run.
dos gate <that-packet> # LIVE | DRAIN | STALE-STAMP, typed
…with the reference app's skills still working byte-for-byte (they keep their driver), the
existing kernel suite green, and a tests/test_skill_pack_generic.py proving the
generic dos-next-up produces a coherent packet against a foreign repo with no
host-specific config.
Phase 0 — the gap audit + the seam ledger (no code)
Before porting prose, pin exactly which lines of each reference-app skill are mechanism (liftable) vs policy (must become data/hook). This is the dissection map the rest of the plan executes against.
- 0a. For
next-up(the heaviestverifyconsumer, the first slice), table every shelled command, every hardcoded path, every lane/convention name, and classify each as MECHANISM or POLICY, with the destination for each POLICY item ([paths]/[lanes]/[stamp]/[render]/ driver hook). Repeat lighter passes for the other four. - 0b. Record the verified seam state this plan builds on (already established
2026-05-31, see the throughline below): SCV stamp readback is shipped and
proven on a foreign repo; WCR
[lanes]/[paths]readback is NOT yet wired (dos doctorignores them). SKP Phase 1 therefore cannot begin until WCR Phase 2 lands. State this dependency as a hard gate. - 0c. Decide the skill-pack home, distinguishing two audiences the repo now
separates (
CLAUDE.md's "Release & dev tooling is OUTSIDE these four layers"): the/release+/stable-releaseskills in.claude/skills/are dev tooling that maintains the package (repo-local, not shipped to consumers). The SKP pack is the opposite — a baseline workflow for consumers of the package, so it ships in the wheel atdos/skills/<name>/SKILL.md(a[tool.setuptools.package-data]/MANIFEST.inentry), discoverable by a host that copies it into its own.claude/skills/. Both importdos/ shell the CLI with the same one-way arrow (nothing undersrc/dos/imports them), so SKP honors the just-documented contract; it differs from the release skills only in audience and delivery (shipped vs repo-local). Confirm SKP is native owner code in this repository (like70–73), not a host-narrative stub.
Litmus (Phase 0): a committed docs/74-seam-ledger.md (or an appendix here)
that, for next-up, lists every POLICY line with its data/hook destination — and
names the ones with no destination yet (the genuine kernel gaps SKP surfaces,
e.g. a packet-template seam [render] that RND's --output does not cover).
Phase 1 — dos doctor --json + dos gate (expose what the screenplay needs)
A generic skill discovers its layout and gates its empty case through the CLI. Two thin verbs, both over machinery that already exists.
- 1a. Add
--jsontodos doctor: emit{workspace, paths:{…}, lanes:{…}, stamp:{…}, git:bool}— exactly the fieldsdoctoralready computes and prints (cli.py:371-377), as a machine-readable object a skill reads with one call. Text output stays byte-identical when--jsonis omitted. - 1b. Add
dos gate <packet>(ordos gate --picks N --…): expose the typed empty-packet verdict (gate_classify/tokens.GateVerdict—LIVE/DRAIN/STALE-STAMP/BLOCKED/RACE) that the reference app's dispatch-loop computes inline today. The classifier exists in the kernel; this is a CLI surface over it, no new logic. - 1c. Verify both against the throwaway foreign repo (the SCV test rig:
PYTHONPATH=src python -m dos.cli, BOM-freedos.toml):doctor --jsonon a repo with WCR-declared[paths]reports the declared glob, not the default.
Litmus (Phase 1):
test_doctor_json_reports_declared_paths— with WCR landed, a workspace whosedos.tomlsetsplans_glob="planning/*.md"hasdoctor --jsonemit that glob.test_gate_classifies_empty_packet— a zero-pick packet returnsDRAIN; a packet whose picks ship-but-aren't-stamped returnsSTALE-STAMP, through the CLI.- Both default-text outputs unchanged (byte-identical litmus).
Phase 2 — the generic dos-next-up skill (the throughline)
The first full vertical slice: one shipped, generic screenplay that drives a plan-and-ship snapshot end-to-end with zero host specifics.
- 2a. Author
dos/skills/dos-next-up/SKILL.md: a screenplay that (1) callsdos doctor --jsonfor paths/lanes, (2) walks the plans glob, (3) for each candidate pick callsdos verify PLAN PHASEfor its true status, (4) renders a dispatch packet to the configurednext_packetspath, (5) reports a typed outcome viados gate. Nodocs/_plans, noapply/tailor, nonext_up_render.py. - 2b. Where
next_up_render.pycarries generic rendering (walk plans, audit via verify, emit a packet) vs the host's template (exact sections, commit subject), lift the generic half into a kernel entry the skill calls (ados next-upemit, or — preferred, to reuse RND — a renderer the skill selects). Leave the template as a[render]data seam (Phase 0 flagged whether RND's--outputcovers this or a new[render]table is needed). Do not port the host's template into the kernel. - 2c. Prove it: run
/dos-next-upagainst the foreign repo and assert the packet names the foreign repo's plans/phases with correct shipped/unshipped status, and that the run touched no host path.
Litmus (Phase 2):
test_skill_pack_generic.py::test_dos_next_up_foreign_repo— drives the skill's scripted steps against a tmp foreign repo (no--job, generic[stamp]), and asserts a coherent packet with verify-backed statuses.- A grep guard: the shipped
dos-next-up/SKILL.mdcontains none of{docs/_plans, output/next-up, apply, tailor, discovery, docs/dispatch:}.
Phase 3 — the lease-aware skills (dos-dispatch, the loop) over arbitrate/lease
dispatch and dispatch-loop add concurrency: a lane lease so parallel loops
don't collide, and the typed gate driving continue/stop. The admission kernel
(dos arbitrate) and the cross-process mutex (dos lease) already exist as CLI
verbs; the heavy fanout_state.py soft-claim core does not port in v1.
- 3a. Author
dos/skills/dos-dispatch/SKILL.md: the chained snapshot→ship cycle, taking a lane viados arbitrate --lane L --kind cluster --leases <live>(trees from WCR[lanes.trees]) before launching, and archiving under ados.toml-declared run dir. The "may I run on this lane" decision is the kernel's, not inline prose. - 3b. Author
dos/skills/dos-dispatch-loop/SKILL.md: the dispatch⇄replan cadence, with the continue/stop decision fromdos(theloop_decidesurface, exposed as a verb if not already) and the typed gate from Phase 1. The drained-twice / dirty-zero breakers are kernel policy (loop_decide.decide), not re-implemented in the screenplay. - 3c. Explicitly scope OUT the soft-claim leasing, focus scheduler, and
rate-limit resume machinery that
fanout_state.py/next_up_focus.pyown — these are the "heavy tier"CLAUDE.mdalready parks in the reference userland app. The generic loop usesarbitrate/leasefor the lighter lane-coordination path andlogs what it is NOT doing (no silent capability gap).
Litmus (Phase 3):
test_dos_dispatch_takes_lane— two generic-skill dispatch runs on disjoint WCR-declared lanes both ADMIT; on overlapping trees the second gets a COLLISION, throughdos arbitrate.test_dos_loop_stops_on_drain_twice— the loop's scripted decision callsloop_decideand halts after two consecutiveDRAINs.
Phase 4 — the planning skills (dos-replan, dos-replan-loop)
replan gardens the portfolio from accumulated evidence. Its mechanism (read
findings, detect closures via verify, rerank a queue) is liftable; its evidence
sources and gardening passes are heavily host-specific.
- 4a. Author
dos/skills/dos-replan/SKILL.mdcovering the domain-free core: closure detection (a queue item whose phases nowverifyas shipped is closed), cooldown-state tracking, and the ruthless operator-summary (0–2 items). The host-specific gardening passes (anchor reconciliation, soak-state drift, the apply-postmortem stream) become driver hooks or are scoped OUT for v1. - 4b. Author
dos/skills/dos-replan-loop/SKILL.md: the thin recurring wrapper (it is already mostly orchestration over/replan+ a guarded release). The release guards (HEAD-on-trunk, docs-only) reference the workspace's trunk from config, not a hardcodedmain(note: this repo's trunk ismaster). - 4c. Reconcile the
dos decisionsqueue (already shipped) as the generic operator-inbox surfacereplanwrites to — replacing the reference app'sdecisions-pending.mdliteral with the kernel's decisions projection where they overlap.
Litmus (Phase 4):
test_dos_replan_closes_shipped_item— a queue item whose phases verify as shipped is moved to closed by the scripted replan steps.- The release-guard reads trunk from config (a
master-trunk repo is handled).
Phase 5 — the workflow axis in the docs + the friction log
Make Axis 5 first-class in the hackability story, and capture what resisted genericization so the next iteration has a target.
- 5a. Add Axis 5 — Workflow to
HACKING.md: the screenplay that sequences syscalls, shipped asdos/skills/, customizable viados.toml(paths/lanes/ stamp/render) + optional driver hooks; the two-attachment-model table grows a row. Flip the relevant sub-statuses to ✅ as phases land. - 5b. Add SKP to
next-stage-plan.md's committed-series table and update its North Star: skills are no longer purely out-of-scope — DOS ships a reference workflow, while host-specific workflow stays the host's. - 5c. Observed-friction log (the operator's "reflect and record" ask):
a running list of every place a reference-app skill behavior could NOT be made generic
in a phase — what it was, why (TOML can't express it / it's genuinely
host-policy / it needs a kernel seam that doesn't exist) — feeding future plan
items (a
[render]template axis, an evidence-source hook, a focus-scheduler port). This is where insight that outran the build gets written down instead of coded ahead of proof.
Litmus (Phase 5): HACKING.md lists five axes with Axis 5 specified and its
example skill referenced; next-stage-plan.md indexes SKP; the friction log names
at least the known-open seams (packet template, evidence sources, the heavy
leasing tier).
Out of scope (explicitly)
- Porting the heavy tier.
fanout_state.py's soft-claim lease core,next_up_focus.py's value-greedy scheduler, and the rate-limit resume machinery stay in the reference userland app (CLAUDE.md's "heavy tier"). The generic loop usesarbitrate/leasefor lane coordination and is honest about the gap. A full lease-core port is a separate plan if demand pulls it. - Migrating the reference app off its skills. The reference app keeps its five driver-backed skills; they have computed/reference policy and battle-scarred tuning. SKP adds the generic baseline for new hosts, it does not force the reference app onto it (mirrors WCR's "does not migrate the reference app off its driver").
- A skill runtime. SKP ships screenplays (SKILL.md) that drive the existing
dosCLI under Claude Code. It does not build a new execution engine; the Claude Code skill mechanism is the host. - TOML-declared behavior. Where a skill needs code (a computed commit
subject, a bespoke evidence reader), that is a driver hook or an
entry_point, neverdos.toml— the HACKING.md data/behavior split holds.
Why this is fifth (and depends on WCR)
SCV/WCR/RND/ADM make the syscalls honest and open for a stranger's repo. SKP is
the first plan to make the workflow portable — and it can only stand on a
workspace that already reads its lanes and paths from data, which is precisely
WCR. (SCV is already sufficient on the verify side: proven 2026-05-31 — a
foreign repo with dos.toml [stamp] subject_dirs=["src"] has dos verify
recognize src/BAR: BAR2 as shipped.) Until WCR Phase 2 lands, a generic skill
would have to hardcode docs/_plans/ — reintroducing the exact host-coupling this
series exists to remove. So SKP is gated on WCR, rides the dos doctor/gate
surfaces it adds in Phase 1, and reuses RND's renderer seam for packet output
where it fits. It is last because workflow is the top of the stack: it composes
every syscall the earlier plans made generic.