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
Setup:
- bd 1.1.0 with a Dolt-server backend, located via the BEADS_DIR env var.
- The working directory has NO local
.beads/ directory (tracker data is on the
Dolt server, not in the repo/worktree).
- A global ~/.config/ralph-tui/config.toml (below); no project .ralph-tui/config.toml.
- An epic with two open child tasks.
-
From the working directory, confirm bd resolves ready work via BEADS_DIR:
$ bd ready --parent <epic-id> --json
# -> returns both open child tasks (see logs)
-
Run ralph-tui headless, scoped to the epic, from that same directory:
$ ralph-tui run --epic <epic-id> --cwd /path/to/workdir --headless --no-setup --iterations 0 --serial
Expected:
Ralph selects a ready task and runs an iteration (bd shows the tasks as ready from the same cwd/env).
Actual:
Ralph resolves the epic and reports "Total tasks: 2", then immediately stops with reason "no_tasks" and 0 iterations. No task is ever selected.
Root cause (source @ commit 8191b80):
In src/plugins/trackers/builtin/beads/index.ts, getNextTask() starts with if (!(await this.isReady())) return undefined;. isReady() -> detect() requires access(join(this.workingDir, this.beadsDir /* ".beads" */), R_OK), i.e. a local <cwd>/.beads directory. With BEADS_DIR set there is no local .beads/, so detect() returns available:false and getNextTask() returns undefined (with no log). getTasks() and getEpics() do NOT call isReady(), so enumeration works while selection silently yields nothing — hence "Total tasks: 2" followed by "no_tasks". The engine (src/engine/index.ts) emits reason "no_tasks" when getNextTask returns null.
Relevant logs / terminal output
### ralph-tui run (headless):
Epic: <epic-id>
[INFO] [session] Session <session-id> created. Agent: opencode, Tracker: beads
[INFO] [engine] Ralph started. Total tasks: 2
[INFO] [engine] Ralph stopped. Reason: no_tasks. Iterations: 0, Tasks completed: 0
[INFO] [engine] Ralph stopped. Reason: interrupted. Iterations: 0, Tasks completed: 0
Tasks: 0/2 completed
### .ralph-tui/session.json shows both tasks WERE loaded (so the tracker resolved):
"trackerState": {
"plugin": "beads",
"epicId": "<epic-id>",
"totalTasks": 2,
"tasks": [
{ "id": "<epic-id>.1", "title": "…", "status": "open", "completedInSession": false },
{ "id": "<epic-id>.2", "title": "…", "status": "open", "completedInSession": false }
]
}
### For contrast, `bd ready` from the SAME cwd + env returns those tasks:
$ bd ready --parent <epic-id> --json
[
{ "id": "<epic-id>.1", "status": "open", "issue_type": "task", ... },
{ "id": "<epic-id>.2", "status": "open", "issue_type": "task", ... }
]
Configuration (if relevant)
agent = "opencode"
tracker = "beads"
configVersion = "2.1"
maxIterations = 10
autoCommit = true
[agentOptions]
provider = "<provider>"
model = "<model>"
variant = "<variant>"
Additional context
- Inconsistency: getNextTask() gates on isReady(); getTasks()/getEpics() do not. Same tracker, same run — enumeration works, selection doesn't.
- Silent failure: the isReady() false path is an unlogged
return undefined, while the other getNextTask failure branches (non-zero exit, JSON parse error) do log. So the one path that trips a valid config emits no diagnostics.
- Wrong readiness signal:
bd is explicitly designed to locate its tracker outside the cwd via BEADS_DIR (and --db). detect() using filesystem presence of <cwd>/.beads rejects a configuration that bd fully supports.
- The adapter has a
beadsDir config option, but detect() does join(workingDir, beadsDir), so pointing it at an absolute/external path doesn't work.
Suggested fixes (any one):
- In detect(), treat BEADS_DIR / an absolute
beadsDir / a configured --db as sufficient (don't join those with cwd).
- Drop the isReady() gate in getNextTask for parity with getTasks/getEpics (let bd be the source of truth).
Workaround (works today): create an empty <cwd>/.beads/ directory. It satisfies detect() and does NOT shadow the Dolt server — with BEADS_DIR set, bd still uses the server even when an empty local .beads is present.
Why it matters: this blocks using ralph-tui with a shared/remote beads (Dolt) tracker that lives independently of each git repo/worktree — a setup that avoids committing tracker files into repos you don't own.
System Information
Steps to reproduce
Setup:
.beads/directory (tracker data is on theDolt server, not in the repo/worktree).
From the working directory, confirm bd resolves ready work via BEADS_DIR:
Run ralph-tui headless, scoped to the epic, from that same directory:
Expected:
Ralph selects a ready task and runs an iteration (bd shows the tasks as ready from the same cwd/env).
Actual:
Ralph resolves the epic and reports "Total tasks: 2", then immediately stops with reason "no_tasks" and 0 iterations. No task is ever selected.
Root cause (source @ commit 8191b80):
In src/plugins/trackers/builtin/beads/index.ts,
getNextTask()starts withif (!(await this.isReady())) return undefined;.isReady()->detect()requiresaccess(join(this.workingDir, this.beadsDir /* ".beads" */), R_OK), i.e. a local<cwd>/.beadsdirectory. With BEADS_DIR set there is no local.beads/, sodetect()returns available:false andgetNextTask()returns undefined (with no log).getTasks()andgetEpics()do NOT callisReady(), so enumeration works while selection silently yields nothing — hence "Total tasks: 2" followed by "no_tasks". The engine (src/engine/index.ts) emits reason "no_tasks" when getNextTask returns null.Relevant logs / terminal output
Configuration (if relevant)
Additional context
return undefined, while the other getNextTask failure branches (non-zero exit, JSON parse error) do log. So the one path that trips a valid config emits no diagnostics.bdis explicitly designed to locate its tracker outside the cwd via BEADS_DIR (and --db). detect() using filesystem presence of<cwd>/.beadsrejects a configuration thatbdfully supports.beadsDirconfig option, but detect() doesjoin(workingDir, beadsDir), so pointing it at an absolute/external path doesn't work.Suggested fixes (any one):
beadsDir/ a configured --db as sufficient (don't join those with cwd).Workaround (works today): create an empty
<cwd>/.beads/directory. It satisfies detect() and does NOT shadow the Dolt server — with BEADS_DIR set, bd still uses the server even when an empty local .beads is present.Why it matters: this blocks using ralph-tui with a shared/remote beads (Dolt) tracker that lives independently of each git repo/worktree — a setup that avoids committing tracker files into repos you don't own.