Deep Dive

Todo List System

When a task is too big for a single pass, RaggieCode creates a todo list. Tasks are planned upfront, reviewed by you, then executed one at a time by isolated subagents. If the session crashes, the todo list survives and can be resumed.

Estimated read time: 10 minutes · Updated July 12, 2026

How It Works

The todo list system is RaggieCode's mechanism for tackling complex, multi-step tasks that cannot be completed in a single LLM response. Instead of the agent jumping straight into execution, it first creates a plan, presents it to you for approval, and only then begins work .; one task at a time, each handled by an isolated subagent.

Why a todo list system?

A single prompt-response loop works well for small, atomic changes. But real-world tasks like "migrate from SQLite to PostgreSQL" or "add input validation to the login endpoint and update all callers" require multiple steps across many files. The todo list system provides:

User oversight .; You review and approve the plan before any code is touched.
Clean context .; Each subagent starts fresh, focused only on its task.
Crash resilience .; If the session terminates, the todo list survives in the database. Resume on restart.
Decomposition .; Complex subtasks can spawn their own nested todo lists, up to 3 levels deep.

The Workflow

Every todo list follows the same six-step pipeline. The agent checks for existing lists first (for crash recovery), creates a new one, adds tasks, reviews the plan, gets your approval, then executes.

Complete Todo List Workflow
1. GetActiveTodoList    Check for an incomplete todo list from a previous session.
                           If one exists and is pending/in_progress/rejected, resume it.
                           If not (or user declines), proceed to step 2.

2. CreateTodoList       Create a new todo list. Returns a todo_list_id used by
                           all subsequent calls in this pipeline.

3. AddTask (x N)        Add each task with a goal, optional requirements,
                           notes, context for the subagent, and an order_index.

4. GetTodoList          Retrieve and display the full plan. All tasks are shown
                           with their status: pending, in_progress, completed,
                           failed, or cancelled.

5. ApproveTodoList      Present the plan to the user for y/n approval.
                           If approved: status becomes approved, tasks can run.
                           If rejected: status becomes rejected. Rebuild the plan
                           based on user feedback.

6. ExecuteNextTask      Dispatch a subagent to execute the next pending task.
                           Repeated until all tasks are done or a task fails.
                           When all tasks complete, the todo list is auto-deleted.
GetActiveTodoList
CreateTodoList
AddTask x N
GetTodoList
ApproveTodoList
ExecuteNextTask (loop)

Step-by-Step Walkthrough

Here is what each step does, why it exists, and what the agent sees at each stage.

1

GetActiveTodoList Crash recovery gate

Before creating anything new, the agent checks whether an incomplete todo list already exists. This is the crash recovery mechanism: if the previous session was interrupted mid-task, the todo list is still in the database. The agent offers to resume it instead of starting fresh.

# Agent calls:
GetActiveTodoList()

# If an incomplete list exists:
Found incomplete todo list from previous session:
  Todo List #3 . "Migrate auth from SQLite to PostgreSQL"
  Status: in_progress
  Tasks: 2 completed, 3 pending

  Resume this todo list? [Y/n]:

If the user says yes, the agent skips steps 2-5 and goes straight to ExecuteNextTask. If no, the old list is cancelled and a new one is created.

2

CreateTodoList Allocate a new list

Creates a new todo list in the database and returns a todo_list_id. This ID is used by every subsequent call: AddTask, GetTodoList, ApproveTodoList, and ExecuteNextTask. The list is empty at this point .; no tasks yet.

# Agent calls:
CreateTodoList()

# Returns:
todo_list_id: 42
3

AddTask Populate the plan

Called once per task. Each task has five fields. The most important is context .; this is how you pass knowledge to the isolated subagent that will execute the task. Without it, the subagent has no idea what came before or what the broader goal is.

Field Required? Purpose
goal Required Clear description of what needs to be done
requirements Optional Specific constraints the subagent must follow
notes Optional Additional helpful context (hints, warnings, tips)
context Optional* Critical for subagent isolation. Background knowledge about the codebase, architecture decisions, file locations, API contracts .; everything the subagent needs to know since it starts with no conversation history.
order_index Required Execution order (0, 1, 2, ...). Tasks are executed sequentially in ascending order.
# Agent adds three tasks:
AddTask(todo_list_id=42, goal="Create a new database adapter for PostgreSQL",
         requirements="Must match the existing SQLite adapter interface",
         context="The project uses src/db/adapter.py as the base class...",
         order_index=0)

AddTask(todo_list_id=42, goal="Update all callers to use the new adapter",
         context="Callers found in src/api/routes.py, src/auth/login.py...",
         order_index=1)

AddTask(todo_list_id=42, goal="Run tests and fix any regressions",
         notes="Use pytest. The test suite is in tests/",
         order_index=2)
4

GetTodoList Review the plan

