DEV Community

Jordan Huang
Jordan Huang

Posted on

FAQ: The venv Died. Five State Myths Agents Repeat

Did your agent install the package on your machine?

I keep getting that exact question in code reviews. The chat log looks confident, complete, and done. The transcript even shows a clean pip exit code.

Then CI fails on a missing import. Your own laptop still lacks that installed wheel. So what actually happened on disk then?

The real problem

Agents talk like they own your disk. They really do not own that disk.

A free remote box is only a scratch runtime. A free model is a speaker, not a filesystem.

Neither actor is your shipping laptop though. And neither actor is your merge pipeline.

I treat every installed claim as a location claim. So where did those installed bytes actually land? If I cannot name a prefix, I do not believe the chat.

How I check, not how I hope

I run the same probe in three places. That means local shell, agent box, then CI. I save every stdout blob beside the repo.

If the three fingerprints differ, I stop trusting the transcript. The mismatch is the bug, not the tone. Confidence in a chat window is not evidence.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

I sometimes run the box-side probe on MonkeyCode's free server option. Free model access is enough to drive those probe commands. I still refuse to treat that box as durable storage.

Myth 1: pip succeeded, so my laptop has it

The transcript shows a successful pip install line. Do you honestly feel finished after that line? Which Python binary ran that pip process?

Which install prefix received the wheel files? If you cannot answer both, you only watched a story.

# probe_pip.sh — labeled example; run where you claim the install happened
set -euo pipefail
python -c "import sys; print('exe=', sys.executable)"
python -c "import sys; print('prefix=', sys.prefix)"
python -m pip -V
python -c "import foo, inspect; print('foo=', foo.__file__)" || echo "foo-not-importable"
Enter fullscreen mode Exit fullscreen mode

If that path is not your laptop prefix, you installed elsewhere. The chat did not sync wheels to your disk. Copying a success line is not a deploy.

Corrected model: an install is a filesystem write. Name the prefix, or it did not happen for you. A bare it-worked line without a path is incomplete.

I also print sys.path when imports look haunted. A second interpreter is a very common thief. Agents love the wrong python on the PATH.

Myth 2: I exported the key, so the next command has it

Did you export inside a short-lived subshell? Did the box recycle the whole process tree? Environment is not a group chat, right?

# probe_env.sh — labeled example
echo "pid=$$"
echo "home=$HOME"
echo "pwd=$PWD"
echo "shell=$SHELL"
env | sort | sha256sum
Enter fullscreen mode Exit fullscreen mode

Compare hashes across turns after each command. Did those hashes stay identical this time around? If they drift, your export already died then.

A model saying it set an access key is not a vault. That sentence is only text on a screen. The next PID may start completely empty.

The corrected model is process-scoped environment, always. New session means new env, unless you prove otherwise. Write the hash down before you argue.

I never paste live production secrets into that probe. Use a dummy DEMO_TOKEN instead for the test. You are measuring survival, not leaking real credentials.

Myth 3: The home directory will be there tomorrow

Free scratch boxes look like small VMs. They feel sticky, like a rented laptop. So are those disks actually sticky though?

Write a canary file on the box. Leave the session for a later return. Come back later and try to read it.

# probe_persist.sh — labeled example
set -euo pipefail
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
CANARY="${HOME}/.canary_${STAMP}"
printf 'host=%s\nstamp=%s\n' "$(hostname)" "$STAMP" > "$CANARY"
ls -l "$CANARY"
sha256sum "$CANARY"
echo "canary_path=$CANARY"
Enter fullscreen mode Exit fullscreen mode

If the next session cannot cat that file, persistence was a story. Do not park secrets there at all. Do not park venvs there either, ever.

The corrected model: assume ephemeral disks until docs prove durable volumes. I will not invent retention hours here. I do not know them, so I measure.

Hostname changes are another useful tell here. Did hostname flip between those two sessions? Then you likely got a fresh box, not a resume.

Myth 4: The agent ran pytest, so I can skip CI

Green text in a chat is not a merge gate. Who owned the checkout directory just then? Which git SHA was actually tested there?

# probe_git.sh — labeled example
set -euo pipefail
git rev-parse HEAD
git status --porcelain
git diff --stat
python -m pytest -q --maxfail=1
Enter fullscreen mode Exit fullscreen mode

