Todo Plugin
Plan registration and progress tracking. Enables the model to create execution plans, report progress on steps, and provide visibility into task completion.
| Name | todo |
| Type | Tool Plugin (Registry-managed) |
| Tools Provided |
Core: createPlan, startPlan, setStepStatus, getPlanStatus, completePlan, addStepCross-Agent: subscribeToTasks, addDependentStep, completeStepWithOutput, getBlockedSteps, getTaskEvents, listSubscriptions, unsubscribe
|
| User Commands | plan |
| Auto-approved | All except startPlan |
Workflow
- createPlan: Register an execution plan with ordered steps
- startPlan: Request user approval (requires permission)
- setStepStatus: Report progress on each step
- addStep: Add new steps if needed during execution
- completePlan: Mark plan as finished
startPlan tool requires user permission because it
commits the model to executing a plan. All other todo tools are
auto-approved since they're purely informational.
from jaato import PluginRegistry
registry = PluginRegistry()
registry.discover()
# Expose todo plugin with defaults
registry.expose_tool('todo')
# With custom configuration
registry.expose_tool('todo', config={
'reporter_type': 'console',
'storage_type': 'file',
'storage_path': '.jaato/plans.json',
})
# 1. Create the plan
createPlan(
title="Refactor auth module",
steps=[
"Review current auth implementation",
"Extract token validation to separate module",
"Add unit tests for new module",
"Update imports in dependent files"
]
)
# 2. Request user approval
startPlan(message="Ready to proceed?")
# 3. Report progress on each step
setStepStatus(step_id="step_1", status="completed")
setStepStatus(step_id="step_2", status="in_progress")
# 4. Complete the plan
completePlan(status="completed", summary="Refactoring done")
Configuration Parameters
reporter_type
How to report plan progress to the user.
| Type | "console" | "webhook" | "file" |
| Default | "console" |
reporter_config
Configuration for the selected reporter.
| Type | Dict[str, Any] |
| Default | {} |
storage_type
How to persist plan data.
| Type | "memory" | "file" | "hybrid" |
| Default | "memory" |
storage_path
Path for file-based storage.
| Type | str |
| Default | ".jaato/plans.json" |
config_path
Path to todo.json configuration file.
| Type | str |
| Default | ".jaato/todo.json" |
# Console reporter with file storage
registry.expose_tool('todo', config={
'reporter_type': 'console',
'storage_type': 'file',
'storage_path': '.jaato/plans.json',
})
# Webhook reporter for remote monitoring
registry.expose_tool('todo', config={
'reporter_type': 'webhook',
'reporter_config': {
'url': 'https://api.example.com/plans',
'headers': {'Authorization': 'Bearer token'},
},
})
# File reporter for log-based tracking
registry.expose_tool('todo', config={
'reporter_type': 'file',
'reporter_config': {
'path': '/var/log/jaato/plans.log',
},
})
{
"reporter_type": "console",
"storage_type": "file",
"storage_path": ".jaato/plans.json"
}
Tool Reference
createPlan
Register a new execution plan with ordered steps.
| Parameter | Type | Required |
|---|---|---|
title | string | Yes |
steps | string[] | Yes |
startPlan
Request user approval to begin execution. Requires permission.
| Parameter | Type | Required |
|---|---|---|
message | string | No |
setStepStatus
Report progress on a specific step.
| Parameter | Type | Required |
|---|---|---|
step_id | string | Yes |
status | "in_progress" | "completed" | "failed" | "skipped" | Yes |
result | string | No |
error | string | No |
addStep
Add a new step during execution.
| Parameter | Type | Required |
|---|---|---|
description | string | Yes |
after_step_id | string | No |
completePlan
Mark the plan as finished.
| Parameter | Type | Required |
|---|---|---|
status | "completed" | "failed" | "cancelled" | Yes |
summary | string | No |
{
"plan_id": "plan_abc123",
"title": "Refactor auth module",
"status": "pending",
"steps": [
{"id": "step_1", "description": "Review current auth...", "status": "pending"},
{"id": "step_2", "description": "Extract token...", "status": "pending"},
{"id": "step_3", "description": "Add unit tests...", "status": "pending"},
{"id": "step_4", "description": "Update imports...", "status": "pending"}
],
"message": "Plan created. Call startPlan to request approval."
}
{
"plan_id": "plan_abc123",
"title": "Refactor auth module",
"status": "in_progress",
"progress": {
"completed": 2,
"total": 4,
"percentage": 50
},
"steps": [
{"id": "step_1", "status": "completed", "result": "..."},
{"id": "step_2", "status": "completed", "result": "..."},
{"id": "step_3", "status": "in_progress"},
{"id": "step_4", "status": "pending"}
]
}
User Command
plan
Show current or most recent plan status. This command can be invoked directly by the user without model mediation.
| Command | plan |
| share_with_model | False |
| Auto-approved | Yes |
The output is NOT shared with the model since it's purely for user visibility into progress. This keeps the conversation focused while allowing users to check plan status at any time.
> plan
Current Plan: Refactor auth module
Status: in_progress
Steps:
[x] step_1: Review current auth implementation
[x] step_2: Extract token validation to separate module
[>] step_3: Add unit tests for new module
[ ] step_4: Update imports in dependent files
Progress: 2/4 (50%)
Step Status Rules
The model is instructed to be honest about step outcomes:
| Status | When to Use |
|---|---|
completed |
Step was FULLY accomplished with expected outcome |
failed |
Could NOT achieve the step's goal for ANY reason |
skipped |
Step became unnecessary or was intentionally bypassed |
in_progress |
Currently working on this step |
blocked |
Waiting for dependencies from other agents (auto-unblocks when resolved) |
# Correct: Step fully achieved
setStepStatus(
step_id="step_1",
status="completed",
result="Found 3 auth-related files: auth.py, tokens.py, session.py"
)
# Correct: Step failed
setStepStatus(
step_id="step_2",
status="failed",
error="Could not find token validation logic in expected location"
)
# Correct: Step became unnecessary
setStepStatus(
step_id="step_3",
status="skipped",
result="Tests already exist, no need to add more"
)
# WRONG: Marking partial success as completed
setStepStatus(
step_id="step_4",
status="completed", # Should be "failed"!
result="Unable to update 2 of 5 imports due to circular dependencies"
)
Cross-Agent Collaboration
The TODO plugin supports coordination between parent agents and subagents through an event-driven architecture with automatic dependency resolution.
Auto-Unblock Mechanism
When a parent agent adds a dependent step:
- Registration:
addDependentStepregisters the dependency with the event bus - Blocking: The step is created with status
blocked - Completion: When the subagent calls
completeStepWithOutput, astep_completedevent is published - Resolution: The event bus automatically resolves the dependency
- Unblocking: The parent's step transitions from
blocked→pending - Output Delivery: The subagent's output is stored in
received_outputs
Key Concepts
| Concept | Description |
|---|---|
blocked status | Step waiting for dependencies from other agents |
depends_on | List of {agent_id, step_id} references this step waits for |
blocked_by | Unresolved dependencies (auto-updated as they complete) |
received_outputs | Map of outputs from completed dependencies |
# === PARENT AGENT ===
# 1. Subscribe to events BEFORE spawning subagents
subscribeToTasks(
event_types=['plan_created', 'step_completed']
)
# 2. Spawn subagent (subagent creates its own plan)
# ... spawn_subagent('implementer', task="...")
# 3. When you see plan_created event, add dependent step
addDependentStep(
description="Review implementation results",
depends_on=[
{"agent_id": "implementer", "step_id": "final_step"}
]
)
# → Step created as BLOCKED
# 4. Wait... step auto-unblocks when subagent completes
# 5. Check received outputs
status = getPlanStatus()
# status.received_outputs = {'implementer': {...}}
# === SUBAGENT ===
# Complete the step WITH structured output
completeStepWithOutput(
step_id="final_step",
output={
"passed": True,
"results": ["file1.py created", "tests pass"],
"errors": []
},
result="Implementation completed successfully"
)
# → Parent's dependent step auto-unblocks
# → Output delivered to parent's received_outputs
Cross-Agent Tool Reference
subscribeToTasks
Subscribe to task events from other agents. Call this BEFORE spawning subagents.
| Parameter | Type | Required |
|---|---|---|
agent_id | string | No (use * for any) |
event_types | string[] | Yes |
plan_id | string | No |
step_id | string | No |
Event types: plan_created, plan_started, plan_completed, plan_failed, plan_cancelled, step_added, step_started, step_completed, step_failed, step_skipped, step_blocked, step_unblocked
addDependentStep
Add a step that waits for tasks from other agents. Auto-unblocks when all dependencies complete.
| Parameter | Type | Required |
|---|---|---|
description | string | Yes |
depends_on | {agent_id, step_id}[] | Yes |
after_step_id | string | No |
provides | string | No |
completeStepWithOutput
Complete a step AND pass structured data to dependent tasks. Use this for subagent final steps.
| Parameter | Type | Required |
|---|---|---|
step_id | string | Yes |
output | object | Yes |
result | string | No |
getBlockedSteps
See which steps are waiting on other agents.
| Parameter | Type | Required |
|---|---|---|
plan_id | string | No |
getTaskEvents
Review recent cross-agent activity.
| Parameter | Type | Required |
|---|---|---|
agent_id | string | No |
event_types | string[] | No |
limit | number | No (default: 20) |
{
"step_id": "step_abc123",
"sequence": 2,
"description": "Review implementation results",
"status": "blocked",
"blocked_by": [
{"agent_id": "implementer", "step_id": "final_step"}
],
"message": "Step added with 1 dependencies (BLOCKED)"
}
{
"blocked_steps": [
{
"step_id": "step_abc123",
"description": "Review implementation results",
"blocked_by": [
{"agent_id": "implementer", "step_id": "final_step"}
],
"received_outputs": {}
}
],
"count": 1
}
{
"blocked_steps": [],
"message": "No blocked steps"
}
// Step status in getPlanStatus:
{
"step_id": "step_abc123",
"status": "pending", // Was "blocked", now ready
"received_outputs": {
"implementer:final_step": {
"passed": true,
"results": ["file1.py created"]
}
}
}