DEV Community

Jordan Huang
Jordan Huang

Posted on

FAQ: Five Myths About Treating a Free Agent Box Like Your Laptop

You just got a free remote agent box running.
Does it feel like your laptop already?
Your machine has Node, Docker, and git.
Why would a shared box match that layout?

I keep watching agents fail on simple shell steps.
The model is not always the real problem.
The remote box is still not your workstation.
This FAQ is the checklist I wish I had.

What this FAQ is for

I write this as a myth list, not a product tour.
You will get claims, checks, and a corrected model.

Run the inventory before you trust any agent command.
Skip the box if your work needs a sealed machine.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.
I use MonkeyCode for free model access and a free server option.

That pairing is useful for throwaway agent loops.
It is not a clone of my laptop image.

Myth 1: The working directory is always the repo root

Agents love listing files and then running tests.
They assume the shell starts inside your project.

Does your wrapper actually change directory before tools?
Have you printed the working directory on turn one?

What I check

pwd
ls -la
git rev-parse --show-toplevel 2>/dev/null || echo "no git root"
Enter fullscreen mode Exit fullscreen mode

The working directory may be the home folder.
The repo may live under a nested work path.
Then every relative path becomes a lie.

A missing package file is often a directory bug.
It is not a missing dependency on its own.

Corrected model

Treat the working directory as untrusted input always.
Pin it in the wrapper, not in the prompt.
Fail the turn if the directory is not the expected root.

Myth 2: If the binary exists on my laptop, it exists here

People say just run jq on the box.
People say just run compose as usual.

Those sentences describe your local machine, not this box.
Have you asked the box what it actually has?

What I check

command -v git
command -v node
command -v python3
command -v docker
command -v jq
command -v make
uname -a
id
Enter fullscreen mode Exit fullscreen mode

A missing jq binary is not a model failure.
A missing docker binary is not a prompt failure.

The agent will invent flags for tools that are absent.
That is how you get confident nonsense in the log.

Corrected model

Build an allowlist of binaries before the loop starts.
Refuse tasks that need tools outside that list.
Do not let the agent install its way into a surprise.

Myth 3: Package installs stick around across turns

You watched the agent install a Python package.
The next turn imported it without any errors.

Did that wheel land on a writable durable disk?
Or did it land in temp space that dies later?

I do not assume persistence on a free server.
I do not assume a stable site-packages path either.
Did the install even use the same interpreter?

What I check

python3 -c "import sys; print(sys.executable); print(sys.path)"
python3 -m pip show requests || true
npm root -g
echo "HOME=$HOME TMPDIR=$TMPDIR"
df -h
Enter fullscreen mode Exit fullscreen mode

If home changes between turns, your cache is gone.
If the interpreter changes, the package is gone.

Success two turns ago is not a contract.
Print the interpreter after every install step.

Corrected model

Install into a path you own and then print it.
Record the interpreter hash next to the lockfile.
Re-run the show command after every sandbox recycle.

Myth 4: I can sudo, bind-mount, and run Docker like home

Locally you are in the docker group.
Locally you have passwordless sudo for a reason.

A free server is not that reason.
Can you even see the docker socket file?

What I check

sudo -n true && echo "sudo works" || echo "no sudo"
ls -l /var/run/docker.sock 2>/dev/null || echo "no docker sock"
cat /etc/os-release
ulimit -a
Enter fullscreen mode Exit fullscreen mode

No sudo is a feature on a shared box.
Nested docker is a privilege you probably lack.

The agent will still propose a root package update.
That proposal copies your laptop privileges by habit.

Corrected model

Assume an unprivileged user with no nested containers.
Rewrite tasks so they only need user-space tools.
If you need Docker, skip this class of box.

Myth 5: Leftover files mean this workspace is mine

You found a node_modules folder already sitting there.
Is that a lucky cache from last turn?

Or last tenant's junk on a recycled disk?
Or is it last turn's half-finished install?

Free boxes get recycled without much ceremony.
Recycling is not the same as a cleanroom.
Did you name your workspace with a unique prefix?

What I check

find . -maxdepth 2 -type d \( -name node_modules -o -name .venv -o -name target \)
ls -la /tmp | head
stat -c '%u %U %y %n' . 2>/dev/null || stat -f '%u %Su %Sm %N' .
Enter fullscreen mode Exit fullscreen mode

A warm cache can hide a dirty tree.
A dirty tree can hide a secret from a prior run.

I treat unexpected files as hostile until hashed.
Hash them or delete them before the first tool call.

Corrected model

Start from a known tarball or a git sha.
Delete or ignore anything you did not create.
Never read leftover env files as yours.

How these five myths stack

Wrong directory plus missing tools looks like a bad model.
Missing tools plus a leftover cache looks like a flaky install.
A leftover cache plus sudo dreams looks like a security incident.

