speclet-ticket
Convert a large draft into individual tickets for isolated implementation sessions
When & Why to Use This Skill
The speclet-ticket skill is a specialized project management tool designed to bridge the gap between high-level planning and technical execution. It automates the decomposition of large, complex draft documents into atomic, independent implementation tickets. By organizing work into isolated sessions with dedicated metadata and status tracking, it optimizes LLM performance, prevents context bleed, and ensures a structured, manageable workflow for complex software development tasks.
Use Cases
- Breaking down a comprehensive feature specification into small, independent coding tasks to ensure maximum atomicity.
- Managing large-scale refactoring projects by isolating individual friction points into separate, trackable implementation sessions.
- Optimizing AI-assisted development by splitting large drafts into smaller units that fit comfortably within LLM context window limits.
- Establishing a centralized progress tracking system for multi-session workflows using the automatically generated index.json and ticket metadata.
- Transitioning from a general brainstorming or analysis phase to a structured, execution-ready ticket-by-ticket implementation cycle.
| name | speclet-ticket |
|---|---|
| description | Convert a large draft into individual tickets for isolated implementation sessions |
| license | MIT |
| compatibility | opencode |
| workflow | speclet |
| phase | planning |
Speclet Ticket Skill
Convert a large draft document into individual tickets for isolated implementation sessions.
What I Do
- Read
.speclet/draft.mdand identify discrete work items - Create ticket folders at
.speclet/tickets/TICKET-N/ - Generate ticket metadata at
.speclet/tickets/TICKET-N/ticket.json - Copy general draft to
.speclet/tickets/TICKET-N/ticket-draft.md - Create/update
.speclet/tickets/index.jsonfor centralized status tracking - Delete root
draft.mdonly after ALL tickets are successfully created - Enable ticket-by-ticket workflow: one ticket → one session → full speclet cycle
When to Use Me
Use this when:
- A draft contains multiple independent fixes/features
- The combined scope would overwhelm LLM context
- You want to work on items one at a time across sessions
Your Task
Step 1: Read the Draft
Read .speclet/draft.md
Identify discrete work items. Each item that can be implemented independently = 1 ticket.
Splitting Rule: 1 ticket = 1 friction/problem. Maximum atomicity.
Step 2: Ask Clarifying Questions (if needed)
If the draft is ambiguous about how to split, ask questions with lettered options.
Example:
1. How should I group these items?
A. One ticket per file mentioned ⭐ Recommended — maximum isolation
B. Group by feature area
C. Group by complexity
D. Keep as single ticket
**Reason for recommendation:** Isolated tickets prevent context bleed and allow
prioritization between sessions.
Global Rules
Always Show Recommendation + Reason
When asking questions with options, ALWAYS:
- Mark the recommended option with ⭐
- Add
**Reason for recommendation:**explaining why
Example format:
1. [Question]?
A. Option A
B. Option B ⭐ Recommended — [brief reason]
C. Option C
**Reason for recommendation:** [Detailed explanation of why B is best]
Step 3: Create Ticket Files and Folders
For each discrete item:
- Create ticket folder:
.speclet/tickets/TICKET-N/ - Copy draft to folder:
.speclet/tickets/TICKET-N/ticket-draft.md - Create ticket JSON:
.speclet/tickets/TICKET-N/ticket.json
IMPORTANT: Complete ALL tickets before proceeding to Step 4. Do NOT delete draft.md until all tickets exist.
Ticket JSON Structure
{
"specletVersion": "1.0",
"id": "TICKET-1",
"title": "Short descriptive title",
"description": "2-3 sentences explaining the problem/friction and desired outcome",
"files": ["path/to/likely/affected/file.ts"],
"sourceContext": ".speclet/draft.md",
"preliminaryCriteria": [
"Preliminary acceptance criterion (will be refined in speclet-draft)",
"Another criterion"
],
"priority": 1,
"dependsOn": [],
"retryHints": [],
"status": "pending"
}
Field Descriptions
| Field | Required | Description |
|---|---|---|
specletVersion |
Yes | Always "1.0" — identifies this as a speclet ticket |
id |
Yes | Unique identifier (TICKET-1, TICKET-2, etc.) |
title |
Yes | Short title (< 80 chars) |
description |
Yes | 2-3 sentences explaining the problem and desired outcome |
files |
Yes | Array of likely affected files (best guess, refined later) |
sourceContext |
Yes | Absolute path to the original source document with optional anchor |
preliminaryCriteria |
Yes | Initial acceptance criteria (refined during speclet-draft) |
priority |
Yes | Numeric priority (1 = highest) |
dependsOn |
No | Array of ticket IDs that must complete first |
retryHints |
No | Accumulated hints from failed attempts |
status |
Yes | One of: pending, in_progress, done, blocked |
specletVersion Field (CRITICAL)
The specletVersion field is mandatory. It serves two purposes:
- Identification: Allows
speclet-draftto recognize this as a speclet-generated ticket - Compatibility: Future versions can check compatibility
If specletVersion is missing, other skills will NOT recognize this as a speclet ticket.
sourceContext Best Practices
The sourceContext field must point to the original source of the requirement:
✅ Good sourceContext values:
.speclet/draft.mdGitHub Issue #123Code review comment on PR #456
❌ Bad sourceContext values:
TICKET-1.json— Self-referential"From the analysis"— Not traceable
Step 4: Create/Update Index
Create or update .speclet/tickets/index.json:
{
"specletVersion": "1.0",
"source": "docs/original-analysis.md",
"createdAt": "2025-01-09T15:30:00Z",
"tickets": [
{
"id": "TICKET-1",
"title": "Fix empty state guidance",
"status": "pending",
"priority": 1
},
{
"id": "TICKET-2",
"title": "Improve serial scanner UX",
"status": "pending",
"priority": 2
}
]
}
Note: The source field in index.json should point to the original source document .speclet/draft.md.
Step 5: Delete Root Draft (ONLY AFTER ALL TICKETS CREATED)
Pre-condition check (MANDATORY):
Before deleting, verify:
- All ticket folders exist:
.speclet/tickets/TICKET-1/,.speclet/tickets/TICKET-2/, etc. - Each folder has
ticket.jsonandticket-draft.md index.jsonexists and lists all tickets
# Verification command
ls .speclet/tickets/*/ticket.json | wc -l # Should equal number of tickets
ls .speclet/tickets/*/ticket-draft.md | wc -l # Should equal number of tickets
Only if verification passes:
rm .speclet/draft.md
If verification fails: STOP. Do not delete draft.md. Report which tickets are missing.
This ensures:
- No confusion about which draft to use
- Clean state for next workflow
- Each ticket has its own
ticket-draft.mdas context
Step 6: Confirm with User
After creating tickets, summarize:
✅ Created N tickets from draft.md
| ID | Title | Priority | Dependencies |
|----|-------|----------|--------------|
| TICKET-1 | [title] | 1 | - |
| TICKET-2 | [title] | 2 | TICKET-1 |
📁 Structure created:
.speclet/tickets/
├── index.json
├── TICKET-1/
│ ├── ticket.json
│ └── ticket-draft.md
├── TICKET-2/
│ ├── ticket.json
│ └── ticket-draft.md
🗑️ Deleted: .speclet/draft.md
**Next steps:**
1. Start new session
2. Pick a ticket: "Use speclet-draft for TICKET-1"
3. Complete full cycle: draft → spec → loop
4. Come back for next ticket
Workflow Integration
PHASE 1: Analysis (this session)
────────────────────────────────
speclet-draft (general analysis)
│
▼
.speclet/draft.md
│
▼
speclet-ticket (this skill)
│
├── Creates .speclet/tickets/TICKET-N/ticket.json
├── Creates .speclet/tickets/TICKET-N/ticket-draft.md
├── Creates .speclet/tickets/index.json
├── Verifies ALL tickets created successfully
├── Deletes .speclet/draft.md (only after verification)
└── END of session
════════════════════════════════════════════════════════════
PHASE 2: Per-ticket work (new session)
──────────────────────────────────────
User: "speclet-draft for TICKET-1"
│
├── Reads .speclet/tickets/TICKET-1/ticket.json (validates specletVersion)
├── Reads .speclet/tickets/TICKET-1/ticket-draft.md
├── Asks clarifying questions
└── Creates .speclet/draft.md (refined)
│
▼
speclet-spec → .speclet/spec.json
│
▼
speclet-loop → implements
│
▼
On completion:
├── Move draft.md → tickets/TICKET-1/draft.md
├── Move spec.json → tickets/TICKET-1/spec.json
├── Update ticket.json status to "done"
└── Ready for next ticket
Post-Completion Artifact Preservation
After completing a ticket with speclet-loop, preserve artifacts:
# Move refined draft (keeps ticket-draft.md as original context)
mv .speclet/draft.md .speclet/tickets/TICKET-1/draft.md
# Move spec
mv .speclet/spec.json .speclet/tickets/TICKET-1/spec.json
# Update ticket status
# Edit .speclet/tickets/TICKET-1/ticket.json: "status": "done"
Final structure for completed ticket:
.speclet/tickets/TICKET-1/
├── ticket.json ← Metadata (status: done)
├── ticket-draft.md ← Original context (from speclet-ticket)
├── draft.md ← Refined draft (from speclet-draft for TICKET-1)
└── spec.json ← Implementation spec (from speclet-spec)
Rules
- One friction = one ticket — Maximum atomicity
- specletVersion required — All tickets must have
"specletVersion": "1.0" - ticket-draft.md in each folder — Copy of general draft for context
- Delete root draft after tickets — Clean state for next workflow
- Dependencies are declarative — Field exists but no automated blocking
- Preliminary criteria only — Real criteria come from speclet-draft
- Status tracking — Update index.json when ticket status changes
- sourceContext = original source — Point to real origin, not speclet artifacts
Output
- Ticket folders:
.speclet/tickets/TICKET-N/ - Ticket metadata:
.speclet/tickets/TICKET-N/ticket.json - Ticket context:
.speclet/tickets/TICKET-N/ticket-draft.md - Central index:
.speclet/tickets/index.json - Root draft: DELETED (only after all tickets verified)
When complete:
"Tickets created in
.speclet/tickets/. Root draft deleted. Start new session and use: speclet-draft for TICKET-1"