Persistent REPL for AI agents. Shared live terminal for humans. bash_tool is curl. k is a socket.
pip install agent-tty
Requires POSIX, Python 3.10+, and tmux 3.0+. Linux, macOS, and WSL are supported; native Windows fails fast.
v0.1.1 · MIT
bash
# start a persistent bash session$ k new work bashOK work# run code, get JSON$ k run -j work "echo hello"{"cell_id": "a1b2c3d4e5f6", "status": "done", "output": "hello"}# state survives across cells$ k run -j work "cd /tmp && export MODE=warm"{"cell_id": "d4e5f6a7b8c9", "status": "done", "output": ""}$ k run -j work "pwd; echo $MODE"{"cell_id": "e7f8a9b0c1d2", "status": "done", "output": "/tmp\nwarm"}
Shared live TTY
The agent is not hidden inside a background task. It works in a real tmux session that a human can watch, interrupt, or take over without losing process state.
agent view
# agent sends a multi-command bash cell$ k fire work "cd app && pytest -q && tail -20 logs/server.log && export FIX_READY=1"{"cell_id": "a1b2c3d4e5f6", "status": "fired"}$ km work a1b2c3d4e5f6 -1{"cell_id": "a1b2c3d4e5f6", "session": "work", "status": "done", "ts": "..."}
human view
# k watch = filtered live view: cell markers, ✓ on done, frame noise hidden$ k watch workwatching work (ctrl-c to stop)
── a1b2c3d4 ──
$ cd app
$ pytest -q
..F
test_api.py::test_health failed
$ tail -20 logs/server.log
missing DATABASE_URL
$ export FIX_READY=1
── ✓ ──# k int interrupts from outside; tmux attach is native raw takeover$ k int workOK$ tmux attach -t work
Why agent-tty
👁️
Human-visible TTY
k watch shows a filtered live log (cell markers, completion ticks, frame noise hidden). tmux attach for raw TTY takeover.
🧠
State survives
Variables, cwd, imports, live connections, SSH sessions, and debugger state stay alive across agent turns.
🔔
Callback completion
km wakes the agent when a long cell finishes. No poll loop when the runtime can monitor stdout.
🔄
JSON cell API
run -j for inline cells, fire/poll for long cells. Structured JSON with cell_id, status, and output.
🎯
Any REPL
bash, python, gdb, redis-cli, ssh — anything with a readline prompt. Three frame detection modes adapt to each.
🛡️
Safe recovery
One cell at a time, timeout recovery hints, k status next actions, and k int Ctrl-C keep sessions recoverable.
Operator loop
k new work bash
+-- create one persistent TTY
+-- cwd, env, imports, sockets, ssh, debuggers stay alive
k run -j work "echo hello"
+-- short cell
+-- returns JSON directly
k fire work "pytest -q && tail -20 logs/server.log"
+-- long cell
+-- returns a cell_id immediately
km work <cell_id> -1
+-- wait once
+-- wake the agent when the cell finishes
k status work
+-- repair the log pipe if needed
+-- print the next useful command
k watch work filtered human view
tmux attach -t work raw human takeover
k int work interrupt without losing the session
km — callback monitor
Persistent TTY state first; callback completion second.
Each stdout line is a JSON event. Any host with background-notification support can consume them directly.
agent orchestration
# poll is a fallback when the runtime cannot monitor stdout$ k poll work# → "running"... call again... "running"... again...# with km: fire a long stateful cell, then wait for its completion event$ k fire work "make build"{"cell_id": "a1b2c3d4e5f6", "status": "fired"}$ km work a1b2c3d4e5f6 -1{"cell_id": "a1b2c3d4e5f6", "session": "work", "status": "done", "ts": "..."}# continuous mode: watch all events across a session$ km work{"status": "fired", ...}{"status": "done", ...}{"status": "notify", "message": "deploy complete", ...}{"status": "fired", ...}{"status": "done", ...}