@comfanion/usethis_todo
v0.1.16
Published
OpenCode plugin: enhanced TODO tools (dual storage + dependency graph)
Readme
📋 @comfanion/usethis_todo
Smart TODO management with dependency graphs and priority tracking
Stop juggling tasks in your head — let the graph show you what to do next!
✨ What is this?
An OpenCode plugin that transforms TODO lists into intelligent task graphs:
- 🎯 Dependency tracking — tasks know what blocks them
- 📊 Visual graph analysis — see available, blocked, and parallel tasks
- 🔥 Priority system — CRIT | HIGH | MED | LOW with auto-sorting
- 🏗️ Hierarchical IDs — E01-S01-T01 (Epic → Story → Task)
- 💾 Dual storage — enhanced features + native TUI integration
- 🚀 Smart transitions — auto-promote tasks when conditions are met
🧹 Context Leak Problem & Auto-Pruning
The Problem
This is not a problem introduced by this plugin — it is an existing problem in the default TodoRead / TodoWrite MCP tools that ship with AI coding agents (Claude Code, OpenCode, etc.).
The default TODO tools work through MCP (Model Context Protocol). When the agent calls a TODO tool, two things happen:
- The MCP tool response is added to conversation history (the agent sees the result)
- A separate chat message is injected into the conversation as a workaround for UI display
The agent sees both — the tool result AND the duplicate chat message. Every single TODO call produces double output in the context window:
Agent calls: TodoWrite(...)
→ tool response: +800 tokens (MCP result — agent sees this)
→ chat message: +800 tokens (UI workaround — agent sees this too)
─────────────────────────────────
Total per call: ~1,600 tokens (2x duplication)In a typical session, an agent calls TODO tools dozens of times — creating tasks, updating statuses, reading the list, checking what's next. Without cleanup:
Call 1: TodoWrite → +1,600 tokens (tool result + chat duplicate)
Call 2: TodoUpdate → +1,600 tokens (tool result + chat duplicate)
Call 3: TodoRead → +1,600 tokens (tool result + chat duplicate)
Call 4: TodoUpdate → +1,600 tokens (tool result + chat duplicate)
...
Call 20: TodoUpdate → +1,600 tokens (tool result + chat duplicate)
─────────────────────────────────────────────────────
Total TODO overhead: ~32,000 tokens — stale duplicated snapshotsOnly the last call result matters. The other 19 are stale data sitting in the context window, pushing out useful code, conversation, and reasoning. This is the context leak — silent, cumulative, and it degrades agent performance as the session progresses.
The problem compounds with larger task lists. A 30-task graph with dependencies can produce 2,000+ tokens per call. With 2x duplication, after 15 updates that's 60,000 tokens of dead weight — roughly 20-30% of a typical context window, gone.
The Solution: Auto-Pruning
This plugin solves both problems — stale accumulation and duplication — by hooking into experimental.chat.messages.transform to automatically clean up old TODO results before each LLM call:
Call 1: usethis_todo_write → [TODO pruned] + snapshot removed ← cleaned
Call 2: usethis_todo_update → [TODO pruned] + snapshot removed ← cleaned
Call 3: usethis_todo_read → [TODO pruned] + snapshot removed ← cleaned
Call 4: usethis_todo_update → (full graph output) + latest snapshot ← only latest kept
─────────────────────────────────────────────────────
Total TODO overhead: ~800 tokens — constant, not cumulativeHow it works:
- Track last call — after each TODO tool execution, the plugin records the
callIDin a per-session state - Transform messages — before each LLM inference, the plugin scans all messages and replaces old TODO tool outputs with
[TODO pruned], clearing bothoutputandinputfields - Keep latest — only the most recent TODO call result is preserved in full, giving the agent current state
- Prune chat snapshots — the plugin publishes TODO state as
## TODOuser messages for UI display; old snapshot messages are removed entirely from the message list, keeping only the latest one. This eliminates the duplication problem where the agent would otherwise see both the tool result and the chat message - Complete cleanup — when all tasks are marked
done, even the last result and the last snapshot are pruned — the TODO list served its purpose and no longer needs context space
Result: TODO tool overhead is O(1) instead of O(n) — constant ~800 tokens regardless of how many times the agent interacts with the task list. The 2x duplication from the chat workaround is also eliminated.
What Gets Pruned
| Content | Pruned? | Why |
|---------|---------|-----|
| Old tool outputs (todo_write, todo_update, etc.) | Yes | Stale state, agent doesn't need old snapshots |
| Old tool inputs | Yes | Arguments to stale calls are not useful |
| Old ## TODO chat snapshot messages | Yes | Duplicate of tool output injected for UI display |
| Latest tool call output | No | Agent needs current state to make decisions |
| Latest ## TODO chat snapshot | No | Kept for UI consistency |
| All outputs when all tasks are done | Yes | Work is finished, free the entire context budget |
Default tools vs. this plugin
| | Default TodoRead/TodoWrite | @comfanion/usethis_todo |
|---|---|---|
| Tool result in context | Accumulates forever | Auto-pruned, only latest kept |
| Chat message duplicate | Accumulates forever | Auto-pruned, only latest kept |
| Tokens per call (visible to agent) | ~1,600 (tool + chat duplicate) | ~800 (only latest) |
| After 20 calls | ~32,000 tokens wasted | ~800 tokens constant |
| When all tasks done | Still in context | Fully cleaned up |
| Context overhead | O(n) — grows with every call | O(1) — constant |
🚀 Quick Start
Installation
npm install @comfanion/usethis_todoConfiguration
Add to opencode.json:
{
"plugin": ["@comfanion/usethis_todo"]
}First TODO
usethis_todo_write({
todos: [
{
id: "E01-S01-T01",
content: "Setup database schema",
status: "todo",
priority: "HIGH"
},
{
id: "E01-S01-T02",
content: "Create API endpoints",
status: "todo",
priority: "HIGH",
blockedBy: ["E01-S01-T01"] // Waits for T01
}
]
})Output:
TODO Graph [0/2 done, 0 in progress]
All Tasks:
- E01
- E01-S01
- ○ 🟠 E01-S01-T01: Setup database schema
- ⊗ 🟠 E01-S01-T02: Create API endpoints ← E01-S01-T01
Available Now:
- E01
- E01-S01
- ○ 🟠 E01-S01-T01: Setup database schema
Blocked:
- E01
- E01-S01
- ⊗ 🟠 E01-S01-T02: Create API endpoints ← E01-S01-T01🎯 Core Features
1. Dependency Graph
Tasks can depend on other tasks. The plugin automatically:
- ✅ Shows which tasks are available (no blockers)
- ⊗ Shows which tasks are blocked (waiting on others)
- 🔗 Resolves transitive dependencies (A → B → C)
- ⚡ Identifies parallel tasks (can work on simultaneously)
Example:
usethis_todo_write({
todos: [
{ id: "T01", content: "Design API", status: "done", priority: "HIGH" },
{ id: "T02", content: "Implement API", status: "todo", priority: "HIGH", blockedBy: ["T01"] },
{ id: "T03", content: "Write tests", status: "todo", priority: "MED", blockedBy: ["T02"] },
{ id: "T04", content: "Setup CI/CD", status: "todo", priority: "MED" } // Parallel!
]
})Graph shows:
- Available: T02 (T01 done), T04 (no blockers)
- Blocked: T03 (waits for T02)
- Parallel: T02 and T04 can be done simultaneously
2. Priority System
Four priority levels with visual indicators:
| Priority | Icon | Use Case |
|----------|------|----------|
| CRIT | 🔴 | Production down, security issue |
| HIGH | 🟠 | Sprint goal, blocking others |
| MED | 🟡 | Normal work (default) |
| LOW | 🟢 | Nice to have, refactoring |
Tasks are auto-sorted by priority in all views.
3. Hierarchical IDs
Organize tasks in 3 levels:
E01-S01-T01
│ │ └── Task 01
│ └────── Story 01
└────────── Epic 01Benefits:
- 📁 Nested display (epics → stories → tasks)
- 🔍 Easy filtering (all tasks in E01-S01)
- 📊 Progress tracking per epic/story
4. Status Lifecycle
todo → in_progress → ready → done
↓ ↓ ↓ ↓
○ ⚙ ⏳ ✓Auto-transitions:
ready→donewhenreleasesfield is set- Blocked tasks show
⊗icon (even if status istodo)
5. Release Tracking
Mark tasks as part of releases:
usethis_todo_update({
todos: [{
id: "E01-S01-T01",
status: "ready",
releases: ["E01-S01-T01-ST02"] // Auto-promotes to "done"
}]
})🛠️ Tools Reference
usethis_todo_write
Create or replace entire TODO list.
usethis_todo_write({
todos: [
{
id: "E01-S01-T01", // Required: Hierarchical ID
content: "Task summary", // Required: Short description
description: "Full details...", // Optional: Long description
status: "todo", // Required: todo | in_progress | ready | done
priority: "HIGH", // Required: CRIT | HIGH | MED | LOW
blockedBy: ["E01-S01-T02"], // Optional: Dependency IDs
releases: ["E01-S01", "E01-S01-T02"] // Optional: Release tags
}
]
})Returns: Full graph analysis
usethis_todo_read
Read all tasks with graph analysis.
usethis_todo_read()Returns:
- All tasks (nested by epic/story)
- Available tasks (ready to work on)
- Blocked tasks (waiting on dependencies)
- Progress stats (X/Y done, Z in progress)
usethis_todo_read_five
Get next 5 available tasks (smart view).
usethis_todo_read_five()Returns:
- Top 5 tasks by priority
- Resolved blockers (what they depend on)
- Missing dependencies (if any)
Perfect for: "What should I work on next?"
usethis_todo_read_by_id
Get details for specific task.
usethis_todo_read_by_id({ id: "E01-S01-T01" })Returns:
- Task details
- Full dependency chain
- Missing dependencies
usethis_todo_update
Update one or more tasks (merge mode).
usethis_todo_update({
todos: [
{
id: "E01-S01-T01",
status: "done" // Only update status, keep other fields
},
{
id: "E01-S01-T02",
status: "in_progress",
priority: "CRIT" // Update multiple fields
}
]
})Returns: Updated graph
🎨 Usage Examples
Example 1: Sprint Planning
// Create sprint tasks
usethis_todo_write({
todos: [
// Epic 01: User Authentication
{ id: "E01-S01-T01", content: "Design auth API", status: "done", priority: "HIGH" },
{ id: "E01-S01-T02", content: "Implement JWT", status: "in_progress", priority: "HIGH", blockedBy: ["E01-S01-T01"] },
{ id: "E01-S01-T03", content: "Add refresh tokens", status: "todo", priority: "MED", blockedBy: ["E01-S01-T02"] },
// Epic 02: User Profile (parallel work)
{ id: "E02-S01-T01", content: "Design profile schema", status: "todo", priority: "MED" },
{ id: "E02-S01-T02", content: "Create profile API", status: "todo", priority: "MED", blockedBy: ["E02-S01-T01"] }
]
})Graph shows:
- Available: E01-S01-T02 (in progress), E02-S01-T01 (can start)
- Blocked: E01-S01-T03, E02-S01-T02
- Parallel: E01 and E02 can progress simultaneously
Example 2: Daily Workflow
// Morning: What's next?
usethis_todo_read_five()
// → Shows top 5 tasks by priority
// Start working
usethis_todo_update({
todos: [{ id: "E01-S01-T02", status: "in_progress" }]
})
// Finish task
usethis_todo_update({
todos: [{ id: "E01-S01-T02", status: "done" }]
})
// Check what unblocked
usethis_todo_read_five()
// → E01-S01-T03 now available!Example 3: Bug Triage
// Critical bug found!
usethis_todo_update({
todos: [{
id: "BUG-001",
content: "Fix login crash",
status: "todo",
priority: "CRIT" // Jumps to top of queue
}]
})
usethis_todo_read_five()
// → BUG-001 is first (CRIT priority)Example 4: Task Completion Tracking
// Mark tasks as completed with linked subtask IDs
usethis_todo_update({
todos: [
{ id: "E01-S01-T01", status: "ready", releases: ["E01-S01-T01-ST01", "E01-S01-T01-ST02"] },
{ id: "E01-S01-T02", status: "ready", releases: ["E01-S01-T02-ST01"] }
]
})
// → Auto-promotes to "done" when releases set
// Check progress
usethis_todo_read()
// → Both tasks promoted to "done"Example 5: Complex Dependencies
usethis_todo_write({
todos: [
{ id: "T01", content: "Database schema", status: "done", priority: "HIGH" },
{ id: "T02", content: "API layer", status: "done", priority: "HIGH", blockedBy: ["T01"] },
{ id: "T03", content: "Business logic", status: "todo", priority: "HIGH", blockedBy: ["T02"] },
{ id: "T04", content: "UI components", status: "todo", priority: "MED", blockedBy: ["T03"] },
{ id: "T05", content: "Integration tests", status: "todo", priority: "MED", blockedBy: ["T04"] }
]
})
// Check specific task
usethis_todo_read_by_id({ id: "T05" })
// → Shows full chain: T05 ← T04 ← T03 ← T02 ← T01📦 Storage
Dual Storage System
The plugin writes to two locations:
1. Enhanced Storage (Project-local)
.opencode/
session-todo/
{session-id}.json # Full data with dependencies
todo.log # Action logContains:
- Full task data (description, blockedBy, releases)
- Timestamps (createdAt, updatedAt)
- All custom fields
2. Native Storage (TUI Integration)
~/.local/share/opencode/storage/todo/{session-id}.json
# or
~/Library/Application Support/opencode/storage/todo/{session-id}.jsonContains:
- Simplified format for OpenCode TUI
- Status/priority mapped to native values
- Dependencies shown in content field
Why dual storage?
- ✅ Enhanced features (graph, dependencies)
- ✅ Native TUI display (sidebar integration)
- ✅ Best of both worlds!
🎨 Visual Indicators
Status Icons
| Icon | Status | Meaning |
|------|--------|---------|
| ○ | todo | Not started |
| ⚙ | in_progress | Working on it |
| ⏳ | ready | Done, awaiting release |
| ✓ | done | Completed |
| ✗ | cancelled | Abandoned |
| ⊗ | (blocked) | Has active blockers |
Priority Icons
| Icon | Priority | Color | |------|----------|-------| | 🔴 | CRIT | Red | | 🟠 | HIGH | Orange | | 🟡 | MED | Yellow | | 🟢 | LOW | Green |
🧠 Smart Features
1. Auto-Promotion
Tasks automatically transition when conditions are met:
// Task in "ready" status
{ id: "T01", status: "ready", releases: [] }
// Add completed subtask IDs
usethis_todo_update({
todos: [{ id: "T01", releases: ["T01-ST01", "T01-ST02"] }]
})
// → Auto-promotes to "done"!2. Transitive Dependencies
The plugin resolves entire dependency chains:
// T03 depends on T02, T02 depends on T01
usethis_todo_read_by_id({ id: "T03" })
// Shows full chain:
// Blocked By (resolved):
// - T02 (in_progress)
// - T01 (done)3. Parallel Detection
Identifies tasks that can be worked on simultaneously:
// Graph analysis shows:
// Parallel groups:
// - [T02, T04, T05] ← Can all start now
// - [T03, T06] ← Can start after T02 done4. Missing Dependency Detection
Warns about broken references:
{ id: "T01", blockedBy: ["T99"] } // T99 doesn't exist
usethis_todo_read_by_id({ id: "T01" })
// → Blocked By missing: T99🔧 Advanced Usage
Custom ID Schemes
While hierarchical IDs are recommended, you can use any format:
// Hierarchical (recommended)
{ id: "E01-S01-T01" } // Epic-Story-Task
// Flat
{ id: "TASK-001" }
// Custom
{ id: "AUTH-LOGIN-JWT" }Note: Hierarchical IDs get nested display, others show flat.
Filtering by Status
// Get all in-progress tasks
const todos = await usethis_todo_read()
const wip = todos.filter(t => t.status === "in_progress")Progress Tracking
// Track epic progress
const todos = await usethis_todo_read()
const epic01 = todos.filter(t => t.id.startsWith("E01-"))
const done = epic01.filter(t => t.status === "done").length
const total = epic01.length
console.log(`Epic 01: ${done}/${total} done`)🐛 Debugging
Enable Logging
All operations are logged to .opencode/todo.log:
[2024-01-15T10:30:00.000Z] WRITE: Created/Updated 5 tasks in session abc123
[2024-01-15T10:31:00.000Z] UPDATE: Updated 1 task(s) in session abc123
[2024-01-15T10:32:00.000Z] READ_FIVE: Read next 5 tasks (total ready: 12)Check Storage
# Enhanced storage
cat .opencode/session-todo/{session-id}.json
# Native storage (macOS)
cat ~/Library/Application\ Support/opencode/storage/todo/{session-id}.json
# Native storage (Linux)
cat ~/.local/share/opencode/storage/todo/{session-id}.jsonValidate Dependencies
// Check for circular dependencies
usethis_todo_read()
// → Graph analysis will show if tasks are mutually blocked🌟 Advantages
Compared to Simple TODO Lists
| Feature | Simple TODO | usethis_todo | |---------|-------------|--------------| | Task list | ✅ | ✅ | | Dependencies | ❌ | ✅ | | Priority sorting | ❌ | ✅ | | Graph analysis | ❌ | ✅ | | Parallel detection | ❌ | ✅ | | Hierarchical IDs | ❌ | ✅ | | Auto-transitions | ❌ | ✅ | | Release tracking | ❌ | ✅ |
Compared to Project Management Tools
| Feature | Jira/Asana | usethis_todo | |---------|------------|--------------| | In your editor | ❌ | ✅ | | Offline | ❌ | ✅ | | Free | ❌ | ✅ | | Fast | 🐌 | ⚡ | | No context switch | ❌ | ✅ | | Version controlled | ❌ | ✅ (project-local) |
📊 Technical Details
- Storage format: JSON
- Session isolation: Tasks are per-session (multi-session support)
- Dependency resolution: Recursive graph traversal
- Priority sorting: Stable sort (CRIT → HIGH → MED → LOW → ID)
- Status normalization: Backward-compatible with old formats
- TUI integration: Automatic sync to native storage
🤝 Contributing
Found a bug? Have an idea? Open an issue or PR!
📄 License
MIT
🎉 Authors
Made with ❤️ by the Comfanion team
Work smart, not hard — let the graph guide you! 🚀
