A computer is disposable. Two ceilings decide when one goes away on its own.
| Field | Default | What it means |
|---|---|---|
idleTimeoutSec | 900 (15 minutes) | Destroy after this long with no exec |
maxLifetimeSec | 0 (off) | Destroy this long after creation, whatever the activity |
Both are per-machine and both are disabled by 0.
computer:
idleTimeoutSec: 600
maxLifetimeSec: 7200husk up scratch --idle-timeout 3600"Idle" means no exec. Every exec on the local provider touches lastUsedAt and
rewrites the record; the container providers read State.StartedAt from the engine.
The reaper
ComputerManager.startReaper(intervalMs = 60_000) starts a sweep every 60 seconds. The
interval timer is unref'd, so it never holds a CLI process open, and startReaper is
idempotent.
husk serve starts it. The CLI's one-shot commands do not — a husk exec that also
garbage-collected somebody else's machine would be a surprise.
The sweep asks every provider that implements reap() and ignores the ones that do not.
Docker and Podman also implement reap() now. Idle cleanup runs only while the
owning process has started the reaper, such as husk serve. One-shot commands do
not leave a background scheduler behind; use husk rm for explicit removal.
A reaper failure in one provider is logged at debug and does not stop the others.
Stopping versus destroying
| Command | Filesystem | Recoverable |
|---|---|---|
husk stop <name> | kept | yes, with husk start |
husk rm <name> | gone | no |
A stopped machine still counts against nothing — only running and creating machines
count toward the eight-machine quota — but it still occupies disk.
Session bindings
ComputerManager.ensure(key, spec) maps a stable key onto a machine, so a conversation
keeps one filesystem without the caller tracking ids.
The map lives in ~/.husk/computers/bindings.json, written with write-then-rename. When
a binding points at a machine that no longer exists, it is cleared and a new machine is
created.
MCP uses this: the session key defaults to $HUSK_SESSION, then to the literal mcp,
and the machine is named mcp-<key>. It is created with idleTimeoutSec: 3600 — an hour,
because a conversation has long pauses in it — and destroyed when the client disconnects
unless you pass --keep.
claude mcp add husk-api -- npx -y @husk-ai/mcp --session api --flavor python
claude mcp add husk-web -- npx -y @husk-ai/mcp --session web --flavor nodeTwo keys, two machines, two filesystems, one client.
Shutdown paths
| Trigger | What happens |
|---|---|
husk rm | The machine and its filesystem are destroyed; the binding is cleared |
| MCP client disconnects (stdin closes) | The machine is destroyed unless --keep |
SIGINT / SIGTERM to husk mcp | Same |
Ctrl-C during husk run | The run aborts between steps. The machine is left alone |
| Reaper | Only on local, ssh and fly |
Ctrl-C during a run is deliberately non-destructive. You interrupted the agent, not the machine, and destroying the filesystem you were about to inspect would be the wrong reading of that keystroke.