Install
$ agentstack add skill-michelkerkmeester-skilled-harness-spec-driven-agent-loops-sk-doc ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Documentation Authoring Hub (sk-doc)
One advisor identity, eleven workflow packets, one shared sk-create-quality-control backbone. sk-doc is the parent hub for documentation and OpenCode-component authoring. It holds NO per-packet logic: it routes by workflowMode through mode-registry.json, and each packet keeps its own contract in its nested folder. The cross-cutting sk-create-quality-control pipeline (validators, global standards, frontmatter/llms/template assets) lives once in shared/ and is consumed by every packet.
1. WHEN TO USE
Use this skill for documentation and OpenCode-component authoring, and for document-quality work. The hub classifies the request, resolves a workflowMode, and loads the matching nested packet.
| Mode | Use it for | Packet | Command | |------|------------|--------|---------| | sk-create-skill | Scaffold an OpenCode skill (and, via sk-create-skill-parent, a parent hub with nested mode packets) | sk-create-skill/ | /create:skill, /create:skill-parent | | sk-create-readme | Author a folder README or an install guide (install-guide is a folded variant) | sk-create-readme/ | /create:readme | | sk-create-agent | Scaffold an OpenCode agent (permission/authority frontmatter) | sk-create-agent/ | /create:agent | | sk-create-command | Scaffold an OpenCode slash command (argument-hint + allowed-tools + router/presentation split) | sk-create-command/ | /create:command | | sk-create-feature-catalog | Author a feature-catalog inventory package | sk-create-feature-catalog/ | /create:feature-catalog | | sk-create-manual-testing-playbook | Author a manual-testing-playbook package | sk-create-manual-testing-playbook/ | /create:manual-testing-playbook | | sk-create-benchmark | Author MCP-promotion, behavior, skill-benchmark, and model-benchmark packages or inputs | sk-create-benchmark/ | /create:benchmark | | sk-create-diagram | Generate an HTML/SVG technical diagram (27 types) or a validated ASCII/markdown flowchart via --output-format | sk-create-diagram/ | /create:diagram | | sk-create-changelog | Author a global or packet-local changelog entry (version bump + topology-aware placement) | sk-create-changelog/ | /create:changelog | | sk-create-diff | Produce a local, Git-free before/after review of an edited document (text/Markdown/HTML/DOCX/text-PDF) as a self-contained HTML report | sk-create-diff/ | — (routes via aliases) | | sk-create-quality-control | Validate / score / optimize an EXISTING document (extract → DQI → HVR → validate) | sk-create-quality-control/ | /doc:quality |
When NOT to Use
- Code implementation, tests, or debugging — use
sk-code. - Git worktree, branch, commit, PR, or release work — use
sk-git. - Spec-folder workflow / memory / save context — use
system-spec-kit. - A measured Style Reference (design tokens extracted from a live source) — use
sk-design-md-generator. - The
shared/backbone is consumed by the packets, not invoked as a user workflow.
2. SMART ROUTING
Routing is registry-driven at runtime and packet-authored at source in two stages. Stage 1 (hub → mode): each nested packet's single Keyword triggers: line is the source of truth for its routing vocabulary; mode-registry.json and hub-router.json are synchronized projections that the hub reads without re-deriving mappings during a request. The advisor routes any documentation/authoring query to the single identity sk-doc; the hub then picks the packet. Stage 2 (mode → leaves): the root ROUTER.md maps the request's authoring intent to the exact packet-local leaf resources that mode loads. The two layers stay separate: the hub never emits leaf paths, and the surface router never re-decides the mode.
> Compiled routing (default-on, flag-gated, additive). Resolve the mode via the compiled router contract first: > ``bash > node .opencode/bin/compiled-route.cjs --hub sk-doc --prompt "" > ` > Follow the returned decision — route (use its targets), clarify/defer (disambiguate), reject (refuse). On a {"servingAuthority":"legacy"} sentinel or any error, use the routing below. The front door self-gates on serving-authority. Compiled routing is now the default for sk-doc; set SPECKITCOMPILEDROUTING=0` to force legacy routing fleet-wide — the explicit kill-switch.
Surface Router — per-intent leaf sets
Stage 2 of routing lives in ROUTER.md at the hub root, next to SKILL.md and README.md. It defines the per-intent leaf model (document quality, optimization, skill/agent/command creation, flowcharts, install guides, HVR rules, playbooks, feature catalogs, READMEs, changelogs, benchmarks, diffs, and the explicit full-toolkit intent), the machine-readable INTENT_SIGNALS / RESOURCE_MAP block that the deterministic router-replay and benchmarks parse, and the how-to-read rules (dominant intent → one leaf set; near-tied intents → deduped union; no keyword match → hub UNKNOWN fallback, never a silent default). Every RESOURCE_MAP path is packet-qualified or an authored shared-alias disk path, and each converts to the canonical (workflowMode, leafResourceId) pair at the one contract boundary.
ROUTER.md stays a separate document on purpose: the router-replay contract resolves the hub's mode from hub-router.json and reads the leaf sets from the surface document — the machine block must not move into SKILL.md (the replay would treat it as the hub's own router and lose the mode projection) or into hub-router.json (schema handoff-ambiguity rule). The shared/ backbone stays the universal sk-create-quality-control source; the surface router only selects leaves.
The discriminator
workflowMode— the public packet key (e.g.sk-create-skill,sk-create-quality-control).sk-create-skill-parentis a second mode over the samesk-create-skillpacket.packetKind—workflowfor every sk-doc packet (there is no surface axis; the sk-create-quality-control pipeline is universal doctrine inshared/, not orthogonal stack-evidence).backendKind—template-scaffoldfor the create-* generators,sk-create-quality-controlfor the sk-create-quality-control mode.
Routing rule
SKILL_ROOT = path containing this SKILL.md
REGISTRY = SKILL_ROOT / "mode-registry.json"
HUB_ROUTER = SKILL_ROOT / "hub-router.json"
UNKNOWN_FALLBACK_CHECKLIST = [
"Confirm whether this is sk-create-skill, sk-create-readme, sk-create-agent, sk-create-command, sk-create-feature-catalog, sk-create-manual-testing-playbook, sk-create-benchmark, sk-create-diagram, sk-create-changelog, sk-create-diff, or sk-create-quality-control work",
"Confirm the target document or component being authored, scaffolded, or reviewed",
"Provide the available inputs: existing doc, source material, or scaffold parameters",
"Confirm the validation expectations before completion (DQI/HVR scoring, validate.sh, or packet-specific checks)",
]
def _guard_in_skill(relative_path):
resolved = (SKILL_ROOT / relative_path).resolve()
resolved.relative_to(SKILL_ROOT)
if resolved.suffix.lower() not in {".md", ".json"}:
raise ValueError("only skill-local markdown/json router resources are routable")
return resolved.relative_to(SKILL_ROOT).as_posix()
def load_if_available(relative_path, seen):
guarded = _guard_in_skill(relative_path)
if guarded not in seen and (SKILL_ROOT / guarded).exists():
load(guarded)
seen.add(guarded)
return True
return False
seen = set()
if not REGISTRY.exists() or not HUB_ROUTER.exists():
return defer("router metadata missing; inspect sk-doc/mode-registry.json and sk-doc/hub-router.json")
read mode-registry.json and hub-router.json
classify the request to one or more workflowMode values using hub-router.json
(dominant authoring/quality intent; a command like /create:agent resolves directly)
if confidence is low, intent is contradictory, or routerPolicy.defaultMode is null and no mode wins:
load_if_available("shared/references/quick-reference.md", seen)
return UNKNOWN_FALLBACK with disambiguation_checklist = UNKNOWN_FALLBACK_CHECKLIST
for each resolved workflowMode:
entry = the matching mode-registry.json modes[] item
if entry is missing or entry.packetKind != "workflow":
return defer("unknown sk-doc workflowMode; extend mode-registry.json and create a packet first")
if not load_if_available(f"{entry.packet}/SKILL.md", seen):
return defer("registered packet SKILL.md is missing; repair the packet before routing")
return single or orderedBundle according to hub-router.json routerPolicy.outcomes
routerPolicy.defaultMode is null: an unclear documentation intent asks for disambiguation rather than forcing a stale default. hub-router.json carries the router signals, vocabulary classes, default fallback resource, and bundle rules. Outcomes are single, orderedBundle, or defer — there is no surfaceBundle (no surface axis).
Per-packet behavior is not flattened: each packet keeps its own authoring contract, references, assets, scripts, and templates.
This hub does not use keyed resource discovery (references// or assets//) at the hub root: there are no hub-root references/ or assets/ directories, and packet resources stay inside their owning packet or the shared backbone. If a future workflow needs keyed resource subdirectories, add that behavior inside the owning packet using guarded runtime discovery; do not hardcode resource inventories in this hub.
3. HOW IT WORKS
Layout
sk-doc/
SKILL.md # this routing hub (no per-packet logic)
ROUTER.md # stage-two surface router (authoring intent -> leaf sets)
mode-registry.json # the eleven-packet discriminator + advisorRouting (single source of truth)
hub-router.json # router signals + vocabulary classes
description.json # hub advisor descriptor
graph-metadata.json # the ONE advisor identity for the whole skill
changelog/ manual-testing-playbook/ benchmark/ feature-catalog/
sk-create-skill/ sk-create-readme/ sk-create-agent/ sk-create-command/
sk-create-feature-catalog/ sk-create-manual-testing-playbook/
sk-create-benchmark/ sk-create-diagram/ sk-create-changelog/ sk-create-diff/ sk-create-quality-control/ # nested workflow packets
scripts/ # facade symlinks -> shared/ + owning packets (tool paths only)
shared/ # sk-create-quality-control backbone: validators, global standards, shared assets
Each packet is self-contained (its own SKILL.md, README.md, changelog/, and moved references//assets//scripts/) and carries no graph-metadata.json, so the advisor discovers exactly one sk-doc identity.
Shared backbone
shared/ holds the universal sk-create-quality-control pipeline consumed by every packet: generic validator scripts (shared/scripts/), cross-cutting standards and vocabulary (shared/references/), and shared templates (shared/assets/). The sk-doc/scripts/ root directory keeps facade symlinks pointing inward to shared/ and the owning packets so tool paths resolve. There are no hub-root assets/ or references/ aggregation directories: consumers reference each packet's own assets//references/ or the shared/ backbone directly.
4. RULES
✅ ALWAYS
- ALWAYS resolve a packet through
mode-registry.json; never hardcode a router mapping in the hub. - ALWAYS keep authoring contracts in the packets; the hub stays routing-only.
- ALWAYS keep exactly one
graph-metadata.json(this hub's) so the advisor sees one identity. - ALWAYS keep the root
ROUTER.mdRESOURCE_MAPin sync withleaf-manifest.jsonandleaf-aliases.json— the leaf sets dual-read to canonical typed pairs at the one contract boundary. - ALWAYS keep the sk-create-quality-control pipeline as one shared source under
shared/, consumed by the packets. - ALWAYS keep changelogs as real files at the hub and in each packet — never symlinked.
⛔ NEVER
- NEVER add a
graph-metadata.jsoninside a packet orshared/. - NEVER put per-packet authoring logic in the hub.
- NEVER add a surface axis or a
surfaceBundleoutcome — sk-doc is workflow-only.
⚠️ ESCALATE IF
- A new documentation workflow is needed — extend
mode-registry.jsonand open a packet; do not bolt logic onto the hub. - A packet would become a near-empty shell (generic doctrine, no type-specific behavior) — fold it into
shared/instead.
5. REFERENCES
- Registry:
mode-registry.json(eleven packets;packetKind: workflow). - Hub router:
hub-router.json(signals + vocabulary classes). - Surface router:
ROUTER.md(authoring intent to packet-local leaf sets). - Advisor descriptor:
description.json; skill-graph identity:graph-metadata.json. - Packets:
sk-create-skill/,sk-create-readme/,sk-create-agent/,sk-create-command/,sk-create-feature-catalog/,sk-create-manual-testing-playbook/,sk-create-benchmark/,sk-create-diagram/,sk-create-changelog/,sk-create-diff/,sk-create-quality-control/. - Shared backbone:
shared/scripts/,shared/references/,shared/assets/. - Parent-skill pattern:
sk-create-skill/references/parent-skill/parent-skills-nested-packets.md.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: MichelKerkmeester
- Source: MichelKerkmeester/skilled-harness_spec-driven-agent-loops
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.