Run that in CI on the merge SHA. Do not trust a dirty agent workdir. Do not trust files the model invented under tmp.

The corrected model treats CI as the SHA record. The box is only a rehearsal room. Rehearsal can lie about dirty trees and missing hooks.

I still use the box to fail fast on obvious breakage. I do not let it replace required checks. Those are different jobs, and they should stay different.

Myth 5: Writing .env on the box is a secrets strategy

The agent offers to save credentials for later. Later for whom, exactly, in this setup?

Was it the next process, tenant, or log shipper? Do you actually know who can read that home?

Never paste production secrets into a scratch server. Never ask a model to echo them back. Never commit .env from a disposable home directory.

# probe_secret_surface.sh — labeled example; dummy names only
ps eww -p $$ 2>/dev/null | tr ' ' '\n' | grep -E 'KEY|TOKEN|SECRET' || true
umask
ls -l .env 2>/dev/null || echo "no local .env"
id
Enter fullscreen mode Exit fullscreen mode

The corrected model is a shared classroom desk. You wipe it when you stand up. You do not leave keys in the drawer.

If a secret touched the box, I rotate it. That is cheaper than hoping in logs. Hope is not an incident response plan.

Artifact: a three-place decision table

I keep this table in the repo. I fill that table once per incident. Empty cells mean unknown, not a success.

Claim in chat Probe Local Agent box CI
package installed sys.executable plus __file__
env var set env sha256
file persisted canary path
tests green SHA plus pytest
secret stored umask plus .env listing

Unknown is not a pass in this table. Fill the cells or reject the claim. The table is the artifact, not the vibes.

A concrete workflow I actually use

  1. Copy the five probes into the scripts/agent_probes directory now.
  2. Run them locally and save probes/local.txt today too.
  3. Run them on the agent box, saving probes/box.txt.
  4. Run them in CI, then save probes/ci.txt.
  5. Diff the three files and argue from that diff.
# labeled example workflow
mkdir -p probes scripts/agent_probes
chmod +x scripts/agent_probes/*.sh
./scripts/agent_probes/probe_pip.sh | tee probes/local.txt
# later, on the box:
# ./scripts/agent_probes/probe_pip.sh | tee probes/box.txt
diff -u probes/local.txt probes/box.txt || true
Enter fullscreen mode Exit fullscreen mode

The file diff is the actual lesson here. The chat transcript is only extra commentary here. I paste the diff into the review, not the model's summary.

Need a fourth file for session notes? Add probes/notes.md with the session id. Then future you can reconstruct the argument.

What this does not prove

These probes do not measure model quality at all. They also do not rank any vendors. They only locate state for the incident.

They do not certify disk lifetime on any host. I never claimed any vendor keeps disks for a set duration.

Command access does not make the disk durable. It does not replace your CI runners either.

Network from a box is not your laptop network. I did not probe egress in this article. Do that with a separate allowlist test if you must.

Clocks can lie too on scratch boxes. I use date -u only as a label. I do not treat the box clock as an audit source.

These probes assume a Linux-like userland. Windows shells will need different commands here.

Who should not use this approach

Skip this if you already have locked-down CI only. You do not need a scratch box to merge. Your pipeline already is the runtime of record.

Skip this if compliance forbids unknown runtimes. A free server stays unknown until you inventory images, users, and logs. Do that work first, or do not send code there.

Skip this if you need long-lived databases. This workflow locates state, not hosted state. Same rule applies for long GPU training jobs.

Do not use a free agent box as a password manager. Do not use it as artifact storage. Do not use it as a backup target.

The mental model I keep

Three actors share every single agent session. A talking model is only one of those actors. A running box is the second actor here.

A shipping laptop is the third actor in that set. Ask where the bytes live every single time.

If you cannot point at a path, the claim is theater. Theater does not belong in the merge checklist.

The venv died with the session itself. That outcome is normal, not a mystery. Plan for ephemeral state, then you stop getting surprised.

Want a disposable place to run the probes? MonkeyCode's free server option is one scratch box I use for that comparison. Then I delete the canary and I move on.

Top comments (0)