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, addStep
Cross-Agent: addDependentStep, completeStepWithOutput, getBlockedSteps
Total: 9 tools
User Commands plan
Auto-approved setStepStatus, getPlanStatus, completePlan, addStep, addDependentStep, completeStepWithOutput, getBlockedSteps, plan (all except createPlan and startPlan)
Event-subscription tools are session-level core tools
Cross-agent event-subscription tools (subscribeToEvents, getTaskEvents, listSubscriptions, unsubscribe) were moved to session-level core tools in shared/event_bus_tools.py. They are not provided by the todo plugin and must not be listed here. The todo plugin's 9 tools are exactly those returned by get_tool_schemas() above.

Workflow

  1. createPlan: Register an execution plan with ordered steps
  2. startPlan: Request user approval (requires permission)
  3. setStepStatus: Report progress on each step
  4. addStep: Add new steps if needed during execution
  5. completePlan: Mark plan as finished
startPlan Requires Approval
The 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.
Basic usage
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',
})
Model workflow example
# 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.

TypeDict[str, Any]
Default{}

storage_type

How to persist plan data.

Type"memory" | "file" | "hybrid"
Default"memory"

storage_path

Path for file-based storage.

Typestr
Default".jaato/plans.json"

config_path

Path to todo.json configuration file.

Typestr
Default".jaato/todo.json"
Configuration examples
# 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',
    },
})
todo.json config file
{
  "reporter_type": "console",
  "storage_type": "file",
  "storage_path": ".jaato/plans.json"
}

Tool Reference

createPlan

Register a new execution plan with ordered steps.

ParameterTypeRequired
titlestringYes
stepsstring[]Yes

startPlan

Request user approval to begin execution. Requires permission.

ParameterTypeRequired
messagestringNo

setStepStatus

Report progress on a specific step.

ParameterTypeRequired
step_idstringYes
status"in_progress" | "completed" | "failed" | "skipped"Yes
resultstringNo
errorstringNo

addStep

Add a new step during execution.

ParameterTypeRequired
descriptionstringYes
after_step_idstringNo

completePlan

Mark the plan as finished.

ParameterTypeRequired
status"completed" | "failed" | "cancelled"Yes
summarystringNo
createPlan response
{
  "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."
}
getPlanStatus response
{
  "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.

Commandplan
share_with_modelFalse
Auto-approvedYes

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.

User command example
> 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:

StatusWhen 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)
Honest Reporting
The model is instructed: "If you say 'could not', 'unable to', or similar in the result, the status MUST be 'failed'. Being honest about failures is more valuable than false completion reports."
Status examples
# 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:

  1. Registration: addDependentStep registers the dependency with the event bus
  2. Blocking: The step is created with status blocked
  3. Completion: When the subagent calls completeStepWithOutput, a step_completed event is published
  4. Resolution: The event bus automatically resolves the dependency
  5. Unblocking: The parent's step transitions from blockedpending
  6. Output Delivery: The subagent's output is stored in received_outputs
No Polling Required
Steps auto-unblock when all dependencies complete. The parent agent doesn't need to poll - just wait for the step to become ready.

Key Concepts

ConceptDescription
blocked statusStep waiting for dependencies from other agents
depends_onList of {agent_id, step_id} references this step waits for
blocked_byUnresolved dependencies (auto-updated as they complete)
received_outputsMap of outputs from completed dependencies
Parent-Subagent coordination workflow
# === PARENT AGENT ===

# 1. Subscribe to events BEFORE spawning subagents
#    (subscribeToEvents is a session-level core tool, not a todo tool)
subscribeToEvents(
    event_types=['plan_created', 'step_completed']
)

# 2. Create your master plan (include a step for awaiting results)
createPlan(title="Main Task", steps=[
    "Spawn implementer",
    "Await and integrate results",  # will get dependency added
])
startPlan()

# 3. Spawn subagent (subagent creates its own plan)
# ... spawn_subagent('implementer', task="...")

# 4. When you see plan_created event, link existing step to subagent work
addDependentStep(
    step_id="",  # existing step in YOUR plan
    depends_on=[
        {"agent_id": "implementer", "step_id": "final_step"}
    ]
)
# → Your existing step is now BLOCKED

# 5. Wait... step auto-unblocks when subagent completes

# 6. Check received outputs
status = getPlanStatus()
# status.steps[await_step].received_outputs = {'implementer:final_step': {...}}
Subagent completing with output
# === 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

Event-subscription tools are NOT todo tools
subscribeToEvents, getTaskEvents, listSubscriptions, and unsubscribe are session-level core tools defined in shared/event_bus_tools.py. They are not provided by the todo plugin. The todo plugin exposes exactly 9 tools.

addDependentStep

Add cross-agent dependencies to an existing step in your plan. The step is BLOCKED until all dependencies complete, then auto-unblocks. Unlike addStep, this does NOT create a new step — it modifies an existing one by attaching dependency references.

ParameterTypeRequired
step_idstringYes — ID of an existing step in your plan
depends_on{agent_id, step_id, plan_id?, agent_name?, step_sequence?, step_description?}[]Yes
providesstringNo — named output key for this step

completeStepWithOutput

Complete a step AND pass structured data to dependent tasks. Use this for subagent final steps.

ParameterTypeRequired
step_idstringYes
outputobjectYes
resultstringNo

getBlockedSteps

See which steps are waiting on other agents.

ParameterTypeRequired
plan_idstringNo
addDependentStep response
{
  "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)"
}
getBlockedSteps response
{
  "blocked_steps": [
    {
      "step_id": "step_abc123",
      "description": "Review implementation results",
      "blocked_by": [
        {"agent_id": "implementer", "step_id": "final_step"}
      ],
      "received_outputs": {}
    }
  ],
  "count": 1
}
After dependency resolves
{
  "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"]
    }
  }
}