remote-control: routine sessions are never sent end_session on completion, and when it is sent the harness exits non-zero

Status Open
Reported on v2.1.247
Maintainer reply None cached
Activity 0 comments · opened Sep 11, 2026

Summary

Every firing of a scheduled routine on a claude remote-control bridge spawns a local claude --print --resume=<cse_…> child. When the run completes, nothing ends it. The process stays resident indefinitely, holding a concurrent-session slot. After 10 days I had 14 of them: ~1.9 GB RSS combined, oldest 10 days old, all finished hours or days earlier. Once capacity fills, the next firing cannot spawn and a scheduled job silently stops running, which for something built to run unattended means it quietly stops happening.

The teardown mechanism exists. Archiving the session delivers a control_request/end_session and the process exits within seconds. It is simply never triggered by run completion. And when it is triggered, the harness exits non-zero, so the successful run gets logged as failed and displayed as cancelled. There is no supported cleanup either: remote-control exposes no idle/TTL/reap option, and claude stop|rm|respawn operate on the cli_bg_* background-jobs registry rather than bridge sessions, leaving kill as the only recourse.

This is the fourth distinct spawner with the same lifecycle gap: Desktop scheduled tasks (#72308), Windows headless runs (#68626), agent-view sessions (#73631), and now the remote-control bridge. Something creates a session and nothing owns ending it.

Request

  1. Send end_session when a routine run completes, at least for persist_session: false.
  2. Make that path exit 0 so it records as completed.
  3. Have the client read the run's own status rather than deriving it from session archived-state (see Defect 3).

Environment

Claude Code 2.1.247, macOS (Apple Silicon), Claude Desktop app. claude remote-control with --spawn=same-dir. Cloud routines (/v1/code/triggers) targeting a kind: bridge environment, so runs execute on the local machine.

Defect 1: completion never sends end_session

Condensed run logs from the same bridge environment:

  • Session archived by hand: (… skipped: … control_request/end_session ×1 …)
  • Routine run left alone: (… skipped: rate_limit_event ×9, system/hook_* ×3), no end_session

The second reported result: success is_error=false turns=51 duration=720s and was still resident 18 hours later.

Control: the same routine fired twice, six minutes apart. The archived one exited. The other completed at 01:18:02 and was still alive and idle 20 minutes later, when I killed it manually.

Defect 2: end_session exits non-zero

The bridge logs Session failed: Process exited with error, identical to what a SIGTERM produces. Three for three across separate trials.

The bridge distinguishes completed exit_code=0 from failed exit_code=<n>, and the designed shutdown path lands in failed. There appears to be no way to make a bridge session exit 0 at all.

Defect 3: archiving makes a succeeded run display as cancelled

| Source | Before archive | After archive |
|---|---|---|
| Routines UI | succeeded | cancelled |
| API last_run.status | SUCCEEDED | SUCCEEDED |
| Bridge terminal | (nothing) | Session failed: Process exited with error |

list_runs separately reports the session as status: archived. The client appears to derive the displayed run status from that, rather than from the run's own status.

Not caused by Defect 2: SIGTERM produces the same bridge log line but leaves the run showing succeeded, with the session marked disconnected rather than archived. Thirteen sessions killed that way left their routine's history reading 10/10 succeeded.

So the only supported way to end a leaked session is the one that misreports it, and killing the process is what preserves the record.

Reproduction

  1. Run claude remote-control, then create a routine on that bridge environment with a trivial prompt.
  2. Fire it. A claude --print --resume=… child of the bridge appears.
  3. The run reports success. The process does not exit, and no end_session appears in its run log.
  4. Archive the session. It exits, the bridge logs Session failed: Process exited with error, and the run flips to cancelled in the UI while the API still reports succeeded.

Related

  • #54626: closed COMPLETED as the canonical fix. The behaviour persists on 2.1.247.
  • #74682: the same ask from the Desktop side. This report adds that end_session already exists and works, and is simply not wired to run completion.
  • #83718 / #73900: archive is documented to stop the session's process. Here it does, but via a non-zero exit (Defect 2).

View original on GitHub ↗