shedix

Run your test suite on a bigger machine

A ten-minute test suite on your laptop takes the laptop with it for ten minutes. The fans spin up, the editor stutters, and the agent that started the run sits waiting on a command that may outlast its own time limit. Moving the suite to a bigger Linux machine fixes all three. The loop is short: copy the code over, run the suite in tmux, bring the results back, stop the machine.

Copy the working tree

rsync is the right tool because it copies only what changed. The rsync manual describes a quick check on file size and modification time to find changed files, and a delta transfer that sends only the differences inside them. Below, $LOGIN is the machine's user and address, like sam@sam-3f2a1b.shedix.dev.

rsync -az --delete --exclude node_modules --exclude dist ./ $LOGIN:~/work/myapp/
  • -a recurses into folders and keeps permissions and timestamps; -z compresses data on the way.
  • The trailing slash on ./ copies the folder's contents, not the folder itself.
  • --delete removes files on the machine that you deleted locally. Excluded paths are left alone, so the machine's own node_modules survives.
  • Leave out dependencies and build output. Packages with native code built on macOS won't run on Linux, so install on the machine:
ssh $LOGIN 'cd ~/work/myapp && pnpm install'

The first sync sends everything. After that, each run sends only what changed.

Start the run in tmux

Agents run shell commands under time limits. Claude Code gives a command two minutes by default, and ten minutes is the default ceiling for one it runs in the foreground (tools reference). A long suite, run over an SSH connection that dies when the laptop sleeps, is fragile. Start it in a detached tmux session on the machine instead, writing to a log:

ssh $LOGIN "tmux new -d -s tests 'cd ~/work/myapp && pnpm test > ~/work/tests.log 2>&1; echo exit=\$? >> ~/work/tests.log'"

When you give ssh a command, it runs that command on the machine instead of a login shell. Here the command starts tmux, tmux starts the suite in the background, and ssh returns at once. The suite keeps running whatever happens to your connection, and the last line of the log records its exit code.

Check on it whenever you like:

ssh $LOGIN 'tail -n 5 ~/work/tests.log'

Tell your agent this in plain words, in its instructions file or the prompt: start the suite with that command, read the end of the log every minute or two, and report the failures once a line starting with exit= appears. The agent's own commands now take a second each, and it can do other work in between.

Make the runner use the cores

A bigger machine helps only if the test runner spreads out. Run nproc on the machine to see how many CPUs it has, then check how your runner picks its number of workers. Playwright, for example, uses half the logical cores by default. Its --workers option takes a number or a percentage, and --shard splits a suite across machines:

npx playwright test --workers=100%
npx playwright test --shard=1/2    # and --shard=2/2 on a second machine

More workers use more memory, so watch the first few runs. On shedix, the web stack comes with Playwright and Chromium installed, so browser tests run without extra setup.

Bring the results back

Copy back whatever your runner writes: a JUnit XML file, a coverage folder, an HTML report, screenshots from failed tests.

rsync -az $LOGIN:~/work/myapp/reports/ ./reports/

On shedix you can also download them from the machine's Files panel, which shows ~/work in the browser.

What a run costs

At shedix's prices, a run costs its length times the hourly price:

Size Machine Price 20-minute run
M 4 vCPU, 8 GB $0.16/hr about $0.05
L 8 vCPU, 16 GB $0.32/hr about $0.11
XL 16 vCPU, 32 GB $0.64/hr about $0.21

If doubling the cores halves the wall time, the cost per run stays the same and you get the answer sooner: 20 minutes on an L and 10 minutes on an XL both come to about $0.11. If your suite doesn't scale that way, the smaller machine is the better deal. Time one run on each and pick.

The cost that adds up is idle time. A shedix machine stops by itself after an hour without use, but that idle hour on an L is $0.32, the price of three runs. Stop the machine when the results are back:

curl -sS -X POST "$SHEDIX_URL/api/machines/$NAME/stop" -H "Authorization: Bearer $SHEDIX_TOKEN"

A stopped machine has no hourly charge and keeps its disk, installed dependencies included, so the next run doesn't begin with a fresh install. Starting it again takes about 45 to 60 seconds. Its IP address changes each time it starts, but a shedix machine also has a name, like sam-3f2a1b.shedix.dev, that follows it to each new address, so $LOGIN above stays the same:

curl -sS -X POST "$SHEDIX_URL/api/machines/$NAME/start?wait=240" -H "Authorization: Bearer $SHEDIX_TOKEN"
LOGIN=$(curl -sS "$SHEDIX_URL/api/machines/$NAME" -H "Authorization: Bearer $SHEDIX_TOKEN" | jq -r '"\(.access.user)@\(.access.host)"')

For scripts, ssh -o StrictHostKeyChecking=accept-new accepts the key of a machine you haven't seen without stopping to ask.

Off your laptop shows this loop on shedix. Every call above is in the API docs, and an agent can run the whole thing with curl and ssh by following /agents.md.