Pipeline Tracker
Tracks ticket-to-PR pipeline runs, syncs status to Notion, and provides a dashboard view.
Commands
Parse the user's request to determine which command to run:
status(default) - Show dashboard of all runssync- Update Notion with current statusresume {ticket-id}- Resume a paused runarchive- Clean up completed runscheck-merged- Check for merged PRs and update Notion to Done
Configuration
RUNS_DIR="$HOME/repos/ticket-to-pr-pipeline/runs"
NOTION_DATABASE="Comfy Tasks"
Command: status (default)
Scan runs directory:
ls "$HOME/repos/ticket-to-pr-pipeline/runs/"For each run directory, read
status.json:cat "$HOME/repos/ticket-to-pr-pipeline/runs/{ticket-id}/status.json"Present dashboard:
# Pipeline Dashboard ## Active Runs | Ticket | Status | Phase | PR | Last Updated | | ------- | ---------- | -------------- | ---- | ------------ | | {title} | 🟢 Active | research | - | 2h ago | | {title} | 🟡 Review | pr-created | #123 | 1d ago | | {title} | 🔴 Blocked | implementation | - | 3d ago | ## Details ### {Ticket Title} - **Notion:** {ticketUrl} - **Status:** {status} - **Started:** {startedAt} - **Last Updated:** {lastUpdated} - **PR:** {prUrl or "not created"} - **Blockers:** {blockers array or "none"}Offer options:
Options: A) Sync all to Notion B) View details for specific run C) Resume a run D) Archive completed runs
Status Icons
- 🟢 Active: research, planning, tasking, implementation
- 🟡 Review: review, qa, pr-ready, pr-created
- 🔴 Blocked: blocked
- ✅ Done: done
Command: sync
Update Notion with current pipeline status.
⚠️ Follow Notion Write Safety rules for all writes.
For each active run:
- Read
ticket.jsonfor Notion page ID (required - skip if missing) - Read
status.jsonfor current phase and previous Notion status
- Read
Map phase to Notion Status:
Pipeline Phase Notion Status research, planning, tasking, implementation In Progress review, qa, pr-ready, pr-created In Review done Done blocked (keep current) Validate before each write:
- Page ID exists in ticket.json
- Status transition is valid (see safety doc)
- PR URL matches
^https://github\.com/[^/]+/[^/]+/pull/\d+$
Update Notion using MCP:
- Update Status property (only if transition valid)
- Update GitHub PR property if prUrl exists
- Ensure Assignee is set (assign only, never unassign)
Log each write to
status.json:{ "field": "Status", "value": "In Review", "previousValue": "In Progress", "at": "...", "skill": "pipeline-tracker", "success": true }Report results:
Synced {X} runs to Notion: - {Ticket 1}: Status → In Progress ✅ - {Ticket 2}: Status → In Review, PR → #123 ✅ - {Ticket 3}: Skipped (invalid transition Done → In Progress)
Command: resume {ticket-id}
Resume a paused or stale pipeline run.
Load status:
cat "$HOME/repos/ticket-to-pr-pipeline/runs/{ticket-id}/status.json"Determine next skill based on phase:
Phase Next Skill research research-orchestrator planning plan-generator tasking task-breakdown implementation implementation-runner review code-review qa qa-runner pr-ready pr-creator pr-created (wait for merge) blocked (show blockers, ask user) Prompt user:
Resuming: {ticketTitle} Current phase: {status} Last updated: {lastUpdated} Blockers: {blockers or "none"} Next step: Load {skill-name} skill Continue? (Y/n)If confirmed, load the appropriate skill.
Command: archive
Clean up completed runs.
Find completed runs (status = "done"):
for dir in "$HOME/repos/ticket-to-pr-pipeline/runs"/*/; do if [ -f "$dir/status.json" ]; then status=$(cat "$dir/status.json" | jq -r '.status') if [ "$status" = "done" ]; then echo "$dir" fi fi doneList candidates and confirm:
Found {X} completed runs: - {ticket-id}: {title} Archive these? (Y/n)Archive (move to archive/):
mkdir -p "$HOME/repos/ticket-to-pr-pipeline/runs/archive" mv "$HOME/repos/ticket-to-pr-pipeline/runs/{ticket-id}" "$HOME/repos/ticket-to-pr-pipeline/runs/archive/"Report:
Archived {X} completed runs.
status.json Schema
{
"ticketId": "xxx",
"ticketTitle": "Feature name",
"ticketUrl": "https://notion.so/...",
"status": "research|planning|tasking|implementation|review|qa|pr-ready|pr-created|done|blocked",
"prNumber": 123,
"prUrl": "https://github.com/...",
"startedAt": "2024-01-15T10:00:00Z",
"lastUpdated": "2024-01-15T14:30:00Z",
"blockers": ["Waiting for design feedback"],
"notes": ["Slack thread context included"]
}
ticket.json Schema
{
"pageId": "notion-page-id",
"title": "Ticket title",
"url": "https://notion.so/...",
"team": "frontend|backend|ml"
}
Empty State
If no runs exist:
# Pipeline Dashboard
No active pipeline runs.
To start a new run, use the ticket-picker skill.
Command: check-merged
Check for merged PRs and update Notion status to Done. This handles the common case where you close the agent before PR merge.
Find runs in review state:
find runs/ -name "status.json" -exec jq -c \ 'select(.status | test("pr-created|in-review|ci-passed")) | {id: .ticketId, prNumber: .prNumber}' {} \; 2>/dev/nullCheck each PR's merge status:
gh pr view $PR_NUMBER --json state,mergedAtFor merged PRs, update Notion:
- Status: In Review → Done
- Log write to status.json
Update local status:
jq '.status = "done" | .completedAt = now' status.jsonReport:
Checked {X} open PRs: - ABC-123: PR #456 merged ✅ → Notion updated to Done - DEF-456: PR #789 still open
For detailed merge watching (including closed PR handling), use /skill pr-merge-watcher.
Auto-Check on Status
When running status command, automatically check for merged PRs:
# Pipeline Dashboard
⚡ Quick check: Found 1 merged PR not yet marked Done
→ ABC-123: PR #456 merged 2 days ago
Update Notion now? (Y/n)
Notion Properties
Update these properties in "Comfy Tasks" database:
- Status: Select property (Not Started, In Progress, In Review, Done)
- GitHub PR: URL property
- Assignee: Person property