Let me be honest about my Linux level first, because this whole article depends on it.
I live in my IDE. These days, an agentic desktop. I write prompts, I review diffs, I ship PRs. I almost never SSH into a server, and when I do, my knowledge stops at apt update, docker compose up, and restarting nginx when it sulks. Anything past that (ufw rules, PostgreSQL allow-lists, Caddy configs) lived in a notes file. Every server task meant opening that file and copy-pasting commands one by one.
Last month, I set up a brand-new VPS from scratch using Pi. It runs system updates, Docker, firewall, app deployment, and HTTPS with my domain in six lines of code.
Here’s the setup, the exact commands it ran, and the one lesson I learned the hard way: an agentic harness is only as safe as the model you plug into it. Your model choice decides whether this saves you an hour or locks you out of your own server.
What is Pi?
Pi is a minimal, open-source agentic harness: a terminal program that wraps a language model with the tools it needs to read files, edit code, and run shell commands similar to any existing AI terminal like Claude Code or OpenCode. The difference is that SSH extension routes those shell commands to a remote server instead of your local machine, so you can administer a VPS in plain language while reviewing each command before it runs.
“Agentic harness” sounds like jargon, but here’s the idea. The model is the brain; the harness is the body you strap it into. Claude Code, OpenCode, Codex CLI, and Pi are all harnesses. Pi’s whole pitch (their tagline is literally “there are many agent harnesses, but this one is yours”) is that it ships deliberately tiny. No plan mode, no sub-agents, no permission popups. Anything extra, you add as a TypeScript extension or install as a package.
SSH support is exactly that kind of package. The one I use, pi-ssh-tools, adds a /ssh command plus a separate remote toolset (ssh_read, ssh_write, ssh_edit, ssh_bash), while your local tools stay local. SSH mode is off by default, doesn't persist across sessions, and injects the active remote host into the system prompt so the agent knows where it's working. Kind of elegant, honestly.
For someone like me, the value isn’t typing speed. It’s that the harness plus a good model knows the commands I don’t. I know what I want. I never remember whether that’s ufw allow or ufw enable, or which order they go in. Turns out the order matters a lot. More on that in a minute, because getting it wrong nearly cost me SSH access to my own box.
Setting Up Pi With the SSH Extension
You need three things. Pi installed locally, the SSH extension in your extensions folder, and key-based SSH access to your VPS. The extension just shells out to your system ssh, so if ssh root@your-ip works from your terminal, it works from Pi too.
Step 1: Install Pi
One line:
npm install -g @earendil-works/pi-coding-agent
Step 2: Install the SSH extension
Also, one line, using Pi’s own package manager:
pi install npm:@ogulcancelik/pi-ssh-tools
That’s it. No cloning example files, no editing config by hand. The package declares its extension in a manifest, and Pi loads it automatically. (Standard caveat from Pi’s own package page: extensions can execute code and steer the agent, so glance at the source of any third-party package before installing. This one is 20 KB with zero dependencies, so the glance is quick.)
Step 3: Configure your model (this is the important one)
I run DeepSeek as my primary model on Pi. And here’s where I’ll save you an afternoon: use the pro model, not flash.
Why? You don’t need a frontier model to crunch terminals; a good enough model is enough. I don’t want to pay Claude Token or GPT for doing terminal commands. Maybe I should try a local model too.
Step 4: Connect
Start Pi, then:
/ssh <your-vps-ip>
Or just /ssh with no arguments, and it offers you the hosts from your ~/.ssh/config. /ssh status shows where you're connected, /ssh off drops back to local. SSH mode never persists across sessions, which I like: you can't accidentally reopen Pi tomorrow and start editing a production server because you forgot you were still attached to it.
While SSH mode is on, everything the agent proposes runs on the remote box. Not your laptop. Which is exactly why the safety section below exists.
Provisioning a Fresh VPS With One Prompt
I’d just bought a new VPS for my apps. Old me would’ve opened the notes file. Instead, I opened Pi, ran /ssh, and sent this simple prompt:
update and upgrade
install docker, fzf
set ufw for port 8080 and 5173 only
clone this repo <github-link>
docker build this app
setup caddy and use this domain https://ekky.dev (use api for api)
Six lines. Zero syntax. Basically how I’d brief a colleague who actually knows Linux.
The command chain Pi generated
Here’s what the agent proposed and ran, grouped the way it worked through my prompt.
System update:
apt-get update && apt-get upgrade -y
Docker and fzf:
curl -fsSL https://get.docker.com | sh
apt-get install -y fzf
systemctl enable --now docker
Firewall. The step I watched like a hawk:
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 8080/tcp
ufw allow 5173/tcp
ufw --force enable
Look at the third line. ufw allow OpenSSH (similar to 22/tcp), before enabling the firewall. I never asked for that. My prompt literally said "port 8080 and 5173 only," and taken at face value, that instruction locks out SSH. Meaning it locks me out and the agent itself, mid-session. The pro model added the SSH rule on its own and explained why.
That one line is the difference between “AI-assisted server admin” and spending your evening in a rescue console rebuilding a VPS.
Clone and build:
git clone https://github.com/<user>/<repo>.git /opt/app
cd /opt/app
docker build -t app .
docker run -d --name app --restart unless-stopped -p 8080:8080 app
Caddy with my domain:
apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt-get update && apt-get install -y caddy
Then it wrote /etc/caddy/Caddyfile:
api.ekky.dev {
reverse_proxy localhost:8080
}
ekky.dev {
reverse_proxy localhost:5173
}
And reloaded with systemctl reload caddy. Caddy grabbed the TLS certificate by itself, which is the entire reason I asked for Caddy and not nginx. My nginx-plus-certbot notes are two screens long. This is four lines.
End state: patched system, running container, firewall with exactly the holes I asked for (plus the SSH hole I forgot to ask for), and HTTPS on my domain. From a completely bare server. I just sat there approving things.
My Ask-to-Verify Workflow
I’m not going to pretend this is safe out of the box. It isn’t. Pi has no built-in guardrails. Whatever the model proposes, Pi will run. There’s no “are you sure?” layer unless you build one yourself, and the pi-mono docs openly suggest containerizing or sandboxing Pi if you want harder boundaries.
So my mitigation is a habit, not a config:
- I read every command before it executes. Not skim. Read. My Linux is basic, but I can spot a destination path, a
-yflag, and anything containingrm,dd, or a redirect into a file I care about. When I don't recognize a command at all, I just ask Pi to explain it first. Costs one message, and explaining commands is the thing these models are genuinely great at. - My hand stays near
Esc. Pressing it aborts execution immediately, even mid-chain. During anything touching the firewall or disk, my left hand doesn't leave that corner of the keyboard.Ctrl+Cquits the session entirely if things get weird. - Firewall and database steps get double attention. These are the two places where a wrong command doesn’t fail loudly. It succeeds quietly, at the wrong thing.
- Rebuildable servers only. Everything I let Pi touch can be recreated from a repo and a Docker build in an afternoon. I’ve never pointed this at a box holding data I can’t lose. I don’t plan to start.
Across sessions on the pro model, I’ve never seen it do anything harmful. But notice the phrasing. “Never seen” is not “never will.” The risk doesn’t disappear; you just make sure you’re in the loop for the moments that count.
What This Actually Saves
My old routine for a new VPS went like this. SSH in manually. Open the notes file. Copy-paste maybe twenty commands one at a time. Google the two that error out because a package name changed since last year. Fix the typo that’s been in my own notes for months. Forget the ufw SSH rule once (ask me how I know). Lose most of an hour.
With Pi: one prompt, ~10 minutes of watching and approving, done. The DeepSeek pro tokens for the whole provisioning run came to the actual cost, likely $0.03 (or even less).
Honestly though, the bigger saving is psychological. I used to postpone small server chores, like tightening a firewall rule or adding an IP to a PostgreSQL allow-list, because each one meant twenty minutes of re-learning something I’d already learned twice before. Now a server task costs one sentence. So I just do them when I think of them. My servers are in better shape than they’ve ever been, and I know less Linux than most people maintaining servers this tidy. Make of that what you will.
Who Should Do This (and Who Really Shouldn’t)
You’ll like this if: you’re a developer who touches a personal VPS a few times a month, you know enough Linux to sanity-check a command but not enough to write it from memory, and your apps can be rebuilt from a repo. If your notes file has been your sysadmin, this replaces it with something that talks back.
Stay away if: it’s production infrastructure, the server holds customer data, there’s compliance involved, or you can’t afford to rebuild the box this afternoon. Also, stay away if your plan is to run it unattended. Pi will cheerfully execute a destructive command while you’re off making coffee. The human in this loop is not decorative. The human is the loop.
If you found this article, don’t forget to follow me on Medium or Substack for future posts on practical AI, Python programming, and any tech-related content. If you need an AI-native engineer to help build your product, I offer development services as well. Let’s have a talk or email me at me@ekky.dev.
Top comments (0)