Skip to content

create_story.py — one-command Story creation (CVN-N014-EC-S07)

scripts/create_story.py performs the create + scaffold half of the Story workflow in a single command, baking in the two rules the manual ritual keeps getting wrong (memory feedback_create_op_wp_for_stories):

  1. Always create the OpenProject work package — not just the GH issue — by delegating to the tested scripts/openproject_import_gh.py (never re-implemented).
  2. The OP wp lands as New (ADR-69). This script never advances status; that stays /story-advance (a gated, operator-approved skill).

What it does (and where it stops)

create_story.py:  GH issue  →  OP wp (New)  →  Epic registry  →  plan-dossier skeleton  →  STOP
/story-advance:                                                                            → In specification → … → Closed
Step Action
0 duplicate pre-check — refuse if an issue already carries the cvn-id (unless --force)
1 write documentation/reviews/<date>-<cvn>-<slug>-plan.md skeleton (satisfies the → In specification gate; idempotent)
2 gh issue create — title normalized to [Story] <cvn-id> — <title>
3 openproject_import_gh.py --type Story — OP wp lands as New
4 Epic registry — append a row to documentation/epics/<parent>*.md if it exists, else comment on the parent Epic's GH issue (format-agnostic, never edits a free-form body)

Usage

# preview everything, create nothing
python scripts/create_story.py --cvn-id CVN-N014-EC-S08 --parent-cvn-id CVN-N014-EC \
    --title "pr-merge (SKILL)" --dry-run

# real run (issue body defaults to TEMPLATE_story.md; pass --body / --body-file to override)
python scripts/create_story.py --cvn-id CVN-N014-EC-S08 --parent-cvn-id CVN-N014-EC \
    --title "pr-merge (SKILL)" --body-file /tmp/body.md

Flags: --body / --body-file (mutually exclusive), --labels a,b (default none — this repo has no story label), --gh-repo owner/repo, --force (bypass the duplicate check), --dry-run, -v.

Failure semantics (ADR-25, no silent half-done state)

  • Bad --cvn-id / --parent-cvn-id → exit 2, nothing created.
  • Duplicate cvn-id (issue exists, no --force) → exit 3.
  • OP import fails after the issue was created → exit 4, prints the created issue number and the exact openproject_import_gh.py retry command so you re-run only the failed step against the existing issue.
  • Any other command failure → exit 1 with the failing command surfaced.

The agreed flow (create → … → Specified)

1. create_story.py        → GH issue + OP wp (New) + Epic registry + plan skeleton
2. /story-advance <wp>    → In specification   (gate: plan dossier exists ✅ — the skeleton)
3. complete the plan dossier + committee plan_review
4. /story-advance <wp>    → Specified          (gate: plan_review PASSED ✅)
5. … In progress → impl → CR → pr_review → merge → Developed → … → Closed

create_story.py covers step 1 only.

The /create-story SKILL (judgment layer, CVN-N014-EC-S14)

.claude/skills/create-story/SKILL.md wraps this SCRIPT as a user-only slash command (disable-model-invocation: true) — the judgment layer over the deterministic CLI, mirroring /story-advance over op_story_transition.py (S11/S01) and /loki-query over loki_query.py (S12/S02):

  • derives the next free S-number (scans GH issues and documentation/ Epic dossiers),
  • resolves the parent Epic (read-only; STOPs if ambiguous/missing — never an orphan Story),
  • shapes title/body from intent, guards duplicates (surfaces --force, never auto-bypass),
  • previews + requires explicit operator approval before the write, runs the SCRIPT --dry-run then for real,
  • stops at New (does not chain into /story-advance) and surfaces the SCRIPT's exit-4 retry command verbatim.

The SKILL re-implements none of the create logic — it calls this SCRIPT (34 unit tests) and emits skill_invoked/skill_operator_approval/skill_completed (S00 §8). Use /create-story for the day-to-day "open a Story" act; call create_story.py directly for scripted/headless creation.

Tests

tests/unit/test_create_story.py — arg/cvn-id validation, title normalization (incl. idempotence), slug + dossier path, skeleton render, command assembly, and the orchestrated main flow with gh/OP calls mocked (dup-refuse, happy path, OP-failure retry surface).