| name | issue-spec |
| description | Create lean-spec style GitHub issues as specs for human-AI aligned implementation on the current repo. Use when asked to "create a spec", "write a spec issue", "spec this feature", "spec this", or when planning work that needs a specification before implementation. Follows the lean-spec SDD methodology — small focused specs (<2000 tokens), intent over implementation, context economy. Creates GitHub issues with Overview, Design, Plan, Test, Alignment, and Notes sections. Repo-specific area taxonomy, sister-skill names, custom body sections (e.g. Provider impact / Schema impact / Reach), and additional principles are overlaid by the consumer repo's CLAUDE.md and its `*-dev-process` sister skill — read those first when the repo isn't obvious. The `pre-push` and `pr-lifecycle` methodology is shared globally (installed from `onsager-ai/dev-skills`), like this skill. |
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash(git diff:*), Bash(git log:*), Bash(git show:*), mcp__github__issue_write, mcp__github__issue_read, mcp__github__list_issues, mcp__github__search_issues, mcp__github__sub_issue_write, mcp__github__get_label |
issue-spec
Create GitHub issues as lean-spec style specifications for human-AI aligned implementation on whatever repo this skill is installed in. GitHub issues are the sole spec medium — no spec files.
This skill is the repo-agnostic methodology half of the contract. Each consumer repo overlays its own delta in two places:
- Repo CLAUDE.md — names the GitHub slug (
codervisor/lean-spec, onsager-ai/onsager, onsager-ai/duhem, …) and any repo-specific spec principles (e.g. Onsager's Reach + seam rule, lean-spec's provider-agnostic core + i18n, Duhem's worked-example + schema-impact).
<repo>-dev-process sister skill — carries the area-label taxonomy, the spec-vs-trivial gate, the SDD loop wiring, and the repo's pre-push check gate + CI-failure patterns.
- Global
pre-push / pr-lifecycle skills — the shared pre-push and post-push methodology (installed from onsager-ai/dev-skills). The consumer repo overlays only its gate command, collision patterns, and any pr-spec-sync automation via CLAUDE.md / <repo>-dev-process; the skills themselves are not per-repo.
When in doubt about the target repo, run git remote -v and read the repo's CLAUDE.md and its *-dev-process skill before drafting the spec body.
Why GitHub Issues, Not Files
lean-spec uses Markdown files with YAML frontmatter for metadata. We replace that entirely with GitHub issues because:
- Status → Issue state (open/closed)
- Priority → Labels (
priority:critical, priority:high, priority:medium, priority:low)
- Tags → Labels (
area:<subsystem>, feat, fix, refactor, perf)
- Dependencies → Issue references (
depends on #42) and sub-issues
- Parent/Child → Sub-issues via
mcp__github__sub_issue_write
- Transitions → Issue timeline (automatic, auditable)
- Collaboration → Comments, reactions, assignments, mentions
GitHub gives us versioned metadata, collaboration, and relationship tracking for free. No CLI needed, no frontmatter to manage, no sync problems.
Philosophy
Three principles from lean-spec, universal across consumer repos:
- Context Economy — Keep issue body under ~2000 tokens. Larger features split into parent + child issues. Small specs produce better AI output and better human review.
- Intent Over Implementation — Document the why and what, not the how. Implementation details belong in PRs, not spec issues. The spec captures human intent that isn't in the code.
- Living Documents — Specs evolve via issue comments and edits. The issue's open/closed state tracks lifecycle; the comment thread becomes the decision record.
Each consumer repo may add 1–2 repo-specific principles on top — read the repo's CLAUDE.md and its *-dev-process sister skill before drafting. Examples of overlay principles you'll find in the wild:
- Reach ships with the primitive (Onsager) — new user-facing primitives must scope in nav entry, first-run flow, empty-state CTAs, and auth gating; deferring discoverability is the bad call.
- Provider-agnostic core + i18n (lean-spec) — changes to the provider abstraction declare
## Provider impact; user-visible strings land in both en and zh-CN.
- Worked example + schema impact (Duhem) — product-surface specs ship with a minimal Verification Definition that exercises the surface; schema-touching changes declare
## Schema impact.
If the overlay introduces an additional issue-body section or label (e.g. Provider impact, Schema impact, provider-impact, schema-impact, i18n), apply it. The repo's CLAUDE.md or sister skill is authoritative for which extras it requires.
When to use this skill
Use when:
- A change touches multiple files or subsystems.
- Multiple stakeholders need alignment before implementation.
- The AI needs explicit boundaries for a non-trivial feature.
- Work will span multiple PRs (parent + child specs).
- The change touches an externally observable contract — schema, CLI surface, public API, provider trait, event manifest — regardless of diff size. Consumer repos may name additional always-spec surfaces in their CLAUDE.md or sister skill; honour them.
Skip when:
- A typo or doc-only fix. Use the
trivial label on the PR instead.
- A one-line bug fix with an obvious reproduction. Just open a PR with
Fixes #existing.
- The feature already has a spec issue — extend that spec, don't create another.
Default is spec, not trivial. If invocation of this skill is itself the decision — the user said "spec this" or the change clearly isn't a typo/one-liner — proceed straight to Discover. Do not stop to confirm spec-vs-trivial. The "Skip when" list is a self-veto for unambiguously trivial diffs; everything else is a spec by default. trivial is a sparingly-used escape hatch (see the repo's *-dev-process sister skill and the global pre-push skill), not a 50/50 fork to ask about.
Setup
| Parameter | Default | Example override |
|---|
| Topic | (required) | "session timeout", "fix heartbeat race" |
| Scope | Inferred from codebase | "only stiglab", "only the cli" |
| Priority | medium | critical, high, low |
| Labels | Auto from type + area | "spec, feat, area:<sub>" |
| Parent | None | #42 (umbrella issue) |
If the user says "spec session timeout", start immediately. Do not ask clarifying questions unless the topic is genuinely ambiguous — and do not ask whether the change should be a trivial-labeled PR instead. Invocation of this skill is the decision; the "Skip when" list above is the only place that question gets re-litigated, and only for unambiguously trivial diffs.
Workflow
1. Discover Search existing issues and codebase
2. Design Draft the spec issue body
3. Align Partition human decisions vs AI work
4. Validate Self-check before creating
5. Publish Create GitHub issue (+ sub-issues if splitting)
1. Discover
Before writing anything, understand what exists:
- Search existing GitHub issues on the target repo for related or duplicate specs.
- Grep the codebase for types, functions, modules related to the topic.
- Read key files that will be affected.
- Check git log for recent changes in the area.
- Read the repo's
CLAUDE.md and any canonical product doc it points at (e.g. an architecture doc, an ADR, a docs/<product>-spec.md) — they ground the spec in existing commitments and identify always-spec surfaces.
If a related spec issue already exists, reference it — don't duplicate.
2. Design
Read references/spec-format.md for the section-by-section format guide.
Don't hard-wrap prose, list items, or blockquote lines. GitHub renders issue and comment bodies with breaks: true — every newline inside a paragraph, list item, or blockquote becomes a <br>, producing visible mid-sentence breaks. Source files in many repos wrap at ~70–100 columns; issue bodies must not. Each paragraph, list item, and blockquote line is a single long line; only blank lines separate paragraphs, and each new bullet/quote line starts on its own line. Fenced code blocks and tables preserve formatting and are unaffected. Headings are single-line by markdown's own rules.
Draft the issue body using the lean-spec structure:
## Overview
Problem statement and motivation. Why does this matter?
## Design
Technical approach: data flow, API changes, architecture decisions.
Keep it high-level — intent, not implementation.
## Plan
- [ ] Checklist of concrete deliverables
- [ ] Each item independently verifiable
- [ ] Order reflects implementation sequence
## Test
- [ ] How to verify each plan item
- [ ] Include: unit tests, integration tests, manual checks
## Notes
Tradeoffs, context, references. Optional — omit if empty.
Consumer repos may require additional sections (e.g. ## Provider impact, ## Schema impact, ## Worked example) — read the repo's CLAUDE.md / sister skill for the full list and the rules for when each section is required vs. optional. Templates under templates/ cover the universal shape; consumer-repo overlays may extend the template.
Context economy check: If the issue body exceeds ~2000 tokens, split it:
- Create a parent issue with Overview + high-level Plan
- Create child issues (sub-issues), one per independent concern
- Each child has its own Design, Plan, Test sections
- Link children to parent via
mcp__github__sub_issue_write
3. Align
Add an Alignment section to the issue body (this extends lean-spec for human-AI collaboration):
## Alignment
### Human decides
- [ ] Architectural tradeoffs, scope, UX, go/no-go
### AI implements
- [ ] Concrete code tasks tied to Plan items
### Open questions
> Items that block AI implementation until a human decides
Rules:
- Every Plan item maps to either "Human decides" or "AI implements"
- If an item requires both, split it — the decision part is human, the execution is AI
- Open questions use
> blockquotes so they're visually distinct
- Once a human answers a question (via issue comment), update the Alignment section
4. Validate
Before creating the issue, self-check:
5. Publish
Create the issue using mcp__github__issue_write against the consumer repo:
Title format: spec(<area>): <short description>
<area> is drawn from the consumer repo's area-label taxonomy — read the *-dev-process sister skill (or the repo's CLAUDE.md if the sister skill defers) for the canonical list. Examples observed across consumer repos: spec(stiglab): add session timeout, spec(provider): github provider — issue CRUD via MCP, spec(schema): add api/observe action type.
Labels: Apply via the issue creation:
spec — always, marks this as a spec issue
- Type:
feat, fix, refactor, perf
- Area (consumer-repo taxonomy)
- Priority:
priority:critical, priority:high, priority:medium, priority:low
- Any consumer-repo cross-cutting labels (e.g.
provider-impact, schema-impact, i18n) when the corresponding overlay section is non-empty
Sub-issues: If this is a child of a parent spec, link it using mcp__github__sub_issue_write.
After creating, report to the user:
- Issue number and URL
- Token count estimate (flag if over 2000)
- Any open questions that need human decisions
- Sub-issue links if the spec was split
Status Lifecycle
GitHub issue state alone tracks lifecycle:
open → closed
- open: Spec exists, work may be in flight. Open questions, if any, are resolved in the issue thread.
- closed: All plan items done, tests passing. PR merge with
Closes #N closes it automatically.
No status labels are applied — the issue's open/closed state plus the comment thread is the audit trail. PRs cross-link via Closes #N / Part of #N in the PR body; the global pr-lifecycle skill covers how Plan checkboxes get ticked as Part of PRs land.
Since "in flight" isn't a label anymore, the scripts/ helpers below reconstruct that view on demand — they read the open state plus linked PRs so you can see which open specs are actually being worked.
Spec Relationships via Sub-Issues
Use GitHub sub-issues for parent/child decomposition:
| Relationship | GitHub mechanism | When to use |
|---|
| Parent/Child | Sub-issues (mcp__github__sub_issue_write) | Large feature decomposed into pieces |
| Depends On | Issue body reference (depends on #N) | Spec blocked until another finishes |
| Related | Issue body reference (related: #N) | Loosely connected specs |
Decision rule: Remove the dependency — does the spec still make sense? If no → sub-issue (child). If yes but blocked → depends on.
Example decomposition (shape, not specific to any one repo):
spec(<area>): umbrella feature ← parent issue
├── spec(<area>): concern A ← sub-issue
├── spec(<area>): concern B ← sub-issue
└── spec(<other-area>): UI surface for A+B ← sub-issue
When a contract under a repo's architectural rule splits work across two subsystems (e.g. a back-end producer + a front-end consumer of an event), use the parent-plus-children shape: one parent spec captures the end-to-end slice, one child spec per subsystem captures its half. The contract lives in the parent's Plan; each child scopes to a single area label. Producer and consumer halves can land in separate PRs as long as both close before the parent does — but the parent's Plan should require a contract test that fails until both halves exist.
Guidance
- Small is better. A 500-token spec that captures intent clearly beats a 3000-token spec that tries to cover everything. Split into sub-issues early.
- Discover first. Always search existing issues before creating. Duplicate specs create confusion.
- One concern per issue. If a spec covers two independent changes, split into sub-issues with a shared parent.
- Reference code, not concepts. Point to actual types, functions, files — not abstract ideas. Use concrete paths like
crates/<sub>/src/... or packages/<pkg>/src/... rather than "the foo module."
- Open questions are alignment points. These are where AI must stop and ask a human. Make them explicit, specific, and include the impact of each decision.
- Comments are the decision record. When a human resolves an open question, they comment on the issue. The thread becomes the audit trail.
- Use specs for alignment, not for everything. Regular bugs and small tasks don't need specs. Use specs when: multiple stakeholders need alignment, intent needs persistence, or the AI needs clear boundaries.
Handoff to implementation
Once the spec is ready to implement:
- Create a branch referencing the issue:
claude/spec-<N>-<slug> (Claude-owned) or any name (human-owned).
- Follow the SDD loop in the repo's
*-dev-process sister skill.
- Pre-push via the global
pre-push skill (spec-link check plus the repo's check gate, named in its CLAUDE.md / *-dev-process).
- PR body must include
Closes #N (slice complete) or Part of #N (scaffolding).
- On merge GitHub auto-closes
Closes #N issues; the merger ticks Plan items on Part of #N parents manually. See pr-lifecycle.
Repo-agnostic by construction; consumer overlay is required
This skill is the methodology; it intentionally does not name a repo, an area taxonomy, or a set of cross-cutting labels. Every consumer repo overlays those via:
- Its
CLAUDE.md (repo-specific principles, target GitHub slug, always-spec surfaces).
- Its
*-dev-process sister skill (area-label taxonomy, spec-vs-trivial gate, SDD loop, the repo's pre-push check gate + CI-failure patterns that the global pre-push / pr-lifecycle skills read).
- Optionally an additional product spec doc (e.g.
docs/<product>-spec.md, an architecture ADR set) that the repo's CLAUDE.md points at.
Treat reading those as part of step 1 (Discover). Don't draft a spec without having loaded the consumer repo's overlay context first — a spec that names the wrong area label, misses a required section, or proposes something the repo's seam / schema / provider rule forbids is a spec the human has to rewrite.
References
| Reference | When to read |
|---|
| references/spec-format.md | Always — section-by-section guide with worked examples |
Repo's CLAUDE.md | Always — repo-specific principles + always-spec surfaces |
Repo's *-dev-process sister skill | Always — area-label taxonomy + spec-vs-trivial gate |
pr-lifecycle (global) | When publishing — post-push workflow; the repo's CLAUDE.md says whether it automates pr-spec-sync. |
Scripts
Because no status label is applied, these helpers reconstruct the lifecycle view from issue state + linked PRs so you don't have to open each issue. Both take --repo owner/name (defaults to the current repo) and need gh + jq.
| Script | Purpose |
|---|
| scripts/spec-list.sh | List spec issues with derived activity + area + plan progress. --state open|closed|all, --area <a>. |
scripts/spec-show.sh <N> | Detail one spec: derived activity, every linked PR + its state, plan progress, outstanding open questions. |
Derived-activity legend: ○ todo (open, no PR) · ● in-progress (open, ≥1 PR open) · ◐ partial (open, only merged PRs — e.g. a Part of #N parent) · ✓ done (closed). The SOP lifecycle is still just open → closed; this is a reporting overlay, not new state.
Templates
Consumer repos may ship an extended template alongside this one (e.g. with a ## Provider impact or ## Schema impact block pre-filled). Prefer the consumer-repo extended template when present.