vessel is a PTY-based runtime for spawning, controlling, and observing interactive terminal agents over a Unix socket.
It is designed for AI orchestrators, test harnesses, and automation systems that need real terminal semantics (not just stdout pipes).
- Is: local control plane for interactive worker processes (
spawn,send,wait,snapshot,events,attach,view). - Is: good for multi-agent workflows, TUI testing, and reproducible terminal automation.
- Is not: container runtime, distributed scheduler, or durable job queue.
- Linux with Unix sockets + PTY support
- Rust 1.85+ (for building from source)
tmux(optional, only forvessel view)
cargo install vessel-pty# 1) Spawn a worker shell
vessel spawn --name demo -- bash
# 2) Send a command (+ Enter)
vessel send demo "echo hello from vessel" -n
# 3) Wait for expected output, then inspect the virtual screen
vessel wait demo --contains "hello from vessel" --timeout 5
vessel snapshot demo
# 4) Clean up (SIGTERM by default; use --force for hard kill)
vessel kill demo --force
# 5) Stop server when done
vessel shutdownAgent = PTY process + transcript ring + virtual screen
Server = owns all agent state, listens on Unix socket
Client = stateless CLI sending JSON requests
View = tmux dashboard; panes run read-only attach streams
Key implications:
snapshotreflects current terminal state (best for assertions).tail/dumpreflect transcript bytes (useful for logs/streaming).- State is in-memory in the server process (no persistence across server restart).
vessel spawn --name worker --label batch --timeout 60 -- bash
vessel list
vessel list --all --format json
vessel kill worker
vessel kill --label batch --force
vessel kill --all --force
vessel signal worker --signal USR1vessel send worker "make test" -n
vessel send-bytes worker 1b5b41 # up arrow
vessel send-keys worker ctrl-c enter
vessel tail worker -f
vessel tail worker --raw
vessel snapshot worker
vessel snapshot worker --raw
vessel dump worker --format jsonlvessel wait worker --contains "READY" --timeout 30
vessel wait worker --stable 200 --contains "$ "
vessel wait worker --exited
vessel assert worker --contains "PASS"
vessel assert worker --not-contains "ERROR"vessel events --output
vessel subscribe --id worker --prefix
vessel subscribe --label batch --format jsonl
vessel attach worker
vessel attach worker --readonly
vessel view
vessel view --mode windows
vessel view --label batchvessel exec -- git status --short
vessel exec --timeout 120 -- cargo testvessel spawn --name rec --record -- bash
vessel send rec "echo hi" -n
vessel recording rec --format pretty
vessel gen-test rec > replay.sh
chmod +x replay.shSpawn dependencies:
# Wait for setup to exit before starting app
vessel spawn --name setup -- ./setup.sh
vessel spawn --name app --after setup -- ./run-app.sh
# Wait for output from another agent before spawning
vessel spawn --name db -- ./start-db.sh
vessel spawn --name api --wait-for db:READY -- ./start-api.shRecommended cleanup for automation:
vessel kill --label batch --forceMany commands support --format text|json|pretty.
text: compact, pipe-friendlyjson: structured envelope ({"<key>": ..., "advice": [...]})pretty: human-oriented terminal output
Example:
vessel list --format json | jq '.agents[] | {id, state, labels}'- Server auto-starts for most regular commands.
eventsandsubscribedo not auto-start (they expect an existing server/session).- Default socket path:
/run/user/$UID/vessel.sock(fallback/tmp/vessel-$UID.sock). - Override with
VESSEL_SOCKETor--socket.
vessel doctorIf you hit stale socket/session issues:
vessel shutdown
tmux kill-session -t vessel 2>/dev/null || trueNotes:
killsends SIGTERM by default; some interactive shells ignore it. Use--forcefor deterministic teardown.- For TUI inspection, prefer
snapshotorattach --readonlyover plaintail.
just build
just testRelevant docs:
AGENTS.md- contributor + agent workflowdocs/testing.md- testing approach and scenarios