Doccraft story
Documentation and project-story skills (ADR, story, queue-audit, session-wrap) for Claude Code and Cursor, layered on OpenSpec.
npx -y skills add alexpialetski/doccraft --skill doccraft-storyAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Author or update product stories (a.k.a. planning docs, backlog items, tickets, specs) as Markdown under docs/stories/ with a YAML frontmatter contract (id, status, impact, urgency, depends_on, tags, openspec). Use this whenever the user is creating a story, reprioritising work, writing acceptance criteria, linking a story to OpenSpec or an ADR, or editing anything under docs/stories/ — even if they call it a spec, ticket, backlog row, or planning doc.
SKILL.md
12.5 KB, as published. Nobody here has run it
Managed by doccraft —
doccraft updateregenerates this file. Local edits will be overwritten. Seedoccraft.jsonto override project-specific vocabulary and paths without touching this file.
doccraft — planning stories
When to use
- Creating a new story in
docs/stories/. - Updating status, acceptance criteria, tags, or
openspecon an existing story. - When closing a story: update
docs/queue.mdand the Status column indocs/backlog.md. See Workflow reminders for queue-audit invocation rules.
YAML frontmatter (required fields)
Use valid YAML between --- delimiters at the top of the file. Every
field marked yes MUST be present — do not omit any. If the user has
not provided enough information to fill a required field, ask — NEVER guess.
| Field | Required | Values / notes |
|---|---|---|
id | yes | Stable, unique id across all stories. P0.3 when aligned to docs/backlog.md, or a slug like story-2026-001. MUST be unique — verify before writing. |
title | yes | Short human-readable title. |
status | yes | One of the values in story.status config (default: todo | in_progress | done). Manual updates only. |
impact | yes | One of the values in story.impact config (default: H | M | L). If the user does not specify, ask. |
urgency | yes | One of the values in story.urgency config (default: now | soon | later). If the user does not specify, ask. |
tags | yes | YAML list of prefixed strings (area:, slice:, theme:) from the tag vocabulary below. If nothing fits and the label will recur, extend the vocabulary in doccraft.yaml in the same change. |
openspec | yes | MUST be set to one of: not-needed | recommended | required. See openspec guidance below. |
updated | yes | ISO date YYYY-MM-DD. MUST be set on creation and updated on every meaningful edit. |
roadmap_ref | optional | e.g. P1.7 — pointer to the backlog row when applicable. |
depends_on | optional | YAML list of story id values that MUST be satisfied before this story is picked up (prerequisites). Omit or [] if none. Each entry MUST match another story's id or a backlog id you intentionally treat as external — prefer real story ids so the queue-audit graph stays honest. |
adr_refs | optional | List of ADR filenames this story implements or contradicts (e.g. 001-foo.md). |
openspec_change | optional | Path or name of the OpenSpec change folder when one exists. |
Do not invent new values for
status,impact, orurgencywithout first adding them to the matchingstory.*enum indoccraft.json— those are the single source of truth. Foropenspec, update this skill in the same change. One-off nuance belongs in the body, not as a new enum value.
openspec guidance
not-needed— small change, obvious scope, few files.recommended— multi-module, schema/graph shifts, ambiguous scope, or high regression risk; add a sentence in the body: OpenSpec recommended because: …required— project policy demands formal spec-before-code for this class of change.
Do not create an openspec/ tree unless the repository has adopted OpenSpec;
the field is preparatory.
File location and naming
- Path:
docs/stories/<slug>.md— kebab-case slug. - P-tier stories (aligned with a prioritised backlog): use
p{tier}-<topic>.mdwhere tier isp0…p4. The ordinal (e.g.P0.3) lives in YAMLid, not in the filename. Examples:p0-payment-retry-flow.md,p2-observability-rollout.md. - Non-tier work: stable prefix + slug, e.g.
opt-2a-workflow-rename.md. - One story per file. No epic folders — use prefixed
tagsfor grouping.
Body template
After frontmatter, use these markdown sections in this order:
- Problem / outcome (required) — what user or system need this addresses.
- Acceptance criteria (required) — bullet list, testable where possible.
- Notes (optional) — links to code (
src/...), related ADRs, PRs.
Do not add other top-level sections. Put additional context in Notes.
Example
---
id: P0.3
title: Payment retry flow with idempotency keys
status: todo
impact: H
urgency: now
tags:
- area:api
- area:data
openspec: recommended
updated: 2026-04-18
roadmap_ref: P0.3
depends_on: []
adr_refs:
- 003-payment-gateway-choice.md
---
## Problem / outcome
Failed third-party charges silently drop transactions; add retries with
idempotency so users can reorder without double-billing.
## Acceptance criteria
- [ ] Retries use persisted idempotency keys.
- [ ] Integration tests cover success, transient-failure, and permanent-failure paths.
- [ ] Runbook updated with the new retry behaviour.
## Notes
OpenSpec recommended because: touches schema + payment service + integration tests.
Tag vocabulary
Every tag MUST use a prefix so subsystem vs product slice vs cross-cutting
theme is unambiguous. Use lowercase after the colon (e.g. area:api).
| Prefix | Meaning | Examples |
|---|---|---|
area: | Subsystem / code area. Align with your project's commit scopes where you already have them. | area:api, area:cli, area:auth, area:data, area:infra, area:schemas |
slice: | Product surface that spans multiple areas. | slice:ui, slice:admin, slice:onboarding |
theme: | Cross-cutting quality or kind of work. | theme:observability, theme:performance, theme:security, theme:docs, theme:testing |
A story may list several tags, e.g. area:api, area:data, theme:performance.
Extending the vocabulary
- If no existing
area:,slice:, ortheme:value fits, and the label will recur, add it to the matching list indoccraft.yaml(keysstory.areas/story.slices/story.themes). Commit the config edit together with the first story that uses the new value. - One-off nuance that will not recur belongs in the body (Notes), not as a new tag.
Do not edit the tables in this SKILL.md directly — doccraft update
regenerates this file and would overwrite the edit. doccraft.yaml
is the single source of truth for project-specific vocabulary.
Invalid examples (do not use)
- Bare words:
api,ui— always use a prefix so the kind of label is explicit. - Wrong prefix for the kind of label (e.g.
area:uiwhileslice:uiis the convention) — preferslice:for product surfaces.
Pre-write validation
Before writing or updating a story file, MUST complete these checks:
- Unique
id— scan alldocs/stories/*.mdfrontmatter and confirm theidvalue does not already exist. If it does, stop and ask the user for a different id. - Valid
depends_on— every entry independs_onMUST match an existing story'sidvalue. If a reference is not found, stop and ask the user to clarify. - Valid tags — every tag MUST use a recognised prefix (
area:,slice:,theme:). Bare words are NEVER acceptable. - Valid enums —
status,impact,urgency, andopenspecvalues MUST match the allowed values (fromdoccraft.yamlor the defaults in the frontmatter table above). - Required fields present — all fields marked "yes" in the frontmatter
table MUST be present. If the user has not provided enough information
to fill
impact,urgency, oropenspec, ask — do not guess.
Done condition
The task is complete when:
- The story file exists at the correct path (
docs/stories/<slug>.md). - Frontmatter contains all required fields with valid values.
- Body contains at minimum Problem / outcome and Acceptance criteria.
- If
depends_onwas added or changed,doccraft-queue-audithas been invoked in the same turn. - If the story was closed (
status: done),docs/queue.mdanddocs/backlog.mdhave been updated.
Configuration
Read doccraft.yaml at invocation. The story: section is this
skill's customisation surface; override the defaults in the tables above
with the values found there. If the file is missing or the story:
section is absent, use the defaults as-is.
Relevant keys:
docsDir— root folder for all docs, relative to project root. Default:docs. Stories live at{docsDir}/stories/.story.areas,story.slices,story.themes— tag vocabulary lists (replace the defaultarea:/slice:/theme:values).story.status— allowed values for thestatus:field. Default:[todo, in_progress, done]. Extend if your project uses additional states (e.g.blocked,abandoned).story.urgency— allowed values for theurgency:field. Default:[now, soon, later]. Some projects use tier names (p0..p4) directly here, or mix both.story.impact— allowed values for theimpact:field. Default:[H, M, L]. Override for projects that prefer[high, medium, low]or another taxonomy.story.id.tiers— filename tier prefixes likep0…p4. Empty list[]means the project does not use tier prefixes.story.id.pattern— regex accepting valid storyid:values in frontmatter. Use this to validate new stories and to normalisedepends_ontypos. Default:^(P\d+(\.\d+)?|[a-z][a-z0-9-]+)$.
Adding to a list in doccraft.yaml teaches the skill a new valid
value without touching this file (which doccraft update regenerates).
That is the intended way to extend vocabulary for a project.
Package context
For monorepo projects, stories may live at the project root or under a
declared package's docs/stories/ tree (a Known package roots
block appears above when packages are declared). For single-root projects
no block appears, every story lives at the project-root
docs/stories/, and the namespace rules below do not apply.
When the project declares packages, decide which scope to write to:
- Explicit
package:arg. If the user names a package (e.g. "create a story foraudio-engine"), write to that package'sdocs/stories/and use the namespaced id form<slug>/STR-NNNN. - Active-file inference. If the user is editing a file under a declared package path, default to that package's docs root.
- Root default. Otherwise, write to the project-root
docs/stories/with an unprefixed id.
In depends_on, the form <slug>/STR-NNNN references a story under that
package's docs/stories/; unprefixed ids always refer to the
project-root scope. The same namespace rule applies to adr_refs
(unprefixed = root, <slug>/NNN-slug.md = package-scoped).
Cross-reference resolution (path-bearing links)
Per ADR 017, a cross-reference should resolve in one hop — opening the target should never require globbing a directory to find the file. The namespaced id stays the canonical, rename-stable handle; pair it with a path so neither readers nor agents pay a search tax:
- In frontmatter lists (
depends_on,adr_refs), keep the id form — link syntax in a YAML list is awkward, and the audit resolves these against the Known package roots anyway. Ids remain canonical here. - In prose, tables, and Notes — whenever you write a reference a reader
or agent will follow (a related-story line, a queue row, an epic table),
render it as a markdown link whose text is the id and whose target is the
resolvable file path:
[pipeline/P1.30](../services/pipeline/docs/stories/p1-...md). - The id is the source of truth; the path is a convenience that the audit
(
doccraft-queue-audit) re-derives from the id and repairs when a file moves — so a stale path is a mechanical fix, not a dead link.
Workflow reminders
- Move
statustoin_progresswhen you start implementation;donewhen shipped or explicitly abandoned (note why in body if abandoned). - After creating a story or changing
depends_on, invokedoccraft-queue-auditin the same turn so the working queue stays consistent with the dependency graph. - When closing a story (
status: done), updatedocs/queue.mdand the Status column indocs/backlog.mdin the same commit.