ββββββββββ ββββββββββ ββββββββ βββ ββββββββ
βββββββββββ βββββββββββββββββββ βββ ββββββββ
βββ βββ ββββββ βββββββββ ββββββββ βββ
βββ βββ ββββββ βββββββββ ββββββββ \
βββββββββββββββββββββββββββββββββββ ββββββββ \ β±ββββ²
βββββββββββββββββββββββββ ββββββββ ββββββββ β²__β± β β β²
βββββββ ββββββ βββ ββββββββ(ββββββββ) β β½ β
βββββββββββββββββββ ββββββββ(ββββββββ) β²ββββ±
βββ ββββββββββββββ ββββββ (ββββββββ) β± β²
βββ ββββββββββββββ ββββββ (ββββββββ) β± β β β²
βββββββββββ βββββββββββββββββββ(ββββββββ) β± β β β²
βββββββ βββ βββββββββββββββββββ(ββββββββ)
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. It builds, tests, deploys, and breaks things β you watch via activity logs. Dale!
AI agents in sandboxed containers (like clide) can't run Docker, bind ports, or test infrastructure. But you don't want to give them the keys to production either.
clidesdale is the middle ground: a throwaway VPS the agent can SSH into and go a little crazy on. You co-pilot via activity logs and shared tmux sessions β observable, interruptible, disposable.
βββββββββββββββββ 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 β
βββββββββββββββββ ββββββββββββββββββββ
β β
β activity logs (.sdale-*.log) β
βββββββββ sdale watch / clidestable ββββββ
human watches in real time
- Everything is logged β
sdale execandsdale runlog all commands + output to activity files. The human cansdale watchor use clidestable to see everything in real time. - Rsync, don't clone β code lives in the agent's sandbox. Sync it to the VPS for builds. Single source of truth.
- The VPS is disposable β if the agent bricks it, reprovision. Keep provisioning scripted and repeatable.
- SSH key per agent β each agent gets its own key pair. Revoke by removing the pubkey.
pip install .
# or run directly:
python -m sdaleRequires Python 3.10+. Zero external dependencies β stdlib only.
Any cheap VPS works. Install Docker and tmux:
apt-get update && apt-get install -y docker.io tmuxOr use a full bootstrap like forge for Docker CE, Tailscale, UFW, and SSH hardening.
On the agent's machine:
ssh-keygen -t ed25519 -f ~/.ssh/sdale -N "" -C "agent-sdale"Add the pubkey to the VPS:
ssh-copy-id -i ~/.ssh/sdale.pub deploy@vps-ip{
"dales": {
"edge": {
"host": "203.0.113.10",
"user": "deploy",
"key": "~/.ssh/sdale",
"session": "build"
}
},
"defaults": {
"key": "~/.ssh/sdale",
"exclude": ["node_modules", ".git"]
}
}See sdale.example.json for the full format.
# Connect to a dale (creates tmux session + activity log)
sdale connect edge
# Run commands directly (captured in activity log)
sdale exec edge "docker build -t app ."
sdale exec edge "docker run --rm app npm test"
# Or via tmux (observable + wait for completion)
sdale run -w edge "make deploy"
# Push a config file
sdale push edge .env /srv/app/.env
# Sync code to the dale
sdale sync edge ./my-project /srv/app
# Watch agent activity in real time
sdale watch edge
# Check status / view audit log
sdale status edge
sdale log edge| Command | Description |
|---|---|
sdale connect <dale> |
Create/reuse tmux session, set up activity log |
sdale watch <dale> |
Watch agent activity in real time (tails activity log) |
sdale exec <dale> "<cmd>" |
Run command via direct SSH (no tmux, good for scripting) |
sdale exec -e <dale> "<cmd>" |
Same, but merge stderr into stdout (avoids 2>&1) |
sdale multi <dale> "c1" "c2" |
Run multiple commands in one SSH round-trip |
sdale cat <dale> <path> [path...] |
Read one or more remote files |
sdale health <dale> |
Quick connectivity + system status check |
sdale health -d <dale> |
Include Docker container listing |
sdale push <dale> <src> <dst> |
Copy a single file to the dale via scp |
sdale pull <dale> <remote> [local] |
Copy a file from the dale to local |
sdale run <dale> "<cmd>" |
Send command to the dale's tmux session (observable) |
sdale run -w <dale> "<cmd>" |
Send via tmux + wait for completion, print output |
sdale output <dale> [-n N] |
Capture recent tmux pane output (default: 20 lines) |
sdale sync <dale> <src> [dst] |
Rsync local directory to the dale |
sdale status [dale] |
Show dale status (or list all) |
sdale list |
List configured dales |
sdale log <dale> [--full|--since DUR] |
Show event log for a dale |
sdale disconnect <dale> |
Kill the tmux session |
sdale exec and sdale run write all commands and output to activity log files on the dale:
/opt/stacks/.sdale-<dale-name>.log
Watch them in real time with sdale watch <dale> or from clidestable's web dashboard.
Every command is also logged as structured JSONL to ~/.sdale/logs/<dale>/events.jsonl, compatible with 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","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","src":".env","dst":"/srv/app/.env"}Secret values (API keys, tokens) are automatically scrubbed before writing.
| Project | What |
|---|---|
| clide | CLI Development Environment β sandboxed terminal for AI agents |
| clidesdale | This CLI β SSH access to remote VPSes for agents |
| clidestable | VPS-side server β dashboard, stall management, split terminal view |
See issues for the full backlog.
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. π΄