Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 42 additions & 13 deletions docker/runtime/supervisor.sh
Original file line number Diff line number Diff line change
@@ -1,27 +1,56 @@
#!/bin/bash
# Container supervisor — PID 1.
#
# Keeps the container alive while agent sessions run via `docker exec`.
# Forwards SIGTERM and SIGINT so `docker stop` / `docker kill` terminate
# cleanly without a 10-second timeout.
# Exits 0 when the last tmux session ends so host-side cleanup fires
# automatically — no manual `jackin eject` needed. Exits 1 if no session
# appears within the startup grace period so diagnose_premature_exit can
# surface the container logs.
#
# Interim placeholder: this script will be replaced by the `jackin-container`
# Rust binary (see reference/roadmap/jackin-container-binary) which adds
# last-session detection via inotify and a Unix socket status interface.
# The tmux server creates its socket at /tmp/tmux-<uid>/default when the
# first session starts. The grace period watches for the socket file to
# appear; the monitor loop polls via `tmux list-sessions` rather than a
# plain file-existence check so a stale socket (tmux crashed without
# cleanup) doesn't keep the supervisor alive indefinitely.
#
# No `set -e`: `wait` returns the exit code of the child it waited on;
# a signal-killed sleep exits non-zero, and `set -e` would misread that
# as a supervisor failure on every clean `docker stop`.
# Will be removed in Phase 2 when the `jackin-container` Rust binary takes
# over as PID 1 with inotify-based socket watching.
# See reference/roadmap/jackin-container-binary for the full plan.
#
# No `set -e`: signal-killed `wait` exits non-zero; `set -e` would misread
# that as a supervisor failure on every clean `docker stop`.

_cleanup() {
kill "$!" 2>/dev/null || true
exit 0
}
trap '_cleanup' TERM INT

# Wait in a background-sleep loop so the trap fires promptly.
# `|| true` guards against a signal-killed sleep triggering an exit.
while true; do
sleep 3600 &
TMUX_SOCKET="/tmp/tmux-$(id -u)/default"

# Grace period: wait up to 60 s for the first tmux session socket to
# appear. Without this the supervisor exits before `docker exec tmux
# new-session` has a chance to create it.
deadline=$((SECONDS + 60))
while [ $SECONDS -lt $deadline ] && [ ! -S "$TMUX_SOCKET" ]; do
sleep 1 &
wait $! || true
done

# No session appeared — something went wrong at startup. Exit non-zero so
# diagnose_premature_exit surfaces the container logs rather than returning
# a cryptic "container is not running" error.
if [ ! -S "$TMUX_SOCKET" ]; then
echo "supervisor: no tmux socket at ${TMUX_SOCKET} after 60 s; is tmux installed and starting correctly?" >&2
exit 1
fi

# Wait for the last session to end. Poll via `tmux list-sessions` rather
# than a plain socket-file existence check: if tmux crashes or is killed
# without removing the socket, a stale file would keep the supervisor
# alive indefinitely.
while tmux list-sessions &>/dev/null; do
sleep 1 &
wait $! || true
done

