← All posts

I Let an AI Agent Run My Tests While I Slept. Here's the Setup.

July 22, 2026 · 6 min read · The xShellz Team

Most AI coding tools stop when your laptop lid closes. That's fine for quick autocompletions, but it falls apart as soon as you want an agent to run a 45-minute test suite, re-run it on a schedule, and tell you what broke while you're getting coffee. I wanted my AI pair programmer to keep working after I logged off. So I wired up a remote Linux shell, an AI coding agent (borg, in my case), and an always-on IRC connection. Now tests, log watches, and build checks happen without me, and results land in my IRC client whether I'm at my desk or not.

The pieces you'll actually need

The core idea is simple: a machine that stays online runs a loop that invokes your AI agent and then tells you what happened over a chat protocol that doesn't require a persistent local client. I used three components:

  1. Remote Linux shell, a small VPS or shell account that never sleeps.
  2. AI coding agent, something that can run commands from a prompt and iterate on output. I'm using borg, but this works with any agent that can be driven headlessly.
  3. IRC bouncer, a daemon (ZNC in my case) that sits between an IRC server and your client, keeping you connected even when you disconnect.

The remote shell hosts borg inside a tmux session. The bouncer stays logged into a private IRC channel. A tiny glue script takes the agent's output and posts it into that channel. I connect to the bouncer from my laptop and see the results, no matter when they ran.

Keeping the shell and bouncer alive forever

I started with an xShellz remote shell because I didn't want to manage a full VPS just for this. It gives me a consistent home directory, tmux support, and a persistent IRC bouncer that comes pre-configured if you ask for it. You can replicate this on any Linux box: install ZNC, create a network that connects to your IRC server (or a self-hosted one), and set KeepNick and KeepBuffer so you never miss messages.

Once the bouncer is running, I can attach to it from any IRC client with server localhost +port, and it replays the backlog.

Giving the agent a long-running command loop

Inside the remote shell, I start a tmux session:

tmux new-session -s agent

Then I drop in a script that runs borg on a loop and logs its output:

#!/bin/bash
while true; do
  echo "=== Run $(date) ===" >> /home/user/test_log.txt
  borg --yes --model gpt-4o "run the full test suite with pytest and append the last 20 lines of output" >> /home/user/test_log.txt 2>&1
  sleep 1800
done

I start it in the tmux session so it survives an ssh disconnect. Borg has a built-in ability to run long shell pipelines; I give it one clear, repeatable instruction. If the tests fail, the output shows the traceback.

Wiring agent output to IRC

A log file isn't much good if I'm not checking it. I want a notification in a chat channel I already monitor. Since the IRC bouncer is local to the same shell, I can inject a message into it with netcat.

First, I make sure ZNC is configured with a module that listens on a local port for message injection, or I just start a tiny IRC bot that connects to the bouncer. I went with a minimalistic approach: a one-liner that writes a PRIVMSG to the ZNC control port.

ZNC's modperl or admin module can be used, but the simplest way is to create a dedicated ZNC user that auto-joins #builds and then write to its incoming socket. Assuming ZNC listens on 127.0.0.1:6667 for that user, sending a raw IRC line works:

echo -e "PRIVMSG #builds :Test run finished. Last line: $(tail -1 /home/user/test_log.txt)" | nc 127.0.0.1 6667

I put that into a small notify.sh and call it from the loop after borg finishes. Because ZNC holds the connection to the IRC server, the message gets sent even if my laptop is offline. The next time I open my IRC client and connect to the bouncer, the entire #builds backlog is waiting for me.

What a nightly run looks like in practice

Here's the whole loop, trimmed to the essential parts:

#!/bin/bash
export OPENAI_API_KEY="sk-..."
while true; do
  echo "--- Starting run at $(date) ---" >> nightly.log
  borg --yes "run pytest. if any test fails, list the failed test names and the relevant traceback snippet" >> nightly.log 2>&1
  STATUS=$(tail -10 nightly.log | grep -c "FAILED")
  if [ "$STATUS" -gt 0 ]; then
    MSG="$(date): ${STATUS} tests failed. Check backlog."
  else
    MSG="$(date): All tests passed."
  fi
  echo -e "PRIVMSG #builds :${MSG}" | nc 127.0.0.1 6667
  sleep 3600

I run it in the tmux session, detach with Ctrl+b d, and close my laptop. The machine keeps ticking. When I reconnect to ZNC in the morning, I see a neat history of hourly runs without me ever having to keep a terminal open.

Trade-offs and real-world friction

This isn't magic. The agent can still hallucinate, and the feedback loop is slower than an interactive session. I limit borg to read-only test commands so it can't push broken code. I also check the IRC channel before I start my day: if the agent started reporting repeated failures at 3 a.m., I need to intervene.

Security matters, too. I don't give the agent write access to production infrastructure. The remote shell is firewalled to allow only my static IP and the bouncer's outbound IRC connection. Keep your API keys safe.

Cost is modest: a small shell account and a few dollars of API calls per night if you run tests often. The biggest expense is your own sanity if the agent gets stuck in a loop; a timeout flag on every command helps.

Why this stack clicked for me

This setup moved my dev loop from "open laptop, run tests, watch screen" to a background service I can check like email. It's particularly useful for workloads that benefit from wall-clock time: long-running integration tests, slow lint passes, or benchmark suites that I'd never run manually.

If you want to try it, you need three things: a persistent Linux box, an agent that can operate headlessly, and a bouncer to deliver the results. xShellz happens to provide a remote shell and a managed IRC bouncer in one account, which saves me from configuring ZNC and keeping a VPS patched. But you can assemble the same pieces on a $5 VPS and half an hour of tinkering. The real win is waking up to a chat channel that already knows if your code is broken.