Installs into .claude/skills of the current project.
Are you the author of Sk Doc?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/michelkerkmeester-sk-doc-675964d2)
---
name: sk-doc
description: "Documentation & OpenCode-component authoring hub: skills, agents, commands, READMEs, catalogs, playbooks, changelogs, packet goals, frontmatter."
allowed-tools: [Read, Write, Edit, Bash, Grep, Glob]
version: 2.2.4.0
metadata:
author: OpenCode
family: sk-util
---
<!-- Keywords: sk-doc, documentation, markdown, authoring, parent-hub, mode-registry, hub-router, workflowmode, packetkind, 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-changelog, sk-create-diff, sk-create-repo-rule, sk-create-frontmatter, sk-create-goal, sk-create-with-human-voice, sk-create-quality-control, human-voice-rules, hvr, shared-backbone, create-quality-control-pipeline -->
# Documentation Authoring Hub (sk-doc)
One advisor identity, fifteen workflow modes across fourteen 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.
**Version authority.** This file's `version` frontmatter is the hub's release version and matches the newest entry under `changelog/`; `description.json`, `mode-registry.json`, `hub-router.json`, and `ROUTER.md` carry the same value, so every hub-root artifact states the same release.
---
## 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, general or code-folder | `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, and model-benchmark packages or inputs | `sk-create-benchmark/` | `/create:benchmark` |
| **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/` | `/create:diff` |
| **sk-create-repo-rule** | Create, revise or retire a repo-local rule under `repo-rules/` and wire it into `REPO RULES.md` (four decision tests refuse most requests) | `sk-create-repo-rule/` | `/create:repo-rule` |
| **sk-create-with-human-voice** | Apply the Human Voice Rules to prose, or score prose against them, with a scope gate and a re-scan | `sk-create-with-human-voice/` | `/create:with-human-voice` |
| **sk-create-frontmatter** | Own the YAML frontmatter contract: per-class field rules, the description budget, and the 4-part `version` derivation | `sk-create-frontmatter/` | — (routes via aliases) |
| **sk-create-goal** | Author or revise a packet `goal.md`: the durable directive, three to seven self-contained completion criteria, and the phase-parent binding table (session-goal setting stays with the goal hooks) | `sk-create-goal/` | `/create:goal` |
| **sk-create-quality-control** | Validate / score / optimize an EXISTING document (extract → DQI → HVR → validate) | `sk-create-quality-control/` | (routes via aliases) |
### 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 .skilled/bin/compiled-route.cjs --hub sk-doc --prompt "<task>"
> ```
> 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 `SPECKIT_COMPILED_ROUTING=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 creation, parent-hub creation, agent creation, command creation, the paired agent-plus-command lane, flowcharts, the human-voice pass, playbooks, feature catalogs, READMEs, changelogs, benchmarks, diffs, packet goals, repo rules, 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-parent` is a second mode over the same `sk-create-skill` packet.
- **`packetKind`** — `workflow` for every sk-doc packet (there is no surface axis; the sk-create-quality-control pipeline is universal doctrine in `shared/`, not orthogonal stack-evidence).
- **`backendKind`** — `template-scaffold` for the create-* generators, `sk-create-quality-control` for 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-skill-parent, sk-create-readme, sk-create-agent, sk-create-command, sk-create-feature-catalog, sk-create-manual-testing-playbook, sk-create-benchmark, sk-create-changelog, sk-create-diff, sk-create-repo-rule, sk-create-frontmatter, sk-create-goal, sk-create-with-human-voice, 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:
for resource in hub_router.routerPolicy.defaultResource: # the ordered defer set, never hardcoded here
load_if_available(resource, 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/<key>/` or `assets/<key>/`) 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 fifteen-mode 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-changelog/ sk-create-diff/
sk-create-repo-rule/ sk-create-frontmatter/ sk-create-goal/
sk-create-with-human-voice/ 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 generic validator `shared/scripts/cite-drift-scan.mjs` counts and resolves the `<path>.<ext>:<line>` citations in every tracked skill doc and makes zero model calls by default, while `--jev` and `--deem` each run one backend and need `--out <dir>` so every call is recorded. 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.md` `RESOURCE_MAP` in sync with `leaf-manifest.json` and `leaf-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.json` inside a packet or `shared/`.
- **NEVER** put per-packet authoring logic in the hub.
- **NEVER** add a surface axis or a `surfaceBundle` outcome — sk-doc is workflow-only.
### ⚠️ ESCALATE IF
- A new documentation workflow is needed — extend `mode-registry.json` and 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` (fifteen modes across fourteen 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-changelog/`, `sk-create-diff/`, `sk-create-repo-rule/`, `sk-create-frontmatter/`, `sk-create-goal/`, `sk-create-with-human-voice/`, `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`.