Retrieves the complete todo list with all tasks and their statuses. The agent uses this to verify the plan looks correct before asking for approval. All tasks start as pending.

# Agent calls:
GetTodoList(todo_list_id=42)

# Returns:
Todo List #42 . 3 tasks
──────────────────────────────────────────────
[0] pending  Create a new database adapter for PostgreSQL
[1] pending  Update all callers to use the new adapter
[2] pending  Run tests and fix any regressions
5

ApproveTodoList User approval gate

Displays the full plan to you and asks for approval. This is the human-in-the-loop checkpoint. No code has been touched yet. If you approve, the todo list status is set to approved and tasks can be executed. If you reject, the agent rebuilds the plan based on your feedback.

# Agent calls:
ApproveTodoList(todo_list_id=42)

# User sees:
Todo List #42 . 3 tasks
──────────────────────────────────────────────
[0] Create a new database adapter for PostgreSQL
[1] Update all callers to use the new adapter
[2] Run tests and fix any regressions
──────────────────────────────────────────────

Approve this plan? (y/n):

If you approve, the plan proceeds to execution. If you reject, the todo list status becomes rejected and the agent must rebuild the plan incorporating your feedback.

6

ExecuteNextTask Sequential execution loop

Each call dispatches the next pending task to a subagent. The subagent is an isolated session .; it has no access to the orchestrator's conversation history. It receives the task's goal, requirements, notes, context, and a summary of all previously completed tasks.

The agent calls ExecuteNextTask repeatedly until all tasks are done. Each call dispatches exactly one task. Tasks always execute in order_index order .; never in parallel.

# Agent calls sequentially:
ExecuteNextTask(todo_list_id=42)  # dispatches task [0]
ExecuteNextTask(todo_list_id=42)  # dispatches task [1]
ExecuteNextTask(todo_list_id=42)  # dispatches task [2]

# After the last task completes:
All tasks completed. Todo List #42 has been automatically deleted.

Key Behaviors

The todo list system is designed around a few fundamental principles that govern how tasks are created, executed, and recovered.

Sequential Execution

Tasks always execute one at a time, in order_index order. The agent never parallelises task execution. This is deliberate:

Deterministic ordering

Task 1's output (a new file, a refactored module) is available to task 2's subagent because the file system persists between tasks. This means later tasks can depend on earlier ones.

Predictable failure

If a task fails, it is clear which task caused the failure. The agent does not need to untangle overlapping changes from parallel tasks.

Context carry-forward

Each subagent receives a summary of all previously completed tasks. It knows what was done and what files were changed, even though it starts with a clean context window.

Cost control

Parallel execution would multiply API costs. Sequential execution keeps costs linear with the number of tasks.

Subagent Isolation

Each ExecuteNextTask call spawns a fresh subagent. This subagent:

  • Has no access to the orchestrator's conversation history
  • Receives only the task's goal, requirements, notes, context, and a summary of completed tasks
  • Starts with the same role, tools, and system prompt as the orchestrator
  • Has access to the code index, file system, and git repo
  • Can create its own nested todo lists (see below)

The context field is critical

Because subagents are isolated, the context field on AddTask is the only way to pass knowledge forward. Without sufficient context, the subagent may produce incorrect or incomplete work. Think of context as a mini-briefing document: include file paths, architecture decisions, API contracts, data structures, and any other details the subagent needs.

Crash Recovery

Todo lists are stored in the SQLite database on disk. If the session is interrupted .; terminal closed, process killed, system crash, or API timeout .; the todo list survives. On the next startup:

1

Agent calls GetActiveTodoList

At the start of every new session, the agent checks for incomplete todo lists. This is baked into the system prompt as a mandatory first step before creating anything new.

2

Incomplete list detected

If a todo list with status pending, in_progress, or rejected is found, the agent displays it to the user.

3

User chooses to resume or discard

If the user says yes, the agent picks up from the next pending task. The completed tasks are listed in the context passed to the subagent. If the user says no, the old list is cancelled and a new one can be created.

Crash recovery in the terminal
$ raggie code .

[INFO] Found incomplete todo list from previous session:

  Todo List #17: "Refactor auth middleware and update all callers"
  Status: in_progress
  Tasks: 2 completed, 3 pending

  Completed:
    [OK] Extract JWT logic into a separate module
    [OK] Write unit tests for the new JWT module

  Pending:
    [0] Update the login endpoint to use the new JWT module
    [1] Update the token refresh endpoint
    [2] Run the full test suite and fix regressions

  Resume this todo list? [Y/n]: Y

Resuming Todo List #17. Executing next pending task...

The crash recovery pairs with the automatic context handover. If a handover occurs mid-todo-list, the handover document records which tasks are done and which remain. The next session receives both the handover document (as a briefing) and the todo list (as a structured plan), and can resume seamlessly.

