dev-task-queue
Agent Task Queue
Persistent, cross-session task queue for AI agents aligned with the Claude Code Tasks schema. Tasks survive beyond sessions, carry full context including conversation transcripts, and support dependency tracking with blocks/blockedBy. Backed by a git repo with move-based locking for conflict-free multi-agent access.
Prerequisites
Clone the task queue repository:
git clone git@github.com:OlechowskiMichal/agent-task-queue.git ~/.agent-task-queue
All commands below assume the repo is at ~/.agent-task-queue.
Quick Reference
| Operation | Command | Description |
|---|---|---|
| Add | python3 ~/.agent-task-queue/scripts/add_task.py |
Create a new task |
| List | python3 ~/.agent-task-queue/scripts/list_tasks.py |
List/filter tasks |
| Claim | python3 ~/.agent-task-queue/scripts/claim_task.py |
Claim a pending task |
| Complete | python3 ~/.agent-task-queue/scripts/complete_task.py |
Mark task done |
| Release | python3 ~/.agent-task-queue/scripts/release_task.py |
Unclaim a task |
| Reassign | python3 ~/.agent-task-queue/scripts/reassign_task.py |
Reassign to different agent |
| Index | python3 ~/.agent-task-queue/scripts/render_index.py |
Regenerate root index |
| Prune | python3 ~/.agent-task-queue/scripts/prune_completed.py |
Archive old tasks |
Adding a Task
Save a task for a future agent session:
python3 ~/.agent-task-queue/scripts/add_task.py \
--assignee go-expert \
--subject "Fix error handling in API middleware" \
--description "The error handler swallows context. Wrap errors with fmt.Errorf." \
--priority high \
--project my-api \
--tags "error-handling,api" \
--active-form "Fixing error handling" \
--ttl-hours 48 \
--blocked-by "3,7" \
--context-repo "git@github.com:OlechowskiMichal/my-api.git" \
--context-files "pkg/middleware/error.go,pkg/middleware/error_test.go" \
--context-notes "See issue #42 for the original bug report"
--assignee is optional and defaults to general-purpose. Omit it for tasks that any agent can pick up.
When --project matches an entry in projects.json (see Project Registry), --context-repo is auto-filled from the registry. You can still pass --context-repo explicitly to override. If --project does not match any known project, the script warns and suggests close matches.
The script reads .highwatermark to assign the next monotonic integer ID, writes the task JSON to pending/{id}.json, regenerates the root index, and pushes to the repo.
Multi-line descriptions
For descriptions with # characters or complex formatting (which break zsh heredocs), write to a temp file and use --description-file:
cat > /tmp/task-desc.md << 'EOF'
## Problem
The error handler swallows context.
### Acceptance criteria
- Wrap errors with fmt.Errorf
- Add retry logic for transient failures
EOF
python3 ~/.agent-task-queue/scripts/add_task.py \
--assignee go-expert \
--subject "Fix error handling in API middleware" \
--description-file /tmp/task-desc.md \
--priority high
--description-file overrides --description when both are provided.
Listing Tasks
# All pending tasks for an agent
python3 ~/.agent-task-queue/scripts/list_tasks.py --agent go-expert --status pending
# Stale tasks (claimed but exceeded TTL)
python3 ~/.agent-task-queue/scripts/list_tasks.py --stale
# Blocked tasks (unmet dependencies)
python3 ~/.agent-task-queue/scripts/list_tasks.py --blocked
# Tasks for a specific project
python3 ~/.agent-task-queue/scripts/list_tasks.py --project my-api
# Tasks created after a date
python3 ~/.agent-task-queue/scripts/list_tasks.py --since 2026-03-01
# List all known projects and their repos (from projects.json)
python3 ~/.agent-task-queue/scripts/list_tasks.py --list-projects
Claiming a Task
Start working on a pending task:
python3 ~/.agent-task-queue/scripts/claim_task.py 1 --session-id $(uuidgen)
The script:
- Verifies all
blockedBydependencies are completed - Moves the task from
pending/toactive/ - Sets
ownerandmetadata.claimed_at - Updates
statustoin_progress - Pushes with conflict detection — if another agent claimed it first, the push fails
Completing a Task
python3 ~/.agent-task-queue/scripts/complete_task.py 1 \
--session-id "$(uuidgen)" \
--jsonl-path "$HOME/.claude/projects/.../conversation.jsonl" \
--notes "Fixed by wrapping errors with context in middleware chain"
The task moves to completed/YYYY-MM/{id}.json with the conversation transcript reference appended.
Releasing a Task
If you cannot finish a claimed task:
python3 ~/.agent-task-queue/scripts/release_task.py 1
Moves back to pending/ with metadata.previously_claimed=true and status reset to pending so the next agent knows it was attempted.
Reassigning a Task
Transfer a task to a different agent type:
python3 ~/.agent-task-queue/scripts/reassign_task.py 1 --to re-expert
This is a metadata-only update — it sets metadata.assignee to the new agent. No file move occurs. The task stays in its current directory (pending/ or active/).
Dependency Management
Tasks support bidirectional dependency tracking via blocks and blockedBy fields, aligned with the Claude Code Tasks schema.
- blockedBy: Array of task IDs that must be completed before this task can be claimed.
claim_task.pyenforces this — it refuses to claim a task with unresolved blockedBy entries. - blocks: Array of task IDs that are waiting on this task. When a task is completed, the system can check whether downstream tasks are now unblocked.
Both sides are kept in sync: adding task 5 to the blockedBy of task 8 also adds task 8 to the blocks of task 5.
Cycle detection runs at add time and at claim time. If adding a dependency would create a circular chain (e.g., A blocks B blocks A), the operation is rejected with an error.
# Add a task that depends on tasks 3 and 7
python3 ~/.agent-task-queue/scripts/add_task.py \
--subject "Deploy after migrations" \
--blocked-by "3,7"
# List all currently blocked tasks
python3 ~/.agent-task-queue/scripts/list_tasks.py --blocked
Project Registry
The projects.json file at the repo root maps project names to their canonical repository URLs:
{
"my-api": "git@github.com:OlechowskiMichal/my-api.git",
"claude-skills": "git@github.com:OlechowskiMichal/claude-skills.git"
}
The registry enables two behaviors:
- Auto-fill
--context-repo: Whenadd_task.pyreceives--project my-apiandmy-apiis in the registry,--context-repois set automatically. An explicit--context-repooverrides the registry value. - Unknown-project warnings: If
--projectdoes not match any registry entry, the script prints a warning with close-match suggestions (viadifflib.get_close_matches). The task is still created — the warning is advisory.
List all registered projects with --list-projects:
python3 ~/.agent-task-queue/scripts/list_tasks.py --list-projects
Output:
Project | Repository
---------------------------+---------------------------------------------------------------
my-api | git@github.com:OlechowskiMichal/my-api.git
claude-skills | git@github.com:OlechowskiMichal/claude-skills.git
Total: 2 project(s)
Race Condition Handling
All scripts use push-reject, pull-rebase, retry (once). If a claim push is rejected after rebase, it means another agent already claimed the task. The script exits with an error message.
Conversation Linking
Link Claude Code conversation transcripts to tasks when completing:
- Pass
--jsonl-pathwith the path to the.jsonltranscript file - The path is stored in the task's
metadata.conversationsarray - Multiple sessions can contribute to the same task
Staleness Detection
Tasks have a metadata.ttl_hours field (default: 24). A claimed task is stale when metadata.claimed_at + ttl_hours < now. Find stale tasks with --stale flag. Release stale tasks manually with release_task.py.
Pruning Completed Tasks
Remove old completed tasks:
# Dry run — show what would be deleted
python3 ~/.agent-task-queue/scripts/prune_completed.py --older-than 90d
# Actually delete
python3 ~/.agent-task-queue/scripts/prune_completed.py --older-than 90d --execute
Task Schema
See references/task-schema.md for the full JSON schema with field descriptions.
Directory Layout
agent-task-queue/
├── .highwatermark # Monotonic ID counter (single integer)
├── pending/ # Flat — no agent subdirs
│ └── {id}.json
├── active/
│ └── {id}.json
├── completed/
│ └── YYYY-MM/
│ └── {id}.json
├── projects.json # Project-to-repo registry
├── index.md # Single root index
├── scripts/
│ ├── _lib.py
│ ├── add_task.py
│ ├── claim_task.py
│ ├── complete_task.py
│ ├── list_tasks.py
│ ├── release_task.py
│ ├── reassign_task.py
│ ├── render_index.py
│ └── prune_completed.py
├── AGENTS.md
├── CLAUDE.md
├── TODO.md
└── README.md