Skip to content

Can't resume an in_progress beads task, stalls with no_tasks #398

Description

@seniorquico

System Information

ralph-tui: 0.12.0
runtime: bun 1.3.14
os: win32 10.0.26200 (x64)
agent: opencode v1.17.15
tracker: beads
global-config: yes
project-config: no
templates: beads-bv.hbs, beads-rust-bv.hbs, beads-rust.hbs, beads.hbs, default.hbs, jira.hbs, json.hbs
bundled-skills: 4
skills-installed: claude:0, opencode:0, droid:0, gemini:0, codex:0, kiro:0, cursor:0, github-copilot:0, kimi:0, pi:0

Steps to reproduce

  1. In beads, create an epic with tasks that are strictly ordered — each task blocked by the previous one (bd dep add <task> --blocked-by <prev>), so only one task is ever "ready".
  2. Run headless, scoped to the epic: ralph-tui run --epic <epic> --headless --iterations 50 --serial --agent opencode
  3. Ralph claims the first task (sets it in_progress) and runs iteration 1. The agent does NOT close the task that iteration (any reason — needs another turn, is interrupted, etc.).
  4. Ralph re-queries for the next task and immediately stops with Reason: no_tasks, even though the iteration budget is untouched (stopped at iteration 1 of 50).

Expected: Ralph resumes the in_progress task on the next iteration. The engine even asks for it — getNextAvailableTask() calls getNextTask({ status: ['open', 'in_progress'], … }).

Actual: the task is stranded in_progress. Because bd ready excludes in_progress (and its blocked dependents), the run stops no_tasks and the whole epic stalls until a human manually resets the status (bd update <task> --status open). This isn't specific to strict ordering — any task not closed in a single iteration becomes unresumable; strict blocking just turns it into a full-epic stall instead of a skipped task.

Root cause (source @ commit 8191b80):

  • src/engine/index.tsgetNextAvailableTask() passes status: ['open', 'in_progress'].
  • src/plugins/trackers/builtin/beads/index.tsgetNextTask() builds bd ready --json --limit 10 [--parent …] and IGNORES filter.status. bd ready is defined to exclude in_progress/blocked/deferred, so an in_progress task is never returned.

Relevant logs / terminal output

[session] Session <session-id> created. Agent: opencode, Tracker: beads
[engine]  Ralph started. Total tasks: 5
[progress] Iteration 1/50: Working on proj-1.1 - <task 1 title>
[progress] Iteration 1 finished. Task proj-1.1: in progress. Duration: 49s
[engine]  Ralph stopped. Reason: no_tasks. Iterations: 1, Tasks completed: 0

Configuration (if relevant)

agent = "opencode"
tracker = "beads"
configVersion = "2.1"
maxIterations = 50
autoCommit = true

[agentOptions]
provider = "<provider>"
model = "<model>"
variant = "<variant>"

Additional context

State of the epic right after the claim — the work exists and is loadable, but bd ready (what getNextTask calls) returns nothing:

bd ready --parent proj-1 --json:

[]

bd list --parent proj-1 --json (trimmed):

[
  { "id": "proj-1.1", "title": "Task 1", "status": "in_progress", "parent": "proj-1" },
  { "id": "proj-1.2", "title": "Task 2", "status": "open", "parent": "proj-1",
    "dependencies": [ { "depends_on_id": "proj-1.1", "type": "blocks" } ] },
  { "id": "proj-1.3", "title": "Task 3", "status": "open", "parent": "proj-1",
    "dependencies": [ { "depends_on_id": "proj-1.2", "type": "blocks" } ] },
  { "id": "proj-1.4", "title": "Task 4", "status": "open", "parent": "proj-1",
    "dependencies": [ { "depends_on_id": "proj-1.3", "type": "blocks" } ] },
  { "id": "proj-1.5", "title": "Task 5", "status": "open", "parent": "proj-1",
    "dependencies": [ { "depends_on_id": "proj-1.4", "type": "blocks" } ] }
]

So: proj-1.1 is in_progress (excluded by bd ready), and .2–.5 are blocked by it → bd ready is empty → no_tasks. bd list still shows all of it.

Suggested fix: in the beads adapter's getNextTask, honor the engine's filter.status. When it includes in_progress, surface the claimed task too — e.g. union bd ready with bd list --status in_progress [--parent …] (preferring an in_progress task so the engine resumes it, which matches the engine's existing "prefer in_progress" logic). Manual workaround today: bd update <task> --status open to un-strand it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions