Doccraft story
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.From its SKILL.md
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.
SKILL.md
12.5 KB, ~3.2k tokens by cl100k_base, 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.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.