exit 0
3 changes: 1 addition & 2 deletions docs/astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ export default defineConfig({
collapsed: true,
items: [
{ label: 'Overview', slug: 'reference/roadmap/agent-orchestrator-research' },
{ label: 'Herdr research', slug: 'reference/roadmap/herdr-research' },
{
label: 'Fleet phase 1 — Foundation gaps',
collapsed: true,
Expand Down Expand Up @@ -286,6 +285,7 @@ export default defineConfig({
collapsed: true,
items: [
{ label: 'Overview', slug: 'reference/roadmap/jackin-daemon' },
{ label: 'jackin-container: in-container multiplexer server', slug: 'reference/roadmap/jackin-container-binary' },
{ label: 'Jackin Desktop Agent Hub', slug: 'reference/roadmap/jackin-desktop-agent-hub' },
{
label: 'Phase 2 — First reactive adapters',
Expand Down Expand Up @@ -334,7 +334,6 @@ export default defineConfig({
items: [
{ label: 'Bollard migration', slug: 'reference/roadmap/bollard-migration' },
{ label: 'Construct user creation', slug: 'reference/roadmap/construct-user-creation' },
{ label: 'jackin-container: in-container supervisor binary', slug: 'reference/roadmap/jackin-container-binary' },
{ label: 'Workspace registry cache', slug: 'reference/roadmap/workspace-registry-cache' },
],
},
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/reference/roadmap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jackin' is a functional proof of concept. **`Claude Code`, `Codex`, `Amp`, `Kimi
- [Workspace Claude token setup](/reference/roadmap/workspace-claude-token-setup/) — shipped token commands are documented in standard docs; roadmap tracks the canonical auth slot, TUI generate action, Apple Keychain backend, validity probe, and bulk migration
- [Config versioning and migration framework](/reference/roadmap/config-versioning-migration/) — shipped per-file schema gates for config, workspace files, and role manifests, plus automatic config/workspace migration, desktop role manifest migration through `jackin role migrate`, and CI migration through `jackin-role migrate`; roadmap tracks deferred `--pr` automation and the Renovate-style auto-migration GitHub Action
- [Console agent session control](/reference/roadmap/console-agent-session-control/) — Phases 1–3 shipped: instance discovery, console Instances panel, `hardline --shell`, tmux-backed primary session (supervisor as PID 1, `tmux new-session -A`), secondary agent sessions via `hardline --new`, and console `a`/`x` keybindings; Phase 4 (agent runtime status + resource panel integration) remains open
- [jackin-container: in-container supervisor binary](/reference/roadmap/jackin-container-binary/) — Phase 1 shipped: improved bash supervisor exits when the last tmux session ends, closing the automatic container teardown gap; Rust binary with inotify, Unix socket status interface, and daemon event streaming remain

## Planned

Expand All @@ -77,7 +78,6 @@ jackin' is a functional proof of concept. **`Claude Code`, `Codex`, `Amp`, `Kimi

### Reactive daemon program

- **[jackin-container: in-container supervisor binary](/reference/roadmap/jackin-container-binary/)** — replace the interim bash supervisor with a Rust binary that acts as PID 1, watches for last-session exit via inotify on the tmux server socket, exits cleanly to trigger host-side cleanup, and exposes a Unix socket interface for session inventory queries; foundation for jackin daemon communication with running containers (status: open — design proposal)
- **[jackin daemon — umbrella](/reference/roadmap/jackin-daemon/)** — introduce the long-running per-operator-user host process jackin will use for reactive features. One umbrella item that decides lifecycle, install method, control socket, security posture, and log redaction once so each reactive feature plugs into one daemon shape. The full list of phase-2/phase-3 reactive adapters lives in the program doc and the sidebar under **Reference → Roadmap → Reactive daemon program** (status: open — design proposal)
- **[Jackin Desktop Agent Hub](/reference/roadmap/jackin-desktop-agent-hub/)** — native macOS menu bar and desktop companion for active Jackin workspaces, isolated agent sessions, PR jump links, and Claude/Codex/Amp account state. Keeps the agent TUIs as the primary agent UI while using the daemon as the shared state/event backend (status: open — design proposal)
- **[Live bidirectional auth sync](/reference/roadmap/live-auth-sync/)** — Phase 2 adapter. Keep host and every running container in lock-step on each auth axis (`gh`, Claude, Codex, Amp, …). Subsumes the launch-time `sync` mode's bidirectional follow-up; reconsiders the `sync` name in the process (status: open — design proposal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ the same problem:
- Docker Sandboxes is the strongest commercial benchmark for **microVM
sandboxing**: per-sandbox VM boundary, private Docker daemon, scoped
workspace sharing, host-side network policy, and credential proxying.
- [Herdr](https://github.com/ogulcancelik/herdr) is the strongest reference for **terminal-multiplexer UX for multi-agent workflows**: four-state agent status (Blocked / Working / Done / Idle) detected with zero configuration via PTY heuristics, workspace-level status roll-up, notification suppression when the operator is already looking, sound escalation as opt-in, and blocking `wait` semantics on a Unix socket API. Its architecture (bare host processes, AGPL-3.0) rules out embedding, but its UX decisions directly inform [agent runtime status](/reference/roadmap/agent-runtime-status/), [agent attention prompts](/reference/roadmap/agent-attention-prompts/), and the daemon socket design. See [Herdr research](/reference/roadmap/herdr-research/) for the full evaluation.
- [Herdr](https://github.com/ogulcancelik/herdr) is the strongest reference for **terminal-multiplexer UX for multi-agent workflows**: four-state agent status (Blocked / Working / Done / Idle) detected with zero configuration via PTY heuristics, workspace-level status roll-up, notification suppression when the operator is already looking, sound escalation as opt-in, and blocking `wait` semantics on a Unix socket API. Its architecture (bare host processes, AGPL-3.0) rules out embedding, but its UX decisions directly inform [agent runtime status](/reference/roadmap/agent-runtime-status/), [agent attention prompts](/reference/roadmap/agent-attention-prompts/), and the daemon socket design. See [jackin-container: in-container multiplexer server](/reference/roadmap/jackin-container-binary/) for the full evaluation and the implementation plan that applies these concepts to Jackin's container model.
- Conductor, Claude devcontainers, Trail of Bits' devcontainer, and private
internal tools remain useful comparison points, but they are not the center
of this program.
Expand Down
Loading
Loading