I debug the stack from the box upward.
I do not start with a longer prompt.
Would you tune hyperparameters before checking the working directory?

Log signatures I watch for

  • ENOENT on a file you can see locally
  • command not found after a confident plan
  • Permission denied on /usr or docker.sock
  • ModuleNotFoundError after a "successful" pip log
  • npm ERR! with a path outside the repo
  • an .env file whose mtime predates your task

Each signature maps to a myth above.
None of them mean the free model got worse today.
You should fix the box story first.

Turn-zero protocol

  1. Upload or clone one known git sha.
  2. Run the inventory script and store the log.
  3. Diff the tool allowlist against the task.
  4. Abort on leftovers, sudo needs, or missing markers.
  5. Only then should you start the agent loop.
  6. Re-run inventory after any suspected box recycle.

This whole protocol stays boring on purpose.
Boring checks beat a clever retry storm.
I would rather waste one minute than ten turns.

The artifact: inventory then decide

Here is the script I paste before any loop.
Label this a proposed check, not a benchmark.
I am not claiming production numbers from it.

#!/usr/bin/env bash
# box-inventory.sh -- proposed check, run inside the agent box
set -euo pipefail

echo "== identity =="
date -u +%Y-%m-%dT%H:%M:%SZ
id
hostname
uname -a

echo "== cwd and git =="
pwd
git rev-parse --is-inside-work-tree 2>/dev/null || echo "not a git work tree"
git status -sb 2>/dev/null || true

echo "== tools =="
for b in git node python3 pip3 npm docker jq make curl sudo; do
  if command -v "$b" >/dev/null 2>&1; then
    echo "PRESENT $b -> $(command -v "$b")"
  else
    echo "MISSING $b"
  fi
done

echo "== python =="
python3 - <<'PY' || true
import sys, os
print("exe", sys.executable)
print("ver", sys.version.replace("\n", " "))
print("HOME", os.environ.get("HOME"))
print("TMPDIR", os.environ.get("TMPDIR"))
PY

echo "== privileges =="
sudo -n true 2>/dev/null && echo "sudo: nopass" || echo "sudo: no"
if test -S /var/run/docker.sock; then echo "docker.sock: yes"; else echo "docker.sock: no"; fi

echo "== disk =="
df -h .
df -h /tmp

echo "== leftovers =="
find . -maxdepth 3 \( -name node_modules -o -name .venv -o -name .env -o -name id_rsa \) -print 2>/dev/null | head
Enter fullscreen mode Exit fullscreen mode

Run it once before the agent loop starts.
Save stdout next to the task id.
Compare the next turn against that snapshot.

Decision table

Signal from inventory Do not assume Do this instead
pwd is not the expected root relative paths work cd in the wrapper and assert
MISSING docker or no socket compose files will run rewrite to unit tests or skip
sudo: no apt or yum belongs in the plan use user-space binaries only
interpreter path flipped prior pip installs survived reinstall into a pinned venv
leftover .env or id_rsa the tree is yours abort and start a fresh workspace
/tmp is tiny or full large installs will work fail fast with a disk check

I want the table in the pull request template.
The agent does not get to skip the inventory.
If a cell is red, I change the task, not the prompt.

A tiny wrapper pattern

Do not bury directory changes inside a long system prompt.
Put them in the tool wrapper where they can fail.

#!/usr/bin/env bash
# run-in-repo.sh -- proposed wrapper
set -euo pipefail
ROOT="${AGENT_ROOT:?AGENT_ROOT is required}"
cd "$ROOT"
if test -f "$ROOT/package.json" || test -f "$ROOT/pyproject.toml"; then
  exec "$@"
fi
echo "refusing: no project marker in $ROOT" >&2
exit 2
Enter fullscreen mode Exit fullscreen mode

Then the tool only runs the wrapped test command.
If the directory is wrong, you get exit two.
You do not get a novel about missing modules.

Limitations

This inventory still does not prove strong isolation.
It does not prove the next recycle will look identical.
It does not measure model quality at all.

Free model access can change without any notice.
A free server option can vanish or throttle.
I am not claiming quotas, hardware, or uptime.

The script can still miss setuid helpers.
It can miss extra path entries the agent later exports.
It cannot see another tenant's process list on every host.

Clock skew can still confuse your later logs.
Network egress may be blocked even when curl exists.
A present binary is not the version you tested.

Who should not use this approach

Do not use a free shared box for secrets.
Do not put customer data on it.

Do not run production deploys from it.
Skip this if you need nested containers.

Skip this if you need a stable IP.
Skip this if compliance needs a named host.

If your task needs a laptop replica, image your own VM.
This FAQ is for throwaway agent work only.
It is not a hardening guide for multi-tenant kernels.

What I want you to try

Print the directory, user, and tool allowlist first.
Then let the model work on the task.
If you try this, tell me which row went red.

Top comments (0)