Nested Todo Lists

Subagents dispatched by ExecuteNextTask can create their own todo lists for complex subtasks. This allows recursive decomposition of work:

Nested todo list structure
Orchestrator (Depth 0)
Todo List #42: "Migrate auth from SQLite to PostgreSQL"
  [0] Create PostgreSQL adapter            <-- dispatched to Subagent A
  [1] Update all callers                   <-- dispatched to Subagent B
  [2] Run tests and fix regressions         <-- dispatched to Subagent C

    Subagent A (Depth 1) . working on "Create PostgreSQL adapter"
    Todo List #43: "PostgreSQL adapter implementation"
      [0] Write the adapter class
      [1] Add connection pooling
      [2] Write adapter unit tests             <-- dispatched to Subagent A1

        Subagent A1 (Depth 2) . working on "Write adapter unit tests"
        Todo List #44: "Adapter test coverage"
          [0] Test connection lifecycle
          [1] Test query execution
          [2] Test error handling

            Depth 3 . MAX DEPTH. No further subagents or todo lists allowed.
3

Maximum nesting depth. At depth 3, subagent dispatch and todo list creation are blocked.

Effort

The effort level (/effort) controls max subagent depth, which also limits nesting. Zen (level 1) still lets subagents create todo lists .; they just cannot nest them deeper. The agent remains fully capable of multi-step planning and execution, just in a linear order.

Persist

Nested todo lists are independent database records. If a parent task fails, its nested todo lists survive and can be resumed.

Nested todo lists are transparent to the orchestrator. The orchestrator only sees its own tasks. When ExecuteNextTask dispatches a subagent, the subagent manages its own plan internally. The orchestrator simply waits for the subagent to finish. If the subagent creates a nested todo list, that list is automatically deleted when all its tasks complete .; just like the parent list.

Auto-Deletion

When all tasks in a todo list are completed, the todo list is automatically deleted from the database. This keeps the database clean and prevents stale todo lists from accumulating.

What triggers auto-deletion

  • ExecuteNextTask completes the last pending task → list is deleted
  • MarkTaskComplete is called on the last incomplete task → list is deleted
  • Lists with failed or cancelled tasks are not auto-deleted. They remain in the database for inspection and manual cleanup.

Handover Integration

The todo list system works hand-in-hand with RaggieCode's automatic context handover. When a handover occurs mid-todo-list, the active todo list is preserved and the next session can resume it.

How they work together

1

Todo list is mid-execution

The agent is partway through a todo list. Some tasks are completed, some are pending. The todo list is in the database with status in_progress.

2

Context window fills up, handover triggers

The agent generates a handover document. The document includes the todo list ID, which tasks are completed, and which task to execute next. The todo list itself stays in the database .; untouched.

3

New session starts with handover document

The fresh session receives the handover as part of its system prompt. The document says: "You were working on Todo List #42. Tasks 0 and 1 are done. Execute task 2 next."

4

Agent calls GetActiveTodoList, finds the existing list

As part of its startup routine, the agent checks for incomplete todo lists. It finds #42, sees that it matches the handover document, and offers to resume. The user confirms, and ExecuteNextTask picks up where it left off.

What the handover document records about todo lists

When a handover occurs during todo list execution, the handover document captures:

  • The todo list ID so the next session can find it in the database
  • Which tasks have been completed and what they produced (files changed, tests written)
  • Which task to execute next (the exact_next_step field)
  • Any decisions made during the completed tasks that the next task's subagent needs to know

For a deeper dive into the handover mechanism, including the full handover document schema and trigger conditions, see the Agent Handover documentation.

Task Lifecycle

Every task transitions through a fixed set of states. Understanding these states helps you interpret what the agent is doing and diagnose issues.

pending in_progress completed
in_progress failed
pending cancelled
Status Meaning How it is set
pending Task has not been executed yet. It is waiting in the queue. Set automatically when AddTask is called
in_progress A subagent is currently working on this task. Only one task is in_progress at a time. Set automatically when ExecuteNextTask picks up the task
completed The subagent finished successfully. The task's changes are committed. Set automatically when the subagent returns successfully; or manually via MarkTaskComplete
failed The subagent encountered an unrecoverable error. The task cannot be completed as-is. Set automatically when the subagent crashes; or manually via MarkTaskFailed
cancelled The task is no longer needed and was intentionally skipped. Different from failed. Set manually via MarkTaskCancelled

Manual status management

Three tools let you manually adjust task status outside the normal ExecuteNextTask flow:

MarkTaskComplete

Use when a task was finished outside the normal flow, or to correct an incorrectly-failed task.

MarkTaskFailed

Use when a task hit an unrecoverable error and cannot be retried.

MarkTaskCancelled

Use when a task is no longer needed. Distinct from failed: cancelled means intentionally skipped.