release: 1.1.0 — daemon mode (--start/--attach/--stop) + network-orphan extras - #39
Merged
Conversation
…an extras THE DAEMON-MODE RELEASE. A sandy session's lifetime is no longer tied to the launching client: start detached, attach/detach clients at will (including from sandy-ui), survive a host reboot, stop explicitly. Additive and backward-compatible: bare `sandy` semantics unchanged, sandbox forward-compat promise holds, introspection schema_version stays 1. Daemon mode (#17): - `--start`: forks a detached supervisor (nohup+disown; portable — no setsid, no `sleep infinity`, both absent/broken on macOS) which owns the workspace lock, the helper processes, and the cleanup trap; the container runs detached with --restart unless-stopped (reboot survival) and no --rm. Returns 0 only once the inner tmux session is attachable; streams the supervisor log; fails fast on a crash-looping container with docker-logs diagnostics. Idempotent; refuses headless (-p would restart-loop). - `--attach`: last-wins concurrent attach (tmux attach -d). Exit codes: 0 = session ended while attached, 3 = clean detach (session lives), 4 = no such session, 5 = attach failed. - `--stop`: signals a live supervisor so its own trap releases the #14 lock; tears down directly (container, networks, stale lock) when the supervisor is gone (reboot case). Exit 0/4/5. - Bare `sandy` over a live daemon session: error-with-hint, exit 1 — keyed off the container label, so a supervisor-less rebooted session is respected, not clobbered. - State = container labels (sandy.daemon/workspace_path/session/started_at/ daemon_pid); container existence is the durable source of truth. - All daemon tmux probes exec as the host uid (-u): the image has no USER directive, so a bare docker exec runs as root and can never see the gosu-dropped user's tmux socket. - Introspection: cli_flags += --start/--attach/--stop; running_containers[] += sandbox (sandboxes[].name join key), daemon (bool), attached_clients (int|null, failure-guarded). Network-orphan extras (#26): - `--prune-orphans`: pre-preflight fast-path maintenance command; exit 0 (incl. "found none") / 1 (docker unreachable). - `orphan_networks` in --print-state (both modes; null when docker absent). - Prune-on-startup on every launch; single source of truth lister (_sandy_orphan_networks_list) shared by reaper, count, and flag — a net is an orphan only if its owner PID is dead AND no container is attached, so live/mid-setup/reboot-resurrected sessions are never touched. Verification: end-to-end acceptance harness (test/acceptance-daemon.sh) green on a real macOS Docker host — including agent-process PID identity across an abruptly killed attach client (in-memory state preserved by construction) — plus 661/661 unit tests and the full integration suite. Fixes #17 Fixes #26 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Squashed release commit for the 1.1.0 daemon-mode milestone (#17 + #26). Closes both on merge.
--start/--attach/--stop, supervisor architecture, container-label state, DEC-A/B/C exit-code contract, introspection additions (schema_version stays 1).--prune-orphans,orphan_networks, prune-on-startup.test/acceptance-daemon.shgreen on real Docker (macOS), 661/661 unit tests, full integration suite.Fast-forward main to this commit after CI, then tag
v1.1.0.🤖 Generated with Claude Code