Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install seb155-atlas-plugin-skills-to-issuesgit clone https://github.com/seb155/atlas-plugin.gitcp atlas-plugin/SKILL.MD ~/.claude/skills/seb155-atlas-plugin-skills-to-issues/SKILL.md---
name: to-issues
description: "Decompose spec/PRD into vertical-slice Forgejo issues. Use when 'break down spec', 'create issues from plan', 'decompose feature X', 'plan to issues', or after to-prd output."
mode: [engineering]
effort: medium
version: 1.0.0
tier: [admin]
attribution: "Cherry-picked from mattpocock/skills (MIT, see CREDITS.md)"
---
# To Issues — Vertical-Slice Decomposition
Convert a spec, PRD, or engineering plan into independently-grabbable Forgejo issues using **tracer-bullet vertical slices**. Each issue is a thin slice cutting through ALL integration layers (DB + API + UI + test) end-to-end — never a horizontal slice of one layer alone.
**Announce:** "Decomposing into vertical-slice issues using to-issues..."
## When to invoke
- User says: "break down this spec", "create issues from plan", "decompose feature X", "plan to issues"
- After `to-prd` produces a PRD that needs sprint breakdown
- After `plan-builder` produces a plan and you need shippable tickets
- A Forgejo issue body contains a plan that needs sub-issue tracking
## Anti-pattern: Horizontal slicing (DO NOT DO THIS)
Horizontal slices ship one layer at a time and are useless until the last layer lands. Examples:
- ❌ "Issue 1: Add `widgets` table migration"
- ❌ "Issue 2: Build `WidgetService` backend"
- ❌ "Issue 3: Wire `/api/v1/widgets` route"
- ❌ "Issue 4: Build widget list UI"
Each issue blocks the next. Nothing demoable until issue 4 ships. Reviewer cannot validate slice 1 in isolation. **This is sequential layer-stacking masquerading as decomposition.**
## Pattern: Vertical slicing (the only correct way)
Each slice ships a small but **end-to-end user-visible behavior**, traversing every layer. Examples:
- ✅ "Issue 1: User can list widgets (read-only, hard-coded styles, 1 column)"
- ✅ "Issue 2: User can create a widget with name only (validation deferred)"
- ✅ "Issue 3: User can filter widget list by status (single dropdown)"
- ✅ "Issue 4: User can edit widget name inline"
Each issue is **demoable and shippable in isolation**. Reviewer validates the user behavior end-to-end. Slices may be ordered by dependency (issue 4 needs issue 2 first), but each lands as a complete vertical pass through schema → API → UI → test.
<vertical-slice-rules>
- Each slice delivers a narrow but COMPLETE path through every layer (schema/migration, service, route, UI, test)
- A completed slice is demoable or verifiable on its own (one curl + one screenshot)
- Prefer many thin slices over few thick ones (target: 1-3 days per slice)
- Slice size capped: if implementing a slice exceeds 3 days, split it
- HITL slices (architectural decision, UX review) explicitly tagged; prefer AFK slices when possible
</vertical-slice-rules>
## Decomposition algorithm
1. **Parse input** — read source spec/PRD/plan (markdown file path, Forgejo issue number, or paste). Extract: user-visible behaviors, acceptance criteria, constraints, glossary terms.
2. **Identify behavior changes** — list every "user can now do Y" statement. Each behavior = candidate slice.
3. **For each behavior, sketch the change-set** — schema delta + service method + route handler + UI element + test. If any layer is "no change", note that explicitly.
4. **Bundle into vertical slices** — one slice per behavior unless two behaviors share 80%+ change-set (rare). Cap each slice at 1-3 days.
5. **Order by dependency** — slices that need DB columns from another slice list it as `Blocked by`. Most slices should be **independent** (parallel-shippable).
6. **Tag HITL vs AFK** — slice needs human decision (architecture, UX choice, security review)? Mark `HITL`. Otherwise `AFK` (an agent can implement + ship without intervention).
7. **HITL gate before publishing** — present numbered list, ask user to confirm granularity / dependencies / HITL flags. Iterate until approved.
8. **Publish in dependency order** — blockers first, so children can reference real issue numbers in `Blocked by`.
## CLI
```bash
# Default: dry-run, output preview only (NO Forgejo writes)
atlas to-issues <spec-path-or-issue-num>
# Actually create issues in Forgejo (REQUIRES HITL confirmation)
atlas to-issues <spec> --create-in <owner/repo>
# Cap slice count (default 10)
atlas to-issues <spec> --max-issues 8
# Force HITL preview even with --create-in (default behavior already)
atlas to-issues <spec> --create-in <owner/repo> --dry-run
# Apply specific labels (default: needs-triage,vertical-slice)
atlas to-issues <spec> --create-in <owner/repo> --labels enhancement,sprint-2.6
# Link all issues as sub-tasks of a parent issue
atlas to-issues <spec> --create-in <owner/repo> --parent 142
```
**Default flag is `--dry-run`.** Issue creation only fires when `--create-in <repo>` is set AND user confirms via AskUserQuestion. This is a non-negotiable HITL gate.
## Workspace Mode (v8.1.0+)
When ATLAS workspace is detected, this skill emits a batch of WI files to workspace `backlog/_inbox/` AND creates corresponding Forgejo issues, cross-linked.
This is a **DUAL WRITE** : N Forgejo issues (existing) + N workspace WI files (new).
### Process
1. Check workspace state :
```bash
if [ -f ~/.atlas/runtime/workspace.json ]; then
WS_ROOT=$(python3 -c "import json; print(json.load(open('$HOME/.atlas/runtime/workspace.json'))['workspace']['root'])")
fi
```
2. For each vertical slice :
- Generate `WI_ID = ops/next-id.py` (sequential, year-scoped)
- Create Forgejo issue → capture `issue_number` and `html_url`
- Write `backlog/_inbox/{WI_ID}-{slug}.md` (write_auto, no HITL) :
```yaml
---
id: WI-2026-NNNN
type: feature # vertical slices are features
status: backlog
owner: unassigned
product: {auto-detect from PRD context}
priority: P2 # auto, refined later
effort: {auto-estimate XS/S/M/L based on slice complexity}
created: {ISO 8601}
created_by: {workspace user}
atlas_session_id: {ATLAS_SESSION_ID}
labels: [vertical-slice, needs-triage]
links:
forgejo_issue: {issue url}
parent_prd: WI-2026-{parent} # cross-link to PRD WI
blocked_by: [WI-2026-X, WI-2026-Y]
---
# {Issue title}
{full body}
```
3. Update parent PRD WI's `links.children: [WI-...]` field for traceability.
4. Audit log : each write triggers `workspace-audit` hook entry.
### Backwards compatibility
- If workspace NOT detected : Forgejo-only batch (existing)
- Plugin v7.16.1 / v8.0.0 : no behavior change
## Forgejo API
Issue create endpoint: `POST /repos/{owner}/{repo}/issues`
```bash
source ~/.env # FORGEJO_API + FORGEJO_TOKEN
curl -X POST "$FORGEJO_API/repos/$OWNER/$REPO/issues" \
-H "Authorization: token $FORGEJO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "User can list widgets (read-only)",
"body": "<rendered template>",
"labels": ["needs-triage", "vertical-slice"]
}'
```
Capture returned `number` from each create call to fill `Blocked by` references in subsequent issues.
Reference: `.claude/references/forgejo-api.md`.
## Issue body template
````markdown
## Parent
Optional reference to parent plan or epic (omit if standalone).
## What to build
End-to-end behavior in 2-4 sentences. Describe what the **user can do** after this slice ships, not the internal layers. Example: "User can filter widget list by status via a dropdown above the grid. Filter resets on navigation."
## Vertical slice contents
- [ ] Schema/migration: <describe or "no change">
- [ ] Service: <method name + 1-line behavior>
- [ ] Route: <HTTP verb + path>
- [ ] UI: <component / page change>
- [ ] Test: <smoke entry + unit test path per TVT tier>
## Acceptance criteria
- [ ] Criterion 1 (observable behavior, not implementation)
- [ ] Criterion 2
- [ ] Criterion 3
## Type
`AFK` (agent can ship solo) **OR** `HITL` (requires human decision: <reason>)
## Blocked by
- #N — <slice title> (or "None — can start immediately")
## TVT tier
T2 / T3 / T4 (per `.claude/rules/test-value-tiering.md`)
## Source
Plan / PRD reference (file path or issue number).
````
## HITL gate (non-negotiable)
Before any Forgejo API write:
1. Render numbered list of slices (title + type + blocked-by + user stories covered).
2. Ask user via AskUserQuestion:
- "Granularity OK? (too coarse / too fine / fine)"
- "Dependencies correct?"
- "Should any slices be merged or split?"
- "HITL/AFK tags accurate?"
3. Iterate until user explicitly approves.
4. Only then call Forgejo API in dependency order.
Never publish issues silently. The HITL gate is the entire point of `--dry-run` being default.
## Reuse and pairing
| Skill | Relationship |
|-------|--------------|
| `to-prd` (W4.6 upstream) | Produces the PRD that `to-issues` consumes |
| `plan-builder` | Top-down 15-section plan (complementary; use plan-builder for architecture, to-issues for sprint breakdown) |
| `forgejo-pr` | After issues are created, each AFK slice opens a PR closing its issue |
| `task-framing` | Use BEFORE to-issues to assess complexity; trivial work skips decomposition |
**Workflow chain**: `to-prd` → `to-issues` (this skill) → `plan-builder` (per-slice if complex) → implementation → `forgejo-pr` per slice.
## Domain glossary respect
When titling and describing issues, use the project's domain vocabulary:
- Synapse: Part lifecycle (G→E→M→I→S), Engineering Chain (IMPORT→CLASSIFY→ENGINEER→...), MBSE 4-layer (QUOI/OÙ/COMMENT/QUI)
- AXOIQ: Programme PROG-003, G-gates (G0-G7), Personas (I&C/EL/ME/...)
Mismatched terminology = friction in PR review. Always extract glossary from the source spec; if absent, ask user.
## Counter-examples (rejected slice patterns)
| Bad slice title | Why rejected | Fixed slice title |
|---|---|---|
| "Implement WidgetService" | Layer-only (no user value) | "User can list widgets (read-only)" |
| "Add widgets table migration" | Layer-only | (rolled into "User can create a widget") |
| "Refactor router for v2" | No user-facing behavior | (split into specific behavior changes) |
| "Build full widget feature" | Too thick (weeks of work) | (split into 4-6 thin slices) |
| "Add tests for widget service" | Tests are part of every slice, not their own slice | (folded into slice acceptance criteria) |
If a proposed slice matches one of these patterns, reject and re-decompose.
## Pocock attribution
Adapted from `mattpocock/skills/engineering/to-issues` (MIT). Synapse-specific changes:
- Forgejo API instead of GitHub CLI
- TVT tier field in template (Synapse convention)
- Vertical-slice contents checklist (schema/service/route/UI/test) — explicit Synapse stack mapping
- Default `--dry-run` flag (HITL gate hardened beyond Pocock's quiz step)
- AFK/HITL terminology preserved
- Issue ordering by dependency preserved
See `CREDITS.md` for full attribution chain.
## References
- Pocock origin: https://github.com/mattpocock/skills (engineering/to-issues)
- Forgejo API: `.claude/references/forgejo-api.md`
- TVT rule: `.claude/rules/test-value-tiering.md`
- Plan-builder: `skills/plan-builder/SKILL.md`
- Forgejo-pr: `skills/forgejo-pr/SKILL.md`
- Memory: `memory/lesson_cherrypick_distribute_vs_dedicated_wave.md`