ββββββββββ ββββββββββ ββββββββ βββ ββββββββ
βββββββββββ βββββββββββββββββββ βββ ββββββββ
βββ βββ ββββββ βββββββββ ββββββββ βββ
βββ βββ ββββββ βββββββββ ββββββββ \
βββββββββββββββββββββββββββββββββββ ββββββββ \ β±ββββ²
βββββββββββββββββββββββββ ββββββββ ββββββββ β²__β± β β β²
βββββββ ββββββ βββ ββββββββ(ββββββββ) β β½ β
βββββββββββββββββββ ββββββββ(ββββββββ) β²ββββ±
βββ ββββββββββββββ ββββββ (ββββββββ) β± β²
βββ ββββββββββββββ ββββββ (ββββββββ) β± β β β²
βββββββββββ βββββββββββββββββββ(ββββββββ) β± β β β²
βββββββ βββ βββββββββββββββββββ(ββββββββ)
give your agent a VPS v0.1
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
sdale connect edge
sdale exec edge "docker build -t app ."
sdale watch edge
sdale push edge .env /srv/.env
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
python 3.10+ Β· zero dependencies Β· dale! π΄
Give your AI agent SSH access to a disposable VPS β and capture structured behavioral data about every interaction. Clidesdale is both an operations tool and a research instrument: it lets agents build, test, and deploy on real infrastructure while producing a complete JSONL audit trail of what they did, when, and under what constraints.
AI agents in sandboxed containers (like clide) can't run Docker, bind ports, or test infrastructure. Clidesdale gives them a real VPS to work with β and turns every SSH session into a data collection opportunity.
Every sdale command produces structured event data: what the agent ran, the exit code, which operator initiated it, the operating mode at the time, and the full output. The SSH boundary is a natural observation point β all agent-infrastructure interaction passes through it, making the data complete by construction.
βββββββββββββββββ SSH (ed25519) ββββββββββββββββββββ
β agent β ββββββββββββββββββββ> β dale (VPS) β
β (sandboxed) β β β
β β sdale exec ββββββββ> β docker build β
β write code β sdale push ββββββββ> β docker run β
β unit tests β sdale sync ββββββββ> β deploy β
β git β <ββββ results ββββββ β break stuff β
βββββββββββββββββ ββββββββββββββββββββ
β β² β
β β structured JSONL β
β β + activity logs β
β β β
βββββββββ sdale watch / clidestable ββββββ
human watches in real time
The SSH boundary is the observation point. Everything crossing it β commands, file transfers, mode transitions β is logged as structured events. The VPS is disposable; the data is not.
Clidesdale produces two complementary data streams for every dale.
Every sdale exec and sdale run appends commands and their output to a per-dale activity file on the remote host:
/opt/stacks/.sdale-<dale-name>.log
Watch in real time with sdale watch <dale> or from the clidestable dashboard.
Every interaction is also recorded as a structured event at:
~/.sdale/logs/<dale>/events.jsonl
Each line is a JSON object following the clide session event schema v1:
{"event":"dale_exec","ts":"2026-03-15T04:30:12Z","session_id":"sdale-edge-1710473400","schema_version":1,"dale":"edge","operator":"amber","command":"docker build -t app .","exit_code":"0"}
{"event":"dale_push","ts":"2026-03-15T04:31:02Z","session_id":"sdale-edge-1710473400","schema_version":1,"dale":"edge","operator":"amber","src":".env","dst":"/srv/app/.env"}
{"event":"dale_mode","ts":"2026-03-15T04:35:00Z","session_id":"sdale-edge-1710473400","schema_version":1,"dale":"edge","operator":"amber","mode":"supervised"}Fields captured per event:
| Field | Description |
|---|---|
event |
Event type (dale_exec, dale_run, dale_push, dale_connect, dale_mode, ...) |
ts |
UTC timestamp (ISO 8601) |
session_id |
Unique session identifier (sdale-<dale>-<epoch>) |
schema_version |
Schema version (currently 1) |
dale |
Target dale name |
operator |
Who initiated the action (detected from $CLIDE_OPERATOR or tmux window name) |
command |
The command string (for exec/run events) |
exit_code |
Process exit code (for exec events) |
mode |
Operating mode at time of event |
Secret scrubbing is automatic β values from known secret environment variables (ANTHROPIC_API_KEY, GH_TOKEN, GITHUB_TOKEN, etc.) are replaced with [REDACTED:<VAR_NAME>] before any event is written to disk.
Clidesdale supports three operating modes per dale, creating natural experimental conditions for studying agent behavior under different autonomy levels:
| Mode | Behavior | Research lens |
|---|---|---|
unrestricted |
Full shell access, no staging | Agent has complete autonomy β baseline capability measurement |
supervised |
Draft/approve cycle for mutations | Human-in-the-loop β how does oversight change agent strategy? |
locked |
Read-only, no execution | Observation only β what does the agent attempt when it cannot act? |
Modes can be set manually or auto-detected based on the owner's presence:
sdale mode edge # show current mode
sdale mode edge supervised # set explicitly
sdale mode edge auto # auto-detect from owner presenceAuto-detection logic: owner attached to tmux = unrestricted, owner on Tailscale but detached = supervised, owner offline = locked. Mode transitions are logged as dale_mode events in the JSONL audit trail.
pip install .
# or run directly:
python -m sdalePython 3.10+. Zero external dependencies β stdlib only.
Any cheap VPS works. Install Docker and tmux:
apt-get update && apt-get install -y docker.io tmuxssh-keygen -t ed25519 -f ~/.ssh/sdale -N "" -C "agent-sdale"
ssh-copy-id -i ~/.ssh/sdale.pub deploy@vps-ip{
"dales": {
"edge": {
"host": "203.0.113.10",
"user": "deploy",
"key": "~/.ssh/sdale",
"session": "build",
"mode": "supervised"
}
},
"defaults": {
"key": "~/.ssh/sdale",
"exclude": ["node_modules", ".git"]
}
}See sdale.example.json for the full format.
sdale connect edge # tmux session + activity log
sdale exec edge "docker build -t app ." # run command, log everything
sdale run -w edge "make deploy" # via tmux, wait for result
sdale push edge .env /srv/app/.env # push a file
sdale sync edge ./my-project /srv/app # rsync code
sdale watch edge # watch activity in real time
sdale log edge # view structured audit log| Command | Description |
|---|---|
sdale connect <dale> |
Create/reuse tmux session, set up activity log |
sdale watch <dale> |
Tail agent activity in real time |
sdale exec <dale> "<cmd>" |
Run command via direct SSH (logged) |
sdale exec -e <dale> "<cmd>" |
Same, merging stderr into stdout |
sdale multi <dale> "c1" "c2" |
Multiple commands in one SSH round-trip |
sdale cat <dale> <path> [path...] |
Read remote files |
sdale health <dale> |
Connectivity + system status check |
sdale health -d <dale> |
Include Docker container listing |
sdale push <dale> <src> <dst> |
Copy file to the dale (scp) |
sdale pull <dale> <remote> [local] |
Copy file from the dale |
sdale run <dale> "<cmd>" |
Send command to tmux session |
sdale run -w <dale> "<cmd>" |
Send via tmux + wait + print output |
sdale output <dale> [-n N] |
Capture recent tmux pane output |
sdale sync <dale> <src> [dst] |
Rsync local directory to dale |
sdale status [dale] |
Show dale status (or list all) |
sdale list |
List configured dales |
sdale log <dale> [--full|--since DUR] |
Show structured event log |
sdale mode <dale> [mode] |
Get or set operating mode |
sdale disconnect <dale> |
Kill the tmux session |
- Everything is logged β commands, output, file transfers, mode changes. Human-readable activity logs on the dale, structured JSONL locally.
- Rsync, don't clone β code lives in the agent's sandbox. Sync to the VPS for builds. Single source of truth.
- The VPS is disposable β if the agent bricks it, reprovision. The data persists locally.
- SSH key per agent β each agent gets its own ed25519 key pair. Revoke by removing the pubkey.
Clidesdale is part of the CLIDE ecosystem. The JSONL event data it produces feeds into the broader session event pipeline alongside container-level telemetry from clide itself.
| Project | What |
|---|---|
| clide | CLI Development Environment β sandboxed terminal for AI agents |
| clidesdale | SSH access to remote VPSes + structured behavioral logging |
| clidestable | VPS-side server β dashboard, stall management, split terminal view |
clidesdale = clide's dale. A horse (Clydesdale -> clidesdale). Also Spanish for "dale!" β go for it! Because that's what you're telling your agent: here's a VPS, dale. π΄