Playbook — Running a Sprint (for PMs)
This playbook walks a project manager through running a complete sprint in Alloy, from backlog grooming through retrospective. Every step uses the API directly — you can script any of it, wire it into Slack, or call it through the MCP server. The guide assumes you already have an Alloy account, an organization, and a project with tickets.
For the full sprint API reference, see Sprints & Boards.
1. Prerequisites and Setup
Set shell variables so the examples are copy-pasteable:
BASE_URL="http://localhost:3000"
TOKEN="<your-access-token>"
PROJECT_ID="<your-project-uuid>"
Confirm you can reach the server:
curl -s "$BASE_URL/health" | jq .
{
"status": "ok",
"service": "alloy",
"version": "0.1.0",
"database": "...",
"db_healthy": true,
"migration_version": "...",
"uptime_seconds": "..."
}
Check your identity:
curl -s "$BASE_URL/api/v1/auth/me" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"user_id": "...",
"org_id": "...",
"email": "...",
"role": "..."
}
CLI shortcut:
alloy auth me
2. Groom the Backlog
Before planning a sprint, review the backlog. List tickets in the project:
curl -s "$BASE_URL/api/v1/projects/$PROJECT_ID/tickets?limit=20" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": "...",
"next_cursor": null,
"has_more": false
}
Update ticket priorities and descriptions as needed:
curl -s -X PATCH "$BASE_URL/api/v1/tickets/$TICKET_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"priority": "High"}' | jq .
{
"id": "...",
"project_id": "...",
"ticket_number": "...",
"title": "...",
"status": "...",
"priority": "High"
}
CLI shortcut:
alloy ticket update $TICKET_ID --priority High
3. Create the Sprint
Define a two-week sprint with a clear goal:
curl -s -X POST "$BASE_URL/api/v1/projects/$PROJECT_ID/sprints" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "Sprint 4 — Payments Integration",
"goal": "Ship Stripe checkout and invoice generation",
"start_date": "2026-04-01",
"end_date": "2026-04-15"
}' | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 4 — Payments Integration",
"goal": "Ship Stripe checkout and invoice generation",
"start_date": "2026-04-01",
"end_date": "2026-04-15",
"status": "Planned",
"created_at": "...",
"updated_at": "..."
}
Save the sprint ID:
SPRINT_ID="<id from above>"
A good sprint goal is specific and outcome-oriented. Avoid goals like “work on payments” — state what ships.
CLI shortcut:
alloy sprint create --project $PROJECT_ID --name "Sprint 4" --goal "Ship Stripe checkout" --start-date 2026-04-01 --end-date 2026-04-15
4. Assign Owners
Every ticket in the sprint should have an assignee. Update a ticket’s assignee:
curl -s -X PATCH "$BASE_URL/api/v1/tickets/$TICKET_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{\"assignee_id\": \"$USER_ID\"}" | jq .
{
"id": "...",
"project_id": "...",
"ticket_number": "...",
"title": "...",
"status": "...",
"assignee_id": "..."
}
Repeat for each ticket. As a PM, make sure every ticket has an owner before the sprint starts — unowned tickets tend to drift.
CLI shortcut:
alloy ticket update $TICKET_ID --assignee $USER_ID
5. Review the Sprint Scope
Before starting, fetch the sprint to confirm it looks right:
curl -s "$BASE_URL/api/v1/sprints/$SPRINT_ID" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 4 — Payments Integration",
"goal": "Ship Stripe checkout and invoice generation",
"start_date": "2026-04-01",
"end_date": "2026-04-15",
"status": "Planned",
"created_at": "...",
"updated_at": "..."
}
Check the sprint board to see what tickets are assigned:
curl -s "$BASE_URL/api/v1/sprints/$SPRINT_ID/board" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"sprint": {
"id": "...",
"name": "...",
"status": "..."
},
"columns": [
{
"status": "...",
"tickets": []
}
]
}
CLI shortcut:
alloy sprint get $SPRINT_ID
6. Start the Sprint
When the team is ready and tickets are assigned, start the sprint:
curl -s -X POST "$BASE_URL/api/v1/sprints/$SPRINT_ID/start" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 4 — Payments Integration",
"goal": "Ship Stripe checkout and invoice generation",
"start_date": "2026-04-01",
"end_date": "2026-04-15",
"status": "Active",
"created_at": "...",
"updated_at": "..."
}
Only one sprint per project should be active at a time. Starting a sprint signals to the team that work begins now.
CLI shortcut:
alloy sprint start $SPRINT_ID
7. Run Daily Standups
Check the sprint board each morning to see where tickets are:
curl -s "$BASE_URL/api/v1/sprints/$SPRINT_ID/board" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"sprint": {
"id": "...",
"name": "...",
"status": "..."
},
"columns": [
{
"status": "...",
"tickets": []
}
]
}
Move tickets between columns by transitioning their status (see Sprints & Boards for transition details). If tickets are stuck, add a comment to flag the issue:
curl -s -X POST "$BASE_URL/api/v1/tickets/$TICKET_ID/comments" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{\"body\": \"Blocked on API credentials from vendor. ETA?\", \"author_id\": \"$USER_ID\"}" | jq .
{
"id": "...",
"ticket_id": "...",
"author_id": "...",
"body": "Blocked on API credentials from vendor. ETA?",
"created_at": "..."
}
CLI shortcut:
alloy comment add $TICKET_ID --body "Blocked on API credentials"
8. Track Progress with Burndown
Check the burndown daily to spot trends early:
curl -s "$BASE_URL/api/v1/sprints/$SPRINT_ID/burndown" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"sprint_id": "...",
"data": [
{
"date": "...",
"total_tickets": 0,
"completed_tickets": 0,
"remaining_tickets": 0
}
]
}
What to look for as a PM:
| Pattern | Signal | Action |
|---|---|---|
| Flat remaining line | No tickets finishing | Check blockers |
| Rising remaining | Scope creep | Cut scope or extend |
| Steep early drop | Team crushing it | Plan for next sprint |
| Cliff at end | Last-minute rush | Improve estimation |
A healthy burndown trends downward steadily. If it flatlines for more than two days mid-sprint, intervene.
9. Mid-Sprint Adjustments
Sometimes scope changes. Update the sprint goal if the direction shifts:
curl -s -X PATCH "$BASE_URL/api/v1/sprints/$SPRINT_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"goal": "Ship Stripe checkout (invoicing moved to Sprint 5)"}' | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 4 — Payments Integration",
"goal": "Ship Stripe checkout (invoicing moved to Sprint 5)",
"start_date": "...",
"end_date": "...",
"status": "Active",
"created_at": "...",
"updated_at": "..."
}
Document why you cut scope — your future self will thank you during retro.
CLI shortcut:
alloy sprint update $SPRINT_ID --goal "Updated goal"
10. Close the Sprint
When the iteration ends, complete the sprint:
curl -s -X POST "$BASE_URL/api/v1/sprints/$SPRINT_ID/complete" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 4 — Payments Integration",
"goal": "...",
"start_date": "...",
"end_date": "...",
"status": "Completed",
"created_at": "...",
"updated_at": "..."
}
Unfinished tickets stay in their current status. Move them to the next sprint or back to the backlog.
CLI shortcut:
alloy sprint complete $SPRINT_ID
11. Run a Retrospective
Use ticket activity and time data to fuel your retro. Pull comments for a ticket to review discussion threads:
curl -s "$BASE_URL/api/v1/tickets/$TICKET_ID/comments" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"ticket_id": "...",
"author_id": "...",
"body": "...",
"created_at": "..."
}
],
"next_cursor": null,
"has_more": false
}
Key retro questions for PMs:
- Did we hit the sprint goal?
- Which tickets carried over, and why?
- Were estimates accurate? Where did we over/underestimate?
- Were there blockers we could have anticipated?
- What should we do differently next sprint?
12. Plan the Next Sprint
Create the next sprint and assign carryover tickets. List all sprints to see what has been completed:
curl -s "$BASE_URL/api/v1/projects/$PROJECT_ID/sprints" \
-H "Authorization: Bearer $TOKEN" | jq .
{
"items": [
{
"id": "...",
"project_id": "...",
"name": "...",
"status": "..."
}
],
"next_cursor": null,
"has_more": false
}
Create the next sprint:
curl -s -X POST "$BASE_URL/api/v1/projects/$PROJECT_ID/sprints" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "Sprint 5 — Invoicing & Notifications",
"goal": "Ship invoice generation and email notifications",
"start_date": "2026-04-16",
"end_date": "2026-04-30"
}' | jq .
{
"id": "...",
"project_id": "...",
"name": "Sprint 5 — Invoicing & Notifications",
"goal": "Ship invoice generation and email notifications",
"start_date": "2026-04-16",
"end_date": "2026-04-30",
"status": "Planned",
"created_at": "...",
"updated_at": "..."
}
Each sprint should improve on the last. Use retro insights to adjust sprint length, team capacity, and scope.
CLI shortcut:
alloy sprint create --project $PROJECT_ID --name "Sprint 5" --goal "Ship invoicing" --start-date 2026-04-16 --end-date 2026-04-30