Skip to content

resume --headless drops agent output #399

Description

@seniorquico

System Information

ralph-tui: 0.12.0
runtime: bun 1.3.14
os: win32 10.0.26200 (x64)
agent: opencode v1.18.5
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


Also reproduced on Linux (same version, same agent).

Steps to reproduce

  1. Start a headless run against a beads epic:
    ralph-tui run --headless --epic <epic-id>
  2. Note that stdout carries a live progress log, including streamed agent output under [AGENT].
  3. Interrupt the process before the epic finishes (or let it exit early).
  4. Resume the same session headless:
    ralph-tui resume --headless

Expected: the same structured log stream as run --headless — timestamped
[level] [component] lines, with agent output streamed as the iteration progresses.

Actual: two plain lines per iteration and nothing in between. With iterations
that take many minutes, stdout is completely silent for the whole iteration, which
is indistinguishable from a hang. I waited 10+ minutes on two separate machines
before concluding the process was stuck; but it wasn't.

This is a straight divergence between the two headless implementations rather than
a config problem:

  • run --headless (src/commands/run.tsx:3170) builds a createStructuredLogger()
    and handles agent:output (line 3271), streaming every stdout/stderr chunk.
    It also handles engine:warning, iteration:retrying, iteration:skipped,
    task:selected, task:activated, and task:completed.
  • resume --headless (src/commands/resume.tsx:485) uses bare console.log and
    handles only eight events: engine:started, iteration:started,
    iteration:completed, iteration:failed, engine:paused, engine:resumed,
    engine:stopped, all:complete. There is no agent:output case at all.

The engine still emits agent:output (src/engine/index.ts:1182) — resume just
never subscribes to it.

Two consequences beyond the missing output:

  • Retries, skips, and engine warnings are invisible on a resumed session.
  • resume doesn't track task:activated / task:completed, so activeTaskIds in
    .ralph-tui/session.json isn't maintained the way run maintains it.

Relevant logs / terminal output

`resume --headless`, ~10 minutes of real work, entire stdout:


Resuming Ralph TUI session...

Session:    a3c96cf6...
Agent:      opencode
Tracker:    beads
Progress:   3/95 tasks complete
Iteration:  8


Resumed Ralph. Total tasks: 17

--- Iteration 1: Make Fixture::reset() provably isolate cases before generating any ---
Iteration 1 completed. Task in progress. Duration: 624s

--- Iteration 2: Make Fixture::reset() provably isolate cases before generating any ---


The `Duration: 624s` line is the proof the process was healthy: a single iteration
legitimately took 10.4 minutes, and it emitted nothing at all while running.

For contrast, `run --headless` on the same repo produces a continuous
`[timestamp] [INFO] [agent] ...` stream throughout each iteration.

Configuration (if relevant)

Not config-related — reproduced with the global config only, no project
`config.toml`, on both Windows and Linux.

Additional context

  • Not agent-specific. The gap is in the command's event subscription, so any agent
    is affected.
  • Practical impact: any supervisor that shells out to resume --headless (CI, a
    scheduler) has no way to tell a slow iteration from a wedged one. That's
    compounded by AgentPlugin.defaultTimeout being 0 — no timeout — by default
    (src/plugins/agents/base.ts:366), so there's no upper bound to fall back on
    either.
  • Workaround until fixed: ignore stdout and poll liveness out of band (check the
    agent process, or .ralph-tui/session.json mtime). Per-iteration logs in
    .ralph-tui/iterations/ are only written after the iteration ends
    (src/logs/persistence.ts:795), so they don't help mid-iteration.
  • Suggested fix: have both commands share one headless event handler instead of
    maintaining two, so this can't drift again. Happy to open a PR.

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