Agent skill
discovery-tree-workflow
Use when planning and tracking work - creates visible, emergent work breakdown using TypeScript API with just-in-time planning and hierarchical task trees
Install this agent skill to your Project
npx add-skill https://github.com/zgagnon/skills/tree/main/discovery-tree-workflow
SKILL.md
Discovery Tree Workflow
Overview
Discovery Trees make work visible through hierarchical task breakdown that emerges just-in-time. Track work programmatically with the TypeScript API, grow the tree as you discover new requirements, maintain focus by capturing distractions.
Core principle: Start minimal, plan just-in-time, grow through discovery, make status visible.
Announce at start: "I'm using the Discovery Tree workflow to track this work."
When to Use
Always use when:
- Starting any non-trivial work (more than a single simple task)
- Planning features, bugs, or investigations
- Working with multiple related tasks
- Need to make progress visible
- Want to capture emergent work without losing focus
Instead of:
- TodoWrite for tracking progress
- Upfront detailed planning
- Hidden mental task lists
- Linear task lists that don't show relationships
Core Philosophy
Just-in-Time Planning
- Start with minimal detail (one task describing user value)
- Have short conversations (2-10 minutes) to break down next steps
- Don't plan everything upfront - plan what you need now
- Delays planning until the last responsible moment
Emergent Work
- New requirements discovered during work → add to tree
- Unexpected complexity → break down further
- Distractions or ideas → capture as tasks, mark low priority
- Tree grows organically as understanding deepens
Visual Status
- Color by status (open, in_progress, closed, blocked)
- Progress visible at a glance
- No context needed to see what's done, active, remaining
- Bottom-up view shows full context for any task
The Discovery Tree Workflow
API Location: This skill includes a ready-to-use TypeScript API in src/discovery-tree.ts - a unified entry point that consolidates database operations and Shortcut integration.
TypeScript Execution: All code examples use top-level await (no async wrapper needed). Single-line imports only.
1. Set Workspace and Create Root Epic
Every Discovery Tree starts with setting workspace context, then creating an epic (container) and root task (actual work):
// Import from discovery-tree-workflow skill's src directory
// IMPORTANT: Use single-line imports only
import {
setWorkspace,
createTask,
addDependency,
updateTask,
closeTask,
findReadyTasks,
getEpicStatus,
drawTree
} from '~/.claude/skills/discovery-tree-workflow/src/discovery-tree.js';
// Set workspace context
await setWorkspace({ workspacePath: '/path/to/project' });
// Create epic (container for all work)
const epic = await createTask({
title: "Feature: User Authentication",
type: "epic",
priority: 1
});
// Create root task (describes the user value)
const rootTask = await createTask({
title: "User Authentication [root]",
type: "task",
priority: 1
});
// Link root task to epic
await addDependency({
taskId: rootTask.id,
dependsOnId: epic.id,
type: "parent-child"
});
Why both epic and root task?
- Epic: Container that tracks overall completion
- Root task: Actual work item that can have subtasks
2. Initial Breakdown
Have a quick conversation (2-10 minutes) to identify first level of work:
Questions to ask:
- "What are the main pieces of this?"
- "What do we need to understand first?"
- "What can we start with minimal detail?"
Create tasks for what you discover:
// Create main tasks
const task1 = await createTask({
title: "API endpoint for login",
type: "task",
priority: 1
});
const task2 = await createTask({
title: "Password validation logic",
type: "task",
priority: 1
});
const task3 = await createTask({
title: "Session management",
type: "task",
priority: 1
});
// Link them to root task
await addDependency({
taskId: task1.id,
dependsOnId: rootTask.id,
type: "parent-child"
});
await addDependency({
taskId: task2.id,
dependsOnId: rootTask.id,
type: "parent-child"
});
await addDependency({
taskId: task3.id,
dependsOnId: rootTask.id,
type: "parent-child"
});
Don't over-plan: Stop when you have enough to start. More detail emerges as you work.
3. Start Working
Pick a task and claim it:
// Find what's ready to work on
const readyTasks = await findReadyTasks({ limit: 10 });
// Claim the first ready task
await updateTask({
taskId: readyTasks[0].id,
status: "in_progress"
});
As you work:
- Discover subtasks needed? Create and link them
- Find blocking issues? Create with
blockedstatus - Get distracted by ideas? Create low-priority task to bookmark
// Discovered more work
const subtask = await createTask({
title: "Validate email format",
type: "task",
priority: 1
});
await addDependency({
taskId: subtask.id,
dependsOnId: task1.id,
type: "parent-child"
});
// Found blocker
const blocker = await createTask({
title: "Database schema needs user table",
type: "task",
priority: 0
});
await updateTask({
taskId: task1.id,
status: "blocked"
});
4. Complete and Continue
When task is done:
await closeTask({
taskId: task1.id,
reason: "Completed"
});
// Update parent with what was accomplished
await updateTask({
taskId: rootTask.id,
notes: "Completed: API endpoint for login. Previously: Initial setup"
});
IMPORTANT: Update parent task with what was accomplished to keep context accurate as subtasks complete.
Check progress:
const status = await getEpicStatus({ epicId: epic.id });
console.log(`Progress: ${status.completionPercentage}%`);
console.log(`${status.completedTasks}/${status.totalTasks} tasks complete`);
// See what's ready to work on next
const nextReady = await findReadyTasks({ limit: 5 });
If more work remains: Claim next task, repeat cycle
If work emerges: Add to tree, keep going
If blocked: Mark blocked, work on unblocked tasks
5. View Progress
// Bottom-up view from any task (current → parent → grandparent → root)
const tree = await getDependencyTree({ taskId: currentTask.id });
// Visual tree (top-down view from epic)
const visualTree = await drawTree({ taskId: epic.id });
console.log(visualTree); // Display to user
// Epic completion stats
const epicStatus = await getEpicStatus({ epicId: epic.id });
Integration with Skills
With TDD
- Create task for feature
- TDD cycle: RED → GREEN → REFACTOR
- If new test reveals complexity → create subtask
- Close task when all tests pass
With Example-Driven Design
- Create task for user story
- EXAMPLE phase discovers API shape → might create subtasks
- Each phase completion → progress visible in tree
- CHECK phase → close task or create next example task
With Mikado Method
- Discover prerequisite → create task with
discovered-fromdependency - Each prerequisite becomes subtask
- Work on leaf tasks (no dependencies)
- Close prerequisites, return to parent
Quick Reference
| Action | API Function |
|---|---|
| Set workspace | setWorkspace({ workspacePath }) |
| Create epic | createTask({ title, type: "epic", priority: 1 }) |
| Create task | createTask({ title, type: "task", priority }) |
| Link to parent | addDependency({ taskId, dependsOnId, type: "parent-child" }) |
| Claim task | updateTask({ taskId, status: "in_progress" }) |
| Complete task | closeTask({ taskId, reason }) |
| Update task | updateTask({ taskId, notes, description, title }) |
| View tree | getDependencyTree({ taskId }) |
| Draw visual tree | drawTree({ taskId }) |
| Check progress | getEpicStatus({ epicId }) |
| Find ready work | findReadyTasks({ limit }) |
| Mark blocked | updateTask({ taskId, status: "blocked" }) |
| Show task details | showTask({ taskId }) |
| Append notes | appendNotes({ taskId, notes }) |
Common Patterns
Capture Distractions
// Something came up while working
const distraction = await createTask({
title: "Refactor utils.ts for clarity",
type: "task",
priority: 3
});
await addDependency({
taskId: distraction.id,
dependsOnId: currentParent.id,
type: "parent-child"
});
// Now it's captured, back to current work
Break Down Complex Task
// Realized task is bigger than expected
const subtask1 = await createTask({
title: "Part 1: Schema validation",
type: "task",
priority: 1
});
const subtask2 = await createTask({
title: "Part 2: Error handling",
type: "task",
priority: 1
});
await addDependency({
taskId: subtask1.id,
dependsOnId: complexTask.id,
type: "parent-child"
});
await addDependency({
taskId: subtask2.id,
dependsOnId: complexTask.id,
type: "parent-child"
});
// Parent stays open until children done
await updateTask({
taskId: complexTask.id,
status: "open"
});
Handle Discovered Prerequisites
// Found something that must be done first
const prerequisite = await createTask({
title: "Add user_id column to sessions table",
type: "task",
priority: 0
});
await addDependency({
taskId: currentTask.id,
dependsOnId: prerequisite.id,
type: "blocks"
});
await updateTask({
taskId: currentTask.id,
status: "blocked"
});
await updateTask({
taskId: prerequisite.id,
status: "in_progress"
});
Restructure Tree Based on New Learnings
// When requirements change and tree needs reorganizing
await setWorkspace({ workspacePath });
// Create new epic/structure
const newEpic = await createTask({
title: "Revised Approach",
type: "epic",
priority: 1
});
// Create tasks programmatically
const tasks = await Promise.all([
createTask({ title: "New component A", type: "task", priority: 1 }),
createTask({ title: "New component B", type: "task", priority: 1 }),
createTask({ title: "Integration layer", type: "task", priority: 2 })
]);
// Link all at once
for (const task of tasks) {
await addDependency({
taskId: task.id,
dependsOnId: newEpic.id,
type: "parent-child"
});
}
// Close obsolete tasks
await closeTask({
taskId: oldTask.id,
reason: "Superseded by revised approach"
});
API Types
type TaskType = "bug" | "feature" | "task" | "epic" | "chore";
type TaskStatus = "open" | "in_progress" | "blocked" | "closed";
type DependencyType = "parent-child" | "blocks" | "related" | "discovered-from";
interface Task {
id: string;
title: string;
description: string;
status: TaskStatus;
priority: number;
taskType: TaskType;
createdAt: string;
updatedAt: string;
}
interface EpicStatus {
epicId: string;
totalTasks: number;
completedTasks: number;
inProgressTasks: number;
blockedTasks: number;
openTasks: number;
completionPercentage: number;
}
Red Flags
STOP if you catch yourself:
- Planning all details upfront before starting work
- Using TodoWrite instead of discovery trees for multi-step work
- Keeping task breakdown in your head instead of API
- Not capturing emerged work because "it's small"
- Marking tasks complete without using
closeTask() - Closing subtasks without updating parent task with what was done
- Forgetting to check
findReadyTasks()when looking for next work - Creating flat task lists instead of hierarchical trees
All of these mean: Use Discovery Trees with the TypeScript API for visible, emergent planning.
Why This Works
Just-in-time planning:
- Short conversations vs hours of upfront meetings
- Plan what you need now, defer rest
- Less waste from planning things that change
Emergent structure:
- Tree grows as understanding deepens
- Captures reality of software development (new discoveries)
- Makes unexpected work visible, not hidden
Visual progress:
- Anyone can see status without asking
- Bottom-up tree shows full context
- Epic progress shows completion percentage
Focus maintenance:
- Distractions captured as low-priority tasks
- Current work stays visible
- Easy to return to main path
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
sharpening-the-knife
Use when discovering a useful technique, pattern, or insight during work - pause to capture it as a skill before the knowledge evaporates, preventing the "I'll remember this" trap that causes expertise loss
incremental-tdd
Use when implementing features or refactoring with TDD - enforces writing ONE test at a time, implementing minimal code to pass, then repeating, preventing batch test writing that defeats incremental design discovery
dispatching-systematic-debugging
Use when encountering bugs, test failures, unexpected behavior, errors, or performance problems - dispatches systematic-debugging-agent that enforces 4-phase process (root cause investigation, pattern analysis, hypothesis testing, implementation) to prevent quick-fix attempts and ensure proper debugging
using-jj
Use when working with Jujutsu (jj) version control for task management and change tracking - provides workflows for examine-commit-work-squash cycle, checkpointing progress, and managing working copies
test-watch-focused-patterns
Use when developing tests or refactoring test suites - run tests in watch mode with focused file patterns to get instant feedback on specific test files without running the entire suite
wishful-thinking-programming
Use when building features with unknowns or uncertainties - start from well-understood parts (business logic, UX, pure functions), write code as if ideal collaborators exist, use mocks to define APIs through usage, preventing analysis paralysis from trying to understand everything upfront
Didn't find tool you were looking for?