anthropics / anthropics/claude-code
remote-control: routine sessions are never sent end_session on completion, and when it is sent the harness exits non-zero
- Lenguaje dominante
- Python
- Estrellas
- 145k
- Forks
- 23.1k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
## Summary
Every firing of a scheduled routine on a `claude remote-control` bridge spawns a local `claude --print --resume=` 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=`, 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).
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Línea de trabajo
Start at the `claude remote-control` entry point and reproduce a routine with a trivial prompt, then trace completion through session teardown and run-status reporting. Done means non-persistent sessions receive `end_session`, the shutdown exits 0, and the displayed result remains `completed` or `succeeded` according to the run's own status.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Área
- backend, cli
- Tipo de issue
- Error
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Estado de actividad
- Activo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 38/100