pythond

sshd gives you a shell. pythond gives you Python.

Persistent Python daemon with named sessions. Code in, result out. Variables, connections, and threads survive between calls. Agents send code through WebSocket. Humans attach with a real terminal. Same namespace.

pip install pythond

Python 3.10+. Three commands:

CommandRoleLike
pythonddaemonsshd
pyshsession clientssh
pyctldaemon controlsystemctl

Quick start

# terminal 1
pythond daemon

# terminal 2
pysh new work
pysh run work "x = 42"
pysh run work "x + 1"
# 43

pysh attach work          # human REPL, Ctrl-] to detach

State persists

pysh run work "import sqlite3; db = sqlite3.connect('app.db')"

# ... 100 turns later ...

pysh run work "db.execute('SELECT count(*) FROM users').fetchone()"
# (42,)

The connection never closed. The namespace is the workspace.

Async execution

# fire: thread, shares namespace
pysh fire work "model = train(X, y)"
pysh poll work abc123
# {"cell_id":"abc123", "status":"done", "output":"..."}
pysh run work "model.score(X_test)"       # model is there

# fork: child process (POSIX only), killable, pickles vars back
pysh fork work "results = expensive_search(params)"
pysh int work                              # SIGKILL the fork (POSIX)

Remote

AI agents can't hold SSH sessions open. The local daemon holds the connection the agent can't hold.

# server
pip install pythond
pyctl start --listen 0.0.0.0:7399 --tls --show-token
# prints token and cert fingerprint

# client: self-signed server cert must be pinned before connecting
# copy server ~/.pythond/tls/cert.pem to client as ~/server_cert.pem
pyctl pin ~/server_cert.pem
pythond daemon
pyctl connect work 10.0.0.5:7399 <token> --tls
pysh run work "import platform; platform.node()"
# remote-host-01

mTLS plus token

# client: generate client cert
pyctl cert
# copy client ~/.pythond/tls/cert.pem to server as ~/client_cert.pem

# server: generate server cert, then trust client cert
pyctl cert
# copy server ~/.pythond/tls/cert.pem to client as ~/server_cert.pem
pyctl trust ~/client_cert.pem
pyctl start --listen 0.0.0.0:7399 --tls --show-token
# cert is required and token is still required

# client: pin server cert, then connect (client cert sent automatically)
pyctl pin ~/server_cert.pem
pythond daemon
pyctl connect work 10.0.0.5:7399 <token> --tls
pysh run work "x"

Write file, then exec

Complex code with quotes, f-strings, or SQL? Write a file, load it. No escaping.

cat > /tmp/task.py << 'EOF'
import pandas as pd
df = pd.read_csv("data.csv")
print(f"rows: {len(df)}, cols: {list(df.columns)}")
EOF

pysh run work "exec(open('/tmp/task.py').read())"

Two channels, one namespace

Agent channel (pysh run):       Human channel (pysh attach):
  code in, text out               real PTY, readline, colors
  no ANSI, no parsing             tab completion, Ctrl-C
  WebSocket protocol              Ctrl-] to detach
           \                     /
            same Python namespace

Commands

pysh new <name>              create session
pysh run <name> "code"       sync exec, raw output
pysh fire <name> "code"      async thread, shares namespace (can't kill C code)
pysh fork <name> "code"      async process (POSIX), killable, pickles vars back
pysh poll <name> [cell_id]   check async result
pysh attach <name>           human REPL
pysh int <name>              interrupt (fire=best effort, fork=kill)
pysh kill <name>             terminate session
pysh ls                      list sessions
pysh status <name>           JSON health
pysh vars <name>             JSON namespace names
pysh complete <name> "text"  JSON completion candidates

pyctl start [--listen H:P] [--tls] [--show-token]  start daemon
pyctl stop                           stop daemon
pyctl status                         daemon endpoint metadata and liveness
pyctl connect <name> <h:p> <tok> [--tls]  proxy to remote
pyctl disconnect <name>             drop remote
pyctl cert                           show/generate TLS cert
pyctl trust <cert.pem>              authorize client
pyctl pin <cert.pem>                verify server

pyctl cert prints the certificate path, key path, fingerprint, and role hints: copy this cert to the server for pyctl trust when this machine is a client, or copy it to the client for pyctl pin when this machine is a server.

Protocol

WebSocket text frames. First line = command. After newline = code body. Python code is never JSON-escaped.

ws.send("run work\nprint('hello')")    # "hello"
ws.send("fire work\ntrain(epochs=50)") # {"cell_id":"..."}
ws.send("ls")                          # "  work: alive"

Security

The security model mirrors SSH:

pythondSSH equivalent
token in daemon.jsonprivate key in ~/.ssh/
pyctl trust cert.pemadding a line to authorized_keys
pyctl pin cert.pemadding a line to known_hosts
authenticated clientlogged-in user

Once authenticated, a client has full access to all sessions — no per-session permission isolation. Same as SSH: once you log in, you are that user with all their permissions.

Not a sandbox: code runs with the daemon user's OS permissions.

ModeAuth
Local POSIXAF_UNIX socket, mode 0o600
Local WindowsTCP + token, OWNER RIGHTS DACL (owner-level isolation, comparable to Unix chmod 700)
Remotepinned self-signed TLS cert + token; optional mTLS client cert

Access logs are written as ACCESS lines to runtime access.log and mirrored to daemon stderr for supervisors. They include conn_id, peer, cmd, session, status, and body_bytes; they do not include tokens or Python code bodies.

Interactive pysh run/fire/fork also echoes submitted code, errors, and raw run output to the client terminal's stderr. That is operator feedback, not daemon access logging.

Session names are lowercase only: a-z, 0-9, underscore, and hyphen, up to 80 characters. Windows reserved device names such as CON, NUL, COM1, and LPT1 are rejected.

Like shell history and environment variables under SSH, pythond session history, logs, and live namespaces can expose secrets. history.py and session.log may contain executed Python source and captured output. Do not paste API keys, passwords, tokens, or other secrets into cells unless you are willing for them to persist in that session and its local files.

Platform

PlatformPTYTransport
Linux / macOS / WSLpty.openpty()AF_UNIX WebSocket
WindowspywinptyTCP WebSocket

Dependencies

PackageRole
websocketsprotocol transport
wsprotoraw WSS client framing
cryptographyTLS cert generation and pinning
pywinptyWindows PTY (Windows only)

Source · PyPI · MIT license