Ticket-Driven Development
Use tickets to guide AI agents through structured development workflows.
Difficulty: Intermediate Time: 15 minutes
What You'll Build
A workflow that:
- Uses tickets to define work
- Has agents implement changes
- Tracks progress automatically
- Links conversations to tickets
TBD: Replace with screenshot of ticket-driven workflow
Prerequisites
The Workflow
┌──────────┐ ┌───────────┐ ┌──────────┐ ┌──────────┐
│ Create │───→│ Plan │───→│ Implement│───→│ Review │
│ Ticket │ │ Agent │ │ Agent │ │ Agent │
└──────────┘ └───────────┘ └──────────┘ └──────────┘
│ │ │ │
└───────────────┴───────────────┴───────────────┘
All linked to ticketStep 1: Create a Well-Structured Ticket
Good tickets guide agents effectively.
Ticket Structure
yaml
id: T-042
title: Add user profile avatar upload
type: feature
priority: medium
status: planned
description: |
## Overview
Users should be able to upload and change their profile avatar.
## Requirements
- Accept JPEG, PNG, GIF (max 5MB)
- Crop to square aspect ratio
- Store in cloud storage
- Display in header and profile page
## Technical Notes
- Use existing FileUpload component
- Store in S3 bucket
- Generate thumbnails (64px, 128px, 256px)
## Acceptance Criteria
- [ ] User can upload image from profile settings
- [ ] Image is cropped to square
- [ ] Thumbnails are generated
- [ ] Avatar displays throughout app
- [ ] Old avatar is replaced on re-upload
subtasks:
- title: Design upload UI
status: pending
- title: Implement backend upload endpoint
status: pending
- title: Add image processing
status: pending
- title: Update profile display components
status: pending
- title: Write tests
status: pendingStep 2: Create Development Agents
Planning Agent
yaml
name: Technical Planner
description: Creates implementation plans from tickets
systemPrompt: |
You are a senior developer creating implementation plans.
Given a ticket:
1. Analyze requirements thoroughly
2. Break down into concrete tasks
3. Identify dependencies and order
4. Note potential challenges
5. Estimate complexity
Output a detailed, actionable plan.
model: claude-opus-4-6
thinkingLevel: think-hard
mcpServers:
- sciorex-tickets
allowedTools:
- tool: Read
allowed: true
- tool: Glob
allowed: true
- tool: Grep
allowed: trueImplementation Agent
yaml
name: Feature Developer
description: Implements features based on plans
systemPrompt: |
You are a skilled developer implementing features.
Follow the plan closely:
- Write clean, tested code
- Follow existing patterns
- Update subtask status as you progress
- Ask for clarification when needed
model: claude-sonnet-5-0
thinkingLevel: think
mcpServers:
- sciorex-tickets
- sciorex-interactions
allowedTools:
- tool: Read
allowed: true
- tool: Write
allowed: true
- tool: Edit
allowed: true
- tool: Glob
allowed: true
- tool: Grep
allowed: true
- tool: Bash
allowed: trueReview Agent
yaml
name: Code Reviewer
description: Reviews implementations against requirements
systemPrompt: |
You are a thorough code reviewer.
Check implementations against:
- Ticket requirements
- Acceptance criteria
- Code quality standards
- Test coverage
Provide specific, actionable feedback.
model: claude-sonnet-5-0
thinkingLevel: think
mcpServers:
- sciorex-ticketsStep 3: The Development Session
Start with Planning
- Open a chat with Technical Planner
- Link to the ticket
- Request a plan:
Plan the implementation for ticket T-042 (avatar upload feature).
Review the existing codebase for relevant patterns.The agent will:
- Read the ticket details
- Explore the codebase
- Create a detailed plan
Implement with Tracking
- Switch to Feature Developer
- Continue in the same ticket context:
Implement the plan for T-042. Start with the first subtask.
Update subtask status as you complete each one.The agent will:
- Follow the plan
- Write code
- Mark subtasks complete via MCP
- Ask questions when stuck
Review Before Completion
- Switch to Code Reviewer
- Request review:
Review the implementation for T-042 against the requirements.
Check all acceptance criteria are met.Step 4: Automate with a Flow
Create a flow for repeatable ticket processing:
┌────────────┐ ┌──────────┐ ┌───────────┐ ┌────────────┐
│ Ticket │───→│ Planner │───→│ Developer │───→│ Condition │
│ Updated │ │ Agent │ │ Agent │ │ (passed?) │
└────────────┘ └──────────┘ └───────────┘ └────────────┘
│
┌────────────────┴────────────────┐
▼ ▼
[passed] [default]
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ Mark Done│ │ Fix Loop │
└──────────┘ └──────────┘Flow Configuration
json
{
"name": "Ticket Development Pipeline",
"nodes": [
{
"id": "trigger",
"type": "trigger",
"label": "Ticket Updated",
"config": {},
"position": { "x": 0, "y": 0 },
"triggerType": "ticket-updated",
"triggerConfig": {
"ticketFilter": {
"status": "in_progress"
}
}
},
{
"id": "plan",
"type": "agent",
"label": "Plan",
"config": {},
"position": { "x": 250, "y": 0 },
"agentId": "technical-planner",
"inputMapping": {
"ticketId": "trigger.input.ticketId"
},
"outputMapping": {},
"worktreeMode": "new",
"worktreeConfig": {
"label": "ticket-implementation",
"baseBranch": "main",
"autoMergeOnSuccess": true,
"cleanupOnComplete": true
}
},
{
"id": "implement",
"type": "agent",
"label": "Implement",
"config": {},
"position": { "x": 500, "y": 0 },
"agentId": "feature-developer",
"inputMapping": {
"plan": "nodes.plan.output",
"ticketId": "trigger.input.ticketId"
},
"outputMapping": {},
"worktreeMode": "inherit",
"inheritWorktreeFromNodeId": "plan"
},
{
"id": "review",
"type": "agent",
"label": "Review",
"config": {},
"position": { "x": 750, "y": 0 },
"agentId": "code-reviewer",
"inputMapping": {
"ticketId": "trigger.input.ticketId",
"implementation": "nodes.implement.output"
},
"outputMapping": {},
"worktreeMode": "inherit",
"inheritWorktreeFromNodeId": "plan"
},
{
"id": "checkPassed",
"type": "condition",
"label": "Review Passed?",
"config": {},
"position": { "x": 1000, "y": 0 },
"conditions": [
{
"path": "nodes.review.output.passed",
"operator": "eq",
"value": true
}
],
"targetNodeId": "markDone",
"defaultTargetNodeId": "fixLoop"
},
{
"id": "markDone",
"type": "ticket_action",
"label": "Mark Done",
"config": {},
"position": { "x": 1250, "y": -100 },
"action": "update_status",
"actionParams": {
"ticketId": "trigger.input.ticketId",
"status": "done"
}
},
{
"id": "fixLoop",
"type": "agent",
"label": "Fix Issues",
"config": {},
"position": { "x": 1250, "y": 100 },
"agentId": "feature-developer",
"inputMapping": {
"feedback": "nodes.review.output",
"ticketId": "trigger.input.ticketId"
},
"outputMapping": {},
"worktreeMode": "inherit",
"inheritWorktreeFromNodeId": "plan",
"reuseSessionOnLoop": true
},
{
"id": "endSuccess",
"type": "end",
"label": "Done",
"config": {},
"position": { "x": 1500, "y": -100 },
"endType": "success"
},
{
"id": "endFixed",
"type": "end",
"label": "Fixed",
"config": {},
"position": { "x": 1500, "y": 100 },
"endType": "success"
}
],
"edges": [
{ "id": "e1", "source": "trigger", "target": "plan" },
{ "id": "e2", "source": "plan", "target": "implement" },
{ "id": "e3", "source": "implement", "target": "review" },
{ "id": "e4", "source": "review", "target": "checkPassed" },
{ "id": "e5", "source": "checkPassed", "target": "markDone", "label": "passed" },
{ "id": "e6", "source": "checkPassed", "target": "fixLoop", "label": "needs fixes" },
{ "id": "e7", "source": "markDone", "target": "endSuccess" },
{ "id": "e8", "source": "fixLoop", "target": "endFixed" }
],
"variables": {},
"maxIterations": 5
}Key features in this flow:
- Worktree isolation: The planner creates a new worktree, and subsequent agents inherit it — all work happens in an isolated branch
- Session reuse: The fix loop agent uses
reuseSessionOnLoop: trueto continue its previous conversation - Auto-merge: On success, the worktree branch merges back to main
Best Practices
Ticket Quality
| Element | Purpose |
|---|---|
| Clear title | Quick identification |
| Detailed description | Full context |
| Acceptance criteria | Definition of done |
| Technical notes | Implementation hints |
| Subtasks | Progress tracking |
Agent Instructions
- Reference ticket explicitly: "for ticket T-042"
- Request status updates: "mark subtasks complete"
- Ask for ticket context: "read the ticket requirements"
Session Linking
Always link sessions to tickets:
- Set ticket context before starting
- Or archive completed sessions to tickets
Example: Bug Fix Workflow
yaml
# Ticket
id: T-099
title: Fix login timeout on slow connections
type: bug
priority: high
description: |
Users on slow connections get logged out unexpectedly.
## Steps to Reproduce
1. Throttle network to 3G
2. Attempt login
3. Wait 10 seconds
## Expected
Login completes successfully
## Actual
Session times out, user sees error
## Technical Context
- Auth timeout is 5 seconds
- Should be increased or made configurableAgent conversation:
You: Fix bug T-099. Read the ticket and investigate the issue.
Agent: I've read ticket T-099. The issue is a 5-second auth timeout.
Let me search for the timeout configuration...
Found it in src/config/auth.ts:15
The AUTH_TIMEOUT is hardcoded at 5000ms.
I'll make this configurable with a higher default.
[Makes changes]
Done. I've:
1. Added AUTH_TIMEOUT to environment config
2. Set default to 30000ms (30 seconds)
3. Updated the auth service to use the config
Marking ticket as ready for review.Tips
- Write good tickets: Garbage in, garbage out
- Use subtasks: Break work into trackable pieces
- Link everything: Sessions, commits, discussions
- Review before closing: Verify requirements are met
- Update status: Keep tickets current
- Use worktrees: Isolate ticket work in dedicated branches
