Claude Code on a VPS: give your always-on agent a real job
The $5-a-month always-on agent box is now a standard founder setup. The part nobody writes about is what fills its queue. The answer: your customers.
The always-on agent box is now a thing
Somewhere in the last year, “run Claude Code on a VPS” went from a weekend hack to a standard setup. The recipe is everywhere: a ~$5/month box, a tmux session that survives disconnects, your Claude plan, and suddenly you have an agent that works while your laptop is closed. Total cost, box included, is usually under what one hour of your time is worth.
It's a genuinely good setup. Long tasks run to completion. Nothing dies with your Wi-Fi. And with the crop of remote-control tools that appeared this year — official and open-source — you can steer the session from your phone.
The idle-box problem
Here's what the setup guides don't mention: the box spends most of its life idle. Not because the agent is slow — because you are the queue. Every task still starts with you noticing something, formulating it, and typing it. The agent has 24/7 capacity and a workday-with-gaps input stream. You built an always-on worker and gave it a sometimes-on manager.
Your customers are the queue
The highest-signal tasks don't come from your backlog — they come from a visitor hitting a wall right now. That's the loop chatwithdev closes:
- A visitor reports something in the chat widget on your site. It lands in your own Telegram, like every chatwithdev conversation.
- You tap ➕ Ticket under the message. The ticket is drafted from the transcript (title, summary, kind, priority) and saved in your words — the visitor never authors anything.
- One more tap — 🖥 Fix on my server — dispatches it to your VPS. Your agent works the ticket on a branch and progress streams back to Telegram: started, working, PR opened.
- You review the PR on your phone and merge. Optionally, the widget tells the visitor their issue is fixed.
From complaint to merged PR, without leaving Telegram — and the box finally earns its five dollars.
What runs on your box: chatrelay-runner
The VPS side is a small open-source daemon, chatrelay-runner (MIT, on npm), that lives next to your repo checkout. It polls chatwithdev for dispatched tickets — outbound-only, so there are no inbound ports, no webhooks to host, and we never hold SSH keys or run code on your machine. The whole install is one paste:
npx chatrelay-runner init --token crr_… # writes the config, checks claude/gh,
# verifies the token live
npx chatrelay-runner # start polling
npx chatrelay-runner service # print a systemd unit to keep it aliveClaude Code is the default, not a requirement — the configured command is a plain shell template ($TASK is the ticket), so anything that takes a prompt plugs in. Your box runs your command in your repo, behind guardrails:
- It refuses a dirty working tree. Your uncommitted work is never swept into an automated branch.
- It never touches your default branch. Every job works on
chatrelay/fix-…, freshly branched; the PR is the only way changes land. - The ticket is the prompt — your words. The customer transcript rides along explicitly marked as data, not instructions.
- Jobs are one-shot and time-boxed. The agent is killed after 90 minutes; stuck jobs are reaped server-side and you're told why.
Keep the human gate
Recent research on agent-authored fix PRs is sobering: unsupervised, a large share never merge — plausible patches that miss the root cause or break something adjacent. The loop above is designed around that reality. A human decides what's real (the ticket), a human words the task, and a human reviews the diff before anything ships. The agent does the typing, not the deciding.
If you don't have a VPS (or don't want one)
The runner is one of three dispatch tiers. If your repo is on GitHub, the 🔧 Fix on GitHub tier files an issue mentioning @claude and the Claude GitHub App opens the PR — zero infrastructure. And tickets are useful with no dispatch at all: a customer-support and bug queue that lives where your chats already are.
Getting started
The chat relay is live today — start free, one script tag, and your website chats arrive in your Telegram. Tickets are built in, and chatrelay-runner is on npm now — the docs cover the widget setup, and the GitHub tier needs no box at all.
FAQ
Do I have to open ports on my VPS or hand over SSH access?
No. The runner is outbound-only: it polls chatwithdev with a revocable bearer token and reports progress the same way. No inbound ports, no webhooks to host, and chatwithdev never holds SSH keys or executes anything — your machine runs your command in your repo.
Does it only work with Claude Code?
No. The configured command is a plain shell template that receives the ticket as $TASK (and a file path as $TASK_FILE). Claude Code is the default; aider or your own script work the same way.
What stops the agent from wrecking my repo?
Four guardrails: the runner refuses to start on a dirty working tree, works only on a fresh chatrelay/fix-… branch, never pushes your default branch, and everything lands through a PR you review. Customer text is never the prompt — your confirmed ticket is.
What does the setup cost?
The chatrelay-runner CLI is MIT-licensed and free. A capable VPS runs about $5/month, and you bring the Claude plan you already have. Tickets are part of chatwithdev; dispatch tiers land on paid plans.
