Skip to content

fix(terminal): persistent sandbox envs survive between turns#6412

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-485d498c
Apr 9, 2026
Merged

fix(terminal): persistent sandbox envs survive between turns#6412
teknium1 merged 1 commit into
mainfrom
hermes/hermes-485d498c

Conversation

@teknium1

@teknium1 teknium1 commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Salvage of #6370 by @malaiwah (fixes #6369).

_cleanup_task_resources unconditionally called cleanup_vm(task_id) at the end of every run_conversation() turn, tearing down Docker/Daytona/Modal/Singularity containers even when container_persistent: true (the default). This contradicted terminal.lifetime_seconds and caused per-turn loss of /workspace, ~/.config, sub-agent CLI auth state, and all in-sandbox content.

Root cause: an unconditional teardown added in fbd3a2fd (Nov 2025) to fix a Morph backend leak was blanket-applied to all backends. The Morph backend has since been removed; the hook outlived it.

Fix

  • Adds terminal_tool.is_persistent_env(task_id) — returns True when the active env has _persistent=True
  • _cleanup_task_resources now skips cleanup_vm for persistent envs; the idle reaper (_cleanup_inactive_envs) handles them on lifetime_seconds expiry
  • Non-persistent backends still get torn down per-turn (original leak-prevention intent preserved)

36 lines across 2 files. Cherry-picked from @malaiwah's commit with authorship preserved.

`_cleanup_task_resources` was unconditionally calling `cleanup_vm()` at
the end of every `run_conversation` (i.e. every user turn), tearing down
the docker/daytona/modal sandbox container regardless of its
`persistent_filesystem` setting. This contradicted the documented intent
of `terminal.lifetime_seconds` (idle reaper) and `container_persistent`,
and caused per-turn loss of `/workspace`, `~/.config`, agent CLI auth
state, and any other content living inside the sandbox.

The unconditional teardown was introduced in fbd3a2f ("prevent leakage
of morph instances between tasks", 2025-11-04) to plug a Morph backend
leak, two days after `lifetime_seconds` shipped in faecbdd. It was
later refactored into `_cleanup_task_resources` in 70dd3a1 without
changing semantics. Code and docs have disagreed since.

Fix: introduce `terminal_tool.is_persistent_env(task_id)` and skip the
per-turn `cleanup_vm` when the active env is persistent. The idle reaper
(`_cleanup_inactive_envs`) still tears persistent envs down once
`terminal.lifetime_seconds` is exceeded. Non-persistent backends (Morph)
are unchanged — still torn down per turn, preserving the original
leak-prevention intent.
@teknium1 teknium1 merged commit e7d3e9d into main Apr 9, 2026
4 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Persistent terminal sandboxes (docker/daytona/modal) are torn down every turn, contradicting terminal.lifetime_seconds

1 participant