
Task Dependency Patterns
- 146 installs
- 213 repo stars
- Updated August 4, 2026
- yonatangross/orchestkit
Model task graphs, blockers, and parallelizable work when orchestrating multi-step agent runs, CLI automation, or SaaS feature delivery in OrchestKit.
About
OrchestKit task-dependency-patterns skill documents how to structure dependent tasks, blockers, and parallel tracks for orchestrated builds so agents and humans execute SaaS, CLI, and automation work in the right order with fewer rework loops.
- DAG-style task modeling
- Blocker and ready rules
- Parallel vs serial lanes
- Milestone grouping
- Agent handoff boundaries
Task Dependency Patterns by the numbers
- 146 all-time installs (skills.sh)
- Ranked #1,194 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yonatangross/orchestkit --skill task-dependency-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 146 |
|---|---|
| repo stars | ★ 213 |
| Last updated | August 4, 2026 |
| Repository | yonatangross/orchestkit ↗ |
What it does
Model task graphs, blockers, and parallelizable work when orchestrating multi-step agent runs, CLI automation, or SaaS feature delivery in OrchestKit.
Files
Task Dependency Patterns
Overview
Claude Code 2.1.16 introduces a native Task Management System with four tools:
- TaskCreate: Create new tasks with subject, description, and activeForm
- TaskUpdate: Update status (pending → in_progress → completed), set dependencies
- TaskGet: Retrieve full task details including blockers
- TaskList: View all tasks with status and dependency summary
Tasks enable structured work tracking, parallel coordination, and clear progress visibility.
When to Use
- Breaking down complex multi-step implementations
- Coordinating parallel work across multiple files
- Tracking progress on large features
- Managing dependencies between related changes
- Providing visibility into work status
Key Patterns
1. Task Decomposition
Break complex work into atomic, trackable units:
Feature: Add user authentication
Tasks:
#1. [pending] Create User model
#2. [pending] Add auth endpoints (blockedBy: #1)
#3. [pending] Implement JWT tokens (blockedBy: #2)
#4. [pending] Add auth middleware (blockedBy: #3)
#5. [pending] Write integration tests (blockedBy: #4)2. Dependency Chains
Use addBlockedBy to create execution order:
// Task #3 cannot start until #1 and #2 complete
{"taskId": "3", "addBlockedBy": ["1", "2"]}3. Status Workflow
pending → in_progress → completed
↓ ↓
(unblocked) (active)
pending/in_progress → deleted- pending: Task created but not started
- in_progress: Actively being worked on
- completed: Work finished and verified
- deleted: Task removed — permanently removes the task
Task Deletion
Use status: "deleted" to permanently remove tasks:
// Delete a task
{"taskId": "3", "status": "deleted"}When to delete:
- Orphaned tasks whose blockers have all failed
- Tasks superseded by a different approach
- Duplicate tasks created in error
- Tasks from a cancelled pipeline
When NOT to delete:
- Tasks that might be retried later (keep as pending)
- Tasks with useful history (mark completed instead)
- Tasks blocked by in_progress work (wait for resolution)
4. activeForm Pattern
Provide present-continuous form for spinner display:
| subject (imperative) | activeForm (continuous) |
|---|---|
| Run tests | Running tests |
| Update schema | Updating schema |
| Fix authentication | Fixing authentication |
Agent Teams
Agent Teams provides multi-agent coordination with shared task lists and peer-to-peer messaging.
CC 2.1.161 — independent parallel-tool failure: A failed tool call in a parallel batch no longer cancels siblings; each returns its own result. Teammates must check task status independently and handle failures explicitly rather than assuming a batch-wide abort.
Team Workflow
1. (implicit team — CC 2.1.178+) → one team per session; no TeamCreate
2. TaskCreate(subject, description) → Add tasks to shared list
3. Agent(name, team_name, prompt) → Spawn teammates into the implicit team
4. TaskUpdate(owner: "teammate-name") → Assign tasks
5. SendMessage(to, message, summary) → Direct teammate communication
6. (turn / background ends) → teammates wind down; Ctrl+F x2 for bgWhen to Use Teams vs Task Tool
| Criteria | Task Tool (subagents) | Agent Teams |
|---|---|---|
| Independent tasks | Yes | Overkill |
| Cross-cutting changes | Limited | Yes |
| Agents need to talk | No (star topology) | Yes (mesh) |
| Cost sensitivity | Lower (~1x) | Higher (~2.5x) |
| Complexity < 3.0 | Yes | No |
| Complexity > 3.5 | Possible | Recommended |
Team Task Patterns
# Spawn teammate into shared task list
Agent(
prompt="You are the backend architect...",
team_name="my-feature",
name="backend-architect",
subagent_type="ork:backend-system-architect"
)
# Teammate claims and works tasks
TaskList → find unblocked, unowned tasks
TaskUpdate(taskId, owner: "backend-architect", status: "in_progress")
# ... do work ...
TaskUpdate(taskId, status: "completed")
TaskList → find next taskPeer Messaging
# Direct message between teammates (params: to, message, summary)
SendMessage(to: "frontend-dev",
message: "API contract ready: GET /users/:id returns {...}",
summary: "API contract shared")
# No broadcast primitive — send to each teammate, or post to the shared
# task list (TaskCreate/TaskUpdate) so every teammate sees it
SendMessage(to: "backend-dev",
message: "Breaking change: auth header format changed",
summary: "Breaking auth change")Context Exhaustion Handling
When using Agent Teams, if context limit is reached mid-workflow:
- Collect partial results from completed teammates via
TaskList - Synthesize available outputs — prefer partial results over silent failure
- Log skipped tasks with
TaskUpdate(taskId: task_id, status: "completed", metadata: {"skipped": "context limit"})
Anti-Patterns
- Creating tasks for trivial single-step work
- Circular dependencies (A blocks B, B blocks A)
- Leaving tasks in_progress when blocked
- Not marking tasks completed after finishing
- Using broadcast for messages that only concern one teammate
- Spawning teams for simple sequential work (use Task tool instead)
Related Skills
ork:implement- Implementation workflow with task tracking and progress updatesork:verify- Verification tasks and completion checklistsork:fix-issue- Issue resolution with hypothesis-based RCA trackingork:brainstorm- Design exploration with parallel agent tasks
References
Load on demand with Read("${CLAUDE_SKILL_DIR}/references/<file>"):
| File | Content |
|---|---|
dependency-tracking.md | Dependency tracking patterns |
status-workflow.md | Status workflow details |
multi-agent-coordination.md | Multi-agent coordination |
Dependency Validation Checklist
Before Adding Dependencies
- [ ] Is there a true execution order requirement?
- [ ] Would parallel execution cause conflicts?
- [ ] Is the dependency on task completion (not just start)?
Dependency Types
Code Dependencies
- [ ] Task B modifies files created by Task A
- [ ] Task B imports modules defined in Task A
- [ ] Task B extends patterns established in Task A
Schema Dependencies
- [ ] Task B uses database schema from Task A
- [ ] Task B consumes API contracts from Task A
- [ ] Task B references types defined in Task A
Test Dependencies
- [ ] Task B tests functionality from Task A
- [ ] Task B requires fixtures from Task A
- [ ] Task B extends test suites from Task A
Dependency Anti-Patterns
Circular Dependencies
Task A blockedBy [B]
Task B blockedBy [A]Fix: Identify shared prerequisite, extract to Task C
Over-Specification
Task D blockedBy [A, B, C]
# But really only needs CFix: Remove unnecessary dependencies, rely on transitive blocking
Under-Specification
Task B has no blockedBy
# But actually needs Task A's outputFix: Add explicit dependency to prevent race conditions
Validation Steps
1. Trace Dependency Chain
For each task with blockedBy:
- Can the blocking task(s) actually complete?
- Is there a path from START to this task?
- Is there a path from this task to END?2. Check for Cycles
For each task T:
visited = {}
queue = [T.blockedBy]
while queue:
current = queue.pop()
if current == T: ERROR: Cycle detected
if current in visited: continue
visited.add(current)
queue.extend(current.blockedBy)3. Verify Parallelism
Tasks without mutual dependencies CAN run in parallel.
Verify: No shared file writes, no ordering requirement.Updating Dependencies
When modifying existing dependencies:
- [ ] Reviewed impact on blocked tasks
- [ ] No orphaned tasks (tasks that can never unblock)
- [ ] Critical path still reasonable
- [ ] Notified other agents/workers if relevant
Documentation
For complex dependency chains:
- [ ] Diagram in task description or PR
- [ ] Rationale for non-obvious dependencies
- [ ] Expected execution order documented
Task Design Checklist
Before Creating Tasks
- [ ] Is this work complex enough to need task tracking? (3+ steps)
- [ ] Have you identified the natural work boundaries?
- [ ] Can each task be completed independently once unblocked?
Task Structure
Subject (required)
- [ ] Uses imperative form ("Add", "Fix", "Update", not "Adding", "Fixed")
- [ ] Describes the outcome, not the process
- [ ] Concise but descriptive (5-10 words max)
Good examples:
- "Create User model with validation"
- "Add JWT authentication endpoint"
- "Fix pagination in search results"
Bad examples:
- "Work on the feature" (too vague)
- "Adding stuff to the database" (wrong tense, vague)
- "Implement the new user authentication system with JWT tokens and refresh token rotation including rate limiting" (too long)
Description (required)
- [ ] Explains what needs to be done
- [ ] Includes acceptance criteria
- [ ] Notes any constraints or considerations
- [ ] References relevant files or patterns
Template:
Implement [specific thing] that:
- [Requirement 1]
- [Requirement 2]
Acceptance criteria:
- [ ] Tests pass
- [ ] Documentation updated
- [ ] No type errorsactiveForm (recommended)
- [ ] Uses present continuous tense
- [ ] Matches the subject semantically
- [ ] Reads naturally as spinner text
| Subject | activeForm |
|---|---|
| Add user validation | Adding user validation |
| Fix broken tests | Fixing broken tests |
| Update API schema | Updating API schema |
Dependency Design
- [ ] Dependencies represent real execution order requirements
- [ ] No circular dependency chains
- [ ] Parallel work identified and unblocked appropriately
- [ ] Critical path minimized
Task Granularity
Too Large
Signs your task is too large:
- Description exceeds 200 words
- Estimated to touch 5+ files
- Multiple distinct outcomes combined
Split strategy: 1. Identify sub-outcomes 2. Create task per outcome 3. Link with dependencies
Too Small
Signs your task is too small:
- Single line change
- Pure refactoring without behavior change
- Part of another task's natural work
Merge strategy: 1. Combine with related task 2. Add to description as sub-item
Review Before Submitting
- [ ] Each task has clear completion criteria
- [ ] Dependencies are minimal but sufficient
- [ ] Task can be understood without external context
- [ ] activeForm provides useful progress feedback
Dependency Tracking
Overview
Task dependencies ensure correct execution order through blocks and blockedBy relationships.
Dependency Fields
| Field | Description |
|---|---|
blocks | Tasks that cannot start until this task completes |
blockedBy | Tasks that must complete before this task can start |
Creating Dependencies
// During task update
{
"taskId": "3",
"addBlockedBy": ["1", "2"],
"addBlocks": ["4", "5"]
}Dependency Patterns
Sequential Chain
#1 → #2 → #3 → #4// Task #2 blocked by #1
{"taskId": "2", "addBlockedBy": ["1"]}
// Task #3 blocked by #2
{"taskId": "3", "addBlockedBy": ["2"]}Fan-Out Pattern
┌→ #2
#1 ──┼→ #3
└→ #4All depend on #1, but can run in parallel after #1 completes.
Fan-In Pattern
#1 ──┐
#2 ──┼→ #4
#3 ──┘{"taskId": "4", "addBlockedBy": ["1", "2", "3"]}Diamond Pattern
#1
↙ ↘
#2 #3
↘ ↙
#4Validation Rules
1. No circular dependencies: A → B → A is invalid 2. Blocked tasks cannot start: Check blockedBy before setting in_progress 3. Completing unblocks dependents: When #1 completes, #2 becomes available
Querying Dependencies
# List tasks to see blockedBy summary
TaskList
# Get full dependency details
TaskGet taskId="3"
# Returns: blockedBy: ["1", "2"], blocks: ["4"]Best Practices
- Keep dependency chains shallow (3-4 levels max)
- Use fan-out for parallelizable work
- Document why dependencies exist in task description
- Review blocked tasks when completing work
Multi-Agent Task Coordination
Overview
When multiple Claude Code instances or agents work on a shared codebase, the Task system provides coordination primitives.
Coordination Patterns
Task Assignment
Use owner field to track which agent owns a task:
// Claim a task
{"taskId": "3", "owner": "backend-agent"}
// Release task
{"taskId": "3", "owner": ""}Finding Available Work
# Pseudo-code for agent task selection
tasks = TaskList()
available = [t for t in tasks
if t.status == "pending"
and not t.owner
and not t.blockedBy]
next_task = available[0] if available else NoneWork Distribution
┌─────────────────────────────────────────┐
│ Task Board │
├──────────────┬──────────────┬───────────┤
│ pending │ in_progress │ completed │
├──────────────┼──────────────┼───────────┤
│ #4 (blocked) │ #2 (agent-A) │ #1 │
│ #5 (ready) │ #3 (agent-B) │ │
│ #6 (ready) │ │ │
└──────────────┴──────────────┴───────────┘Agent Workflow
1. Check for Work
// Agent startup: list all tasks
TaskList2. Claim Task
// Found unblocked, unowned task
{"taskId": "5", "status": "in_progress", "owner": "my-agent"}3. Complete Work
// After finishing work
{"taskId": "5", "status": "completed"}
// Check for newly unblocked tasks
TaskListHandoff Patterns
Sequential Handoff
Agent-A completes #1 → Agent-B unblocked for #2Parallel Fork
Agent-A completes #1
├→ Agent-B can start #2
├→ Agent-C can start #3
└→ Agent-D can start #4Merge Point
Agent-A completes #2 ─┐
Agent-B completes #3 ─┼→ Any agent can start #5
Agent-C completes #4 ─┘Best Practices
1. Atomic task design: Tasks should be completable by single agent 2. Clear ownership: Always set owner when starting work 3. Timely completion: Mark completed as soon as work is done 4. Dependency awareness: Check blockedBy before starting 5. Communication via tasks: Use description for context handoff
Integration with OrchestKit
The task system integrates with:
- context-compression: Task context in compressed summaries
- agent handoff hooks: Auto-document in decision log
Status Workflow
Overview
Tasks progress through a defined state machine: pending → in_progress → completed.
Status States
pending
- Task created but not started
- May be blocked by other tasks
- Available for claiming if no blockers
in_progress
- Actively being worked on
- Only one task should typically be in_progress per worker
- Mark immediately when starting work
completed
- Work finished and verified
- Unblocks dependent tasks
- Cannot be modified further
deleted (CC 2.1.20)
- Task permanently removed
- Use for orphaned, superseded, or duplicate tasks
- Cannot be recovered after deletion
State Transitions
┌─────────┐ start ┌─────────────┐ finish ┌───────────┐
│ pending │ ────────────→ │ in_progress │ ───────────→ │ completed │
└─────────┘ └─────────────┘ └───────────┘
↑ │ │ │
│ └───────────────────────│──│──→ ┌─────────┐
└───── revert ─────────────┘ └──→ │ deleted │ (CC 2.1.20)
(if blocked) └─────────┘Valid Transitions
| From | To | When |
|---|---|---|
| pending | in_progress | Starting work, no blockers |
| in_progress | completed | Work verified complete |
| in_progress | pending | Discovered blocker, need to wait |
| pending | deleted | Orphaned, superseded, or duplicate (CC 2.1.20) |
| in_progress | deleted | Cancelled or superseded (CC 2.1.20) |
Status Update Examples
// Start work
{"taskId": "1", "status": "in_progress"}
// Mark complete
{"taskId": "1", "status": "completed"}
// Revert if blocked
{"taskId": "1", "status": "pending"}
// Delete orphaned task (CC 2.1.20)
{"taskId": "1", "status": "deleted"}Completion Criteria
Before marking completed, verify:
1. Implementation done: All code changes complete 2. Tests passing: Related tests succeed 3. No blockers: Nothing prevents dependent tasks 4. Documentation updated: If applicable
Anti-Patterns
Premature Completion
// DON'T: Mark complete with failing tests
{"taskId": "1", "status": "completed"}Abandoned in_progress
// DON'T: Leave task in_progress when blocked
// DO: Revert to pending, create blocker task
{"taskId": "1", "status": "pending"}Skipping States
// DON'T: Go directly from pending to completed
// DO: Always transition through in_progress
{"taskId": "1", "status": "in_progress"}
// ... do work ...
{"taskId": "1", "status": "completed"}activeForm Display
The activeForm field displays during in_progress status:
[#1 in_progress] Running tests... ⣾Provide meaningful present-continuous descriptions:
- "Creating database schema"
- "Updating API endpoints"
- "Writing integration tests"
Rule Categories
1. Task Lifecycle (task) — HIGH — 3 rules
Patterns for managing task dependencies, coordination, and completion in multi-agent workflows.
task-dependency-validation.md— Validate blockers resolved before starting, detect circular dependenciestask-agent-coordination.md— Clear ownership, avoid duplicate work, coordinate via messages and task listtask-completion-criteria.md— Only mark complete when fully verified, create follow-ups for remaining work
[Rule Name]
[Brief description — 1-2 sentences.]
Incorrect:
// Bad patternCorrect:
// Good patternKey rules:
- [Rule 1]
- [Rule 2]
- [Rule 3]
Reference: [link]
Tasks: Agent Coordination
In multi-agent workflows, every in-progress task must have a clear owner, and agents must coordinate through the task list and messaging tools. Without ownership, two agents may silently work on the same task, causing merge conflicts and wasted effort.
Incorrect:
// Two agents both start the same task without claiming ownership
// Agent-A:
TaskUpdate(taskId: "5", status: "in_progress") // No owner set
// Agent-B (simultaneously):
TaskUpdate(taskId: "5", status: "in_progress") // No owner set
// Both agents now work on #5 — duplicate effort, likely merge conflictCorrect:
// Agent-A claims the task atomically with owner field
TaskList // Review available tasks
// Found #5: pending, no owner, blockedBy: []
TaskUpdate(taskId: "5", status: "in_progress", owner: "agent-a")
// Agent-B sees #5 is owned
TaskList // #5 shows owner: "agent-a", in_progress
// Agent-B picks a different unblocked, unowned task instead
TaskUpdate(taskId: "6", status: "in_progress", owner: "agent-b")Incorrect:
// Agent completes work silently — no one knows the output or context
TaskUpdate(taskId: "5", status: "completed")
// Downstream agent starts #7 (blocked by #5) with no context about what was doneCorrect:
// Agent communicates completion context to dependent agent
TaskUpdate(taskId: "5", status: "completed")
SendMessage(
to: "frontend-dev",
message: "Task #5 done: API returns { users: User[], total: number }. Schema in src/types/user.ts.",
summary: "API contract ready for frontend"
)
// Downstream agent has full context to start dependent workKey rules:
- Always set
ownerwhen transitioning a task toin_progress— this prevents duplicate work - Use
TaskListto find unblocked, unowned tasks before claiming one - Design tasks to be completable by a single agent — avoid tasks that require two agents to collaborate mid-execution
- Use
SendMessageto share completion context (output formats, file locations, decisions made) with agents who own dependent tasks - Mark tasks
completedpromptly after finishing — delayed completion blocks dependent agents unnecessarily - Release ownership (
owner: "") if you cannot finish a task, reverting it topendingso another agent can pick it up
Reference: Multi-Agent Coordination — Best Practices (lines 110-116), Agent Workflow (lines 47-70)
Tasks: Completion Criteria
A task must only be marked completed when all implementation is done, tests pass, and nothing blocks dependent tasks from proceeding safely. Premature completion cascades errors: downstream agents start work assuming a solid foundation that does not exist.
Incorrect:
// Marking complete when tests are failing
// Agent implements feature but 2 of 8 tests fail
TaskUpdate(taskId: "3", status: "completed") // BAD: tests not passing
// Dependent task #4 starts, builds on broken code — compounds the failureCorrect:
// Verify all criteria before marking complete
// 1. Implementation done — all code changes committed
// 2. Tests passing — ran test suite, all green
// 3. No blockers for dependents — output matches expected interface
// 4. Documentation updated (if applicable)
TaskUpdate(taskId: "3", status: "completed") // GOOD: fully verified
TaskList // Check if #4 is now unblocked and readyIncorrect:
// Leaving a task in_progress when blocked by a discovered issue
// Agent hits unexpected blocker mid-work
// Task sits as in_progress indefinitely — no one else can pick it up
// Other agents wait for dependent tasks that will never unblockCorrect:
// Revert to pending and create a blocker task for the discovered issue
TaskUpdate(taskId: "3", status: "pending") // Revert — not abandonable as in_progress
TaskCreate(
subject: "Fix database connection pooling",
description: "Discovered during #3: pool exhaustion under load. Must fix before #3 can proceed.",
activeForm: "Fixing connection pooling"
)
// New task #7 created
TaskUpdate(taskId: "3", addBlockedBy: ["7"]) // #3 now properly blockedIncorrect:
// Skipping in_progress — going directly from pending to completed
TaskUpdate(taskId: "1", status: "completed") // BAD: skipped in_progress
// No visibility that work was happening; no activeForm spinner shownCorrect:
// Always transition through in_progress for visibility
TaskUpdate(taskId: "1", status: "in_progress", activeForm: "Creating user model")
// ... do work, verify results ...
TaskUpdate(taskId: "1", status: "completed")Key rules:
- Verify all four completion criteria before marking done: implementation complete, tests passing, no blockers for dependents, documentation updated if applicable
- Never skip
in_progress— always transitionpendingtoin_progresstocompletedfor proper visibility - If blocked mid-work, revert to
pendingand create a new blocker task withaddBlockedBylinking - When partial work is done but scope remains, create follow-up tasks for the remaining items rather than leaving one large task incomplete
- After completing a task, run
TaskListto identify newly unblocked dependents
Reference: Status Workflow — Completion Criteria (lines 71-78), Anti-Patterns (lines 80-105)
Tasks: Dependency Validation
Always validate that a task's dependencies are fully resolved before transitioning it to in_progress. Skipping validation leads to wasted effort, incorrect assumptions about system state, and potential circular dependency deadlocks.
Incorrect:
// Starting a task without checking if blockers are resolved
TaskList // shows #3 has blockedBy: ["1", "2"]
// Task #1 is completed but #2 is still in_progress
TaskUpdate(taskId: "3", status: "in_progress") // BAD: #2 not done yet
// Agent now works against incomplete prerequisite stateCorrect:
// Always verify blockedBy is empty before starting work
TaskGet(taskId: "3")
// Returns: blockedBy: ["1", "2"], status: "pending"
// Check: #1 = completed, #2 = completed? No — #2 still in_progress
// Result: Do NOT start #3. Pick a different unblocked task instead.
// Later, when #2 completes:
TaskGet(taskId: "3")
// Returns: blockedBy: [] (all resolved), status: "pending"
TaskUpdate(taskId: "3", status: "in_progress", owner: "my-agent") // GOODIncorrect:
// Creating circular dependencies
TaskUpdate(taskId: "2", addBlockedBy: ["3"])
TaskUpdate(taskId: "3", addBlockedBy: ["2"])
// Deadlock: neither task can ever startCorrect:
// Keep dependency chains acyclic — review the full chain before adding
// If #2 depends on #3 output, restructure:
TaskCreate(subject: "Extract shared interface", ...) // New task #6
TaskUpdate(taskId: "2", addBlockedBy: ["6"])
TaskUpdate(taskId: "3", addBlockedBy: ["6"])
// Both #2 and #3 depend on #6, no cycleKey rules:
- Call
TaskGetand verifyblockedByis empty before setting any task toin_progress - Never add a dependency that creates a cycle (A blocks B blocks A); restructure with a shared prerequisite task instead
- Keep dependency chains shallow (3-4 levels max) to avoid long critical paths
- When completing a task, call
TaskListto check if dependent tasks are now unblocked - Document why each dependency exists in the task description so future agents understand the ordering
Reference: Dependency Tracking — Validation Rules (lines 72-77), Best Practices (lines 89-94)
#!/usr/bin/env python3
"""
Task Tree Visualizer
Generates ASCII dependency tree from task list JSON.
Usage:
echo '<task_list_json>' | python task-tree-visualizer.py
python task-tree-visualizer.py --sample # Show sample output
Input format (TaskList output):
{
"tasks": [
{"id": "1", "subject": "Task A", "status": "completed", "blockedBy": []},
{"id": "2", "subject": "Task B", "status": "in_progress", "blockedBy": ["1"]},
{"id": "3", "subject": "Task C", "status": "pending", "blockedBy": ["1"]},
{"id": "4", "subject": "Task D", "status": "pending", "blockedBy": ["2", "3"]}
]
}
Output:
┌─ Task Dependency Tree ─────────────────────────────┐
│ │
│ #1 [completed] Task A │
│ ├─→ #2 [in_progress] Task B │
│ │ └─→ #4 [pending] Task D │
│ └─→ #3 [pending] Task C │
│ └─→ #4 [pending] Task D │
│ │
└────────────────────────────────────────────────────┘
"""
import json
import sys
from typing import Any
def status_icon(status: str) -> str:
"""Return status indicator."""
icons = {
"completed": "[done]",
"in_progress": "[>>>]",
"pending": "[...]",
}
return icons.get(status, "[???]")
def build_tree(tasks: list[dict[str, Any]]) -> dict[str, list[str]]:
"""Build adjacency list: task_id -> list of tasks it unblocks."""
tree: dict[str, list[str]] = {t["id"]: [] for t in tasks}
tree["ROOT"] = []
for task in tasks:
if not task.get("blockedBy"):
tree["ROOT"].append(task["id"])
else:
for blocker in task["blockedBy"]:
if blocker in tree:
tree[blocker].append(task["id"])
return tree
def render_tree(
tasks: list[dict[str, Any]],
tree: dict[str, list[str]],
node: str = "ROOT",
prefix: str = "",
visited: set[str] | None = None,
) -> list[str]:
"""Render tree as ASCII lines."""
if visited is None:
visited = set()
lines: list[str] = []
children = tree.get(node, [])
for i, child_id in enumerate(children):
is_last = i == len(children) - 1
task = next((t for t in tasks if t["id"] == child_id), None)
if task is None:
continue
# Prevent infinite loops from circular dependencies
if child_id in visited:
connector = "└─" if is_last else "├─"
lines.append(f"{prefix}{connector}→ #{child_id} (circular ref)")
continue
visited.add(child_id)
connector = "└─" if is_last else "├─"
status = status_icon(task.get("status", "pending"))
subject = task.get("subject", "Untitled")[:40]
lines.append(f"{prefix}{connector}→ #{child_id} {status} {subject}")
# Recurse to children
child_prefix = prefix + (" " if is_last else "│ ")
lines.extend(
render_tree(tasks, tree, child_id, child_prefix, visited.copy())
)
return lines
def visualize(task_json: str) -> str:
"""Generate ASCII visualization from JSON."""
try:
data = json.loads(task_json)
tasks = data.get("tasks", data) if isinstance(data, dict) else data
except json.JSONDecodeError as e:
return f"Error parsing JSON: {e}"
if not tasks:
return "No tasks to visualize"
tree = build_tree(tasks)
lines = render_tree(tasks, tree)
# Build output box
max_width = max(len(line) for line in lines) if lines else 40
box_width = max(max_width + 4, 50)
output = [
"+" + "-" * (box_width - 2) + "+",
"|" + " Task Dependency Tree".center(box_width - 2) + "|",
"|" + " " * (box_width - 2) + "|",
]
for line in lines:
output.append("| " + line.ljust(box_width - 4) + "|")
output.extend(
[
"|" + " " * (box_width - 2) + "|",
"+" + "-" * (box_width - 2) + "+",
]
)
return "\n".join(output)
def sample_output() -> str:
"""Generate sample visualization."""
sample = {
"tasks": [
{"id": "1", "subject": "Create User model", "status": "completed", "blockedBy": []},
{"id": "2", "subject": "Add auth endpoints", "status": "in_progress", "blockedBy": ["1"]},
{"id": "3", "subject": "Implement JWT tokens", "status": "pending", "blockedBy": ["2"]},
{"id": "4", "subject": "Add auth middleware", "status": "pending", "blockedBy": ["3"]},
{"id": "5", "subject": "Write integration tests", "status": "pending", "blockedBy": ["4"]},
]
}
return visualize(json.dumps(sample))
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--sample":
print(sample_output())
elif not sys.stdin.isatty():
input_json = sys.stdin.read()
print(visualize(input_json))
else:
print("Usage: echo '<json>' | python task-tree-visualizer.py")
print(" python task-tree-visualizer.py --sample")
sys.exit(1)
{
"skill": "task-dependency-patterns",
"version": "1.0.0",
"testCases": [
{
"id": "basic-i-need-to-implement",
"rule": "",
"query": "I need to implement a full authentication system: user model, auth endpoints, JWT tokens, middleware, and integration tests. Help me break this down into trackable tasks with proper dependencies.",
"expectedBehavior": [
"Claude decomposes the work into atomic tasks using TaskCreate",
"Establishes dependency chains with addBlockedBy (e.g., auth endpoints blocked by user model)",
"Sets proper status workflow: pending for all initially, then in_progress as work begins",
"Provides activeForm for each task (e.g., 'Creating User model', 'Implementing JWT tokens')",
"Uses TaskUpdate to track progress as tasks complete"
]
},
{
"id": "edge-we-have-a-crosscutting",
"rule": "",
"query": "We have a cross-cutting refactor that needs a backend architect and frontend dev working simultaneously on shared contracts. Should I use Task tool subagents or Agent Teams?",
"expectedBehavior": [
"Claude evaluates the criteria table: cross-cutting changes, agents need to communicate",
"Recommends Agent Teams over Task tool for this scenario due to mesh communication needs",
"Explains the implicit team (Agent(name=...)), peer-to-peer SendMessage, and shared task list patterns",
"Warns about the higher cost (~2.5x) of Agent Teams vs Task tool subagents"
]
},
{
"id": "negative-change-the-button-color",
"rule": "",
"query": "Change the button color from blue to green in the header component",
"expectedBehavior": [
"Claude does NOT invoke the task-dependency-patterns skill",
"Makes the simple CSS/style change directly without task decomposition",
"Does not create TaskCreate calls for trivial single-step work"
]
},
{
"id": "task-agent-coordination",
"rule": "task-agent-coordination",
"query": "I have two agents both trying to work on the same database migration task. How do I prevent conflicts?",
"expectedBehavior": [
"Requires agents to claim task ownership atomically before starting work on it",
"Uses TaskUpdate with owner field set to the claiming agent's identifier",
"Prevents two agents from simultaneously working on the same task without ownership",
"Coordinates through the shared task list and messaging tools rather than direct state sharing"
]
},
{
"id": "task-completion-criteria",
"rule": "task-completion-criteria",
"query": "My downstream task started failing because the upstream task was marked complete too early. How should I handle completion?",
"expectedBehavior": [
"Verifies all implementation is done and tests pass before marking a task as completed",
"Warns that premature completion cascades errors to dependent tasks in the chain",
"Requires running the test suite and confirming all green before status transition",
"Documents what was done and any caveats in the task completion notes"
]
},
{
"id": "task-dependency-validation",
"rule": "task-dependency-validation",
"query": "How do I check if a task's blockers are resolved before I start working on it?",
"expectedBehavior": [
"Uses TaskGet to check the blockedBy array before transitioning to in_progress status",
"Validates that all blocking tasks have completed status before starting dependent work",
"Detects circular dependencies that would create deadlocks in the task graph",
"Refuses to start work on a task when any of its blockers are still pending or in progress"
]
}
]
}