Did your last free run inherit yesterday's cache?
I keep hearing one confident claim during reviews. "The agent passed, so the repo is fine." Is that claim about git, or about a dirty disk?
This FAQ is not about latency or chat logs. It is about the workspace your agent actually touched.
What I am actually arguing
A free model can still be useful here. A free server can still be useful here. Neither one proves the working tree was clean.
You still need a fingerprint of the files. You still need a fingerprint of the caches. You still need to know clone versus continue.
Scratch capacity is not a cleanroom
When I need a scratch model and a scratch server, I use MonkeyCode. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
MonkeyCode provides free model access and a free server option. I treat that pair as a scratch pad only. I do not treat the pair as a CI system.
The model can still invent a passing test. The server can still keep last night's dependencies. Why would a green chat fix either problem?
The artifact: a workspace fingerprint
Do not argue from memory about the disk. Print a fingerprint before and after the session.
I use a small bash script on purpose. It is boring, and that is the point. It writes a text file next to the repository.
Label this as a proposed local check only. Run it on your own machine first. Do not paste secrets into the output file.
#!/usr/bin/env bash
# workspace-fingerprint.sh
# Proposed check. Read it before you run it.
set -euo pipefail
OUT="${1:-workspace-fingerprint.txt}"
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
cd "$ROOT"
{
echo "cwd=$PWD"
echo "date_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "git_head=$(git rev-parse HEAD 2>/dev/null || echo NO_GIT)"
echo "git_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo NO_GIT)"
echo "--- porcelain ---"
git status --porcelain=v1 -uall 2>/dev/null || echo "NO_GIT"
echo "--- lockfile hashes ---"
for f in package-lock.json pnpm-lock.yaml yarn.lock Cargo.lock go.sum poetry.lock Gemfile.lock requirements.txt uv.lock; do
if [[ -f "$f" ]]; then
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$f"
else
shasum -a 256 "$f"
fi
fi
done
echo "--- maybe-dirty dirs ---"
for d in node_modules .venv venv target dist build .next .tox .pytest_cache __pycache__; do
if [[ -e "$d" ]]; then
echo "PRESENT $d"
else
echo "ABSENT $d"
fi
done
echo "--- top level ---"
ls -1
} > "$OUT"
echo "wrote $OUT"
Run the script before the agent starts work. Run the script after the agent stops work. Diff the two files with a calm head.
chmod +x workspace-fingerprint.sh
./workspace-fingerprint.sh before.txt
# start the agent session on this tree
./workspace-fingerprint.sh after.txt
diff -u before.txt after.txt
What changed that git cannot even see? If the diff is empty, stay skeptical anyway. You only proved that the fingerprint stayed stable.
That is already more than a chat transcript. A transcript is prose. A fingerprint is evidence.
Myth 1: A new chat is a new machine
Claim: I opened a fresh thread, so the disk is fresh.
How do you know that without listing files? Look for leftover node_modules you never installed. Look for a branch you never checked out.
A chat session is only a conversation. A workspace is only a directory. They do not reset on the same clock.
Ask the boring questions before you trust the run.
git rev-parse --is-inside-work-tree
git remote -v
git log -1 --oneline
If you cannot answer those three commands, you are continuing, not cloning. Why would the model know the difference?
Myth 2: A passing test proves the lockfile
Claim: The test command was green, so the lockfile is honest.
Hash the lockfile yourself before you celebrate. Check whether node_modules predates this supposed clone. A pre-existing tree can hide a broken lockfile.
# Proposed npm example. Adapt to your package manager.
test -f package-lock.json && sha256sum package-lock.json
test -d node_modules && echo "node_modules already exists"
The agent may run tests against leftover packages. Those leftovers may be kinder than your CI. Have you ever seen a laptop pass and CI fail?
Corrected model: a green test on a dirty disk is a maybe. A green test on a fresh clone is a start. CI remains the record you merge against.
Myth 3: The agent cleaned up after itself
Claim: It created a venv, so it removed the venv.
Read the fingerprint section called maybe-dirty dirs. Then read untracked files in the porcelain output. Temp file names will look like leftover experiments.
Agents are sloppy houseguests on a good day. They install extra packages and then patch local files. Who told them to delete the leftover caches?
git clean -nd
git status --ignored
Remember that git clean -nd is a dry run. Read the list slowly before you panic. Do not run git clean -fd until you mean every line.
Corrected model: cleanup is a command you actually ran. It is not a vibe the model implied.
Myth 4: Free servers reset like CI runners
Claim: This server is free, so it must be ephemeral.
Is it ephemeral in any written note? Did you check the directory after a disconnect? Billing and lifecycle are different facts.
CI runners usually start from a clean image. Then they clone the SHA and die on purpose. A reused free server is closer to a laptop.
Laptops accumulate junk without asking anyone. Free describes billing, not lifecycle. Prove the lifecycle with a clone step you control.
I want this sequence in the notes, every time.
- Create an empty directory.
- Run
git clone <url> .inside it. - Run
workspace-fingerprint.shand savebefore.txt. - Run the agent against that clone only.
- Run
workspace-fingerprint.shagain asafter.txt. - Run the project's real test command yourself.
- Attach both fingerprint files to the PR.
If you skip the empty directory, you are not doing CI. You are doing conversation-driven work on a used plate. Does that workflow still sound mergeable to you?
Myth 5: git status is enough by itself
Claim: porcelain is empty, so the workspace is clean.
Porcelain ignores a lot of runtime junk files. node_modules is often gitignored on purpose. .venv and build caches are often gitignored too.
Those ignored paths are exactly what change tests. Empty porcelain plus PRESENT .venv is not clean. It means the repo is clean and the machine is not.
git status --porcelain=v1 -uall
git status --ignored
Corrected model: git answers questions about tracked files. Tests answer questions about runtime files. You need both fingerprints before you shrug.
Decision table: what that free run proved
Print the table in the pull request body. Argue from the row you actually occupy. Which row are you in right now?
| You saw | You proved | You did not prove |
|---|---|---|
| Chat said tests passed | The model emitted that sentence | The test runner actually exited 0 |
| Fingerprint shows ABSENT caches, then tests | You probably started from source | Anything about production parity |
Fingerprint shows PRESENT node_modules
|
Something was installed earlier | That the tree matches the lockfile |
| Porcelain empty after the session | Tracked files still match HEAD | Ignored caches are honest |
| Two fingerprints match | The fingerprint was stable | The fingerprint was the right one |
| Fresh clone + real test command + exit 0 | This SHA passed this command here | Tomorrow's box will match today |
Two extra checks worth running
These commands are examples, so label them as unproven sketches. Adapt them to your stack before you copy.
# Node: pick a fight with the lockfile, do not "fix" it yet
if [[ -f package-lock.json ]]; then
npm ci --ignore-scripts --dry-run
fi
# Python: are we sitting inside a leftover prefix?
python -c "import sys; print(sys.prefix)"
test -d .venv && echo "local .venv present"
npm ci --dry-run will not repair the tree. It will argue with the tree in public. That public argument is the entire point here.
For compiled stacks I also glance at target or dist. A warm cache can hide a broken toolchain. A cold clone cannot hide it as easily.
Limitations
This fingerprint does not hash every file on disk. It does not detect hostile processes on the box. It does not prove network isolation either way.
It does not name a model or any hardware. It does not promise a free server will exist tomorrow. Treat those absences as features of the check.
It also cannot see secrets, and that is good. Do not teach the script to print .env. Do not dump credentials into the PR for completeness.
If your build needs private packages, this sketch is incomplete. If your tests need extra services, this sketch is incomplete. If you need a contractual SLA, this is the wrong layer.
Who should not use this approach
Do not use a shared free server for customer data. Do not use it for production deploys either. Do not use it as your only CI system.
Skip this folklore if you already have ephemeral runners. Those runners already clone a SHA into a throwaway disk. Your job is then the test command, not the workspace myth.
Skip this if you cannot read git status output. The script will not save a review you will not do.
What I want reviewers to ask
Was this run a clone or a continue? Where is the before fingerprint, and the after fingerprint? Which row of the table are we occupying?
If the answers are shrugs, the green chat is a story. Stories do not belong on main branch. Cheap tools still need expensive honesty about the disk.
A free model is a cheap way to draft a change. A free server is a cheap place to try that draft. The workspace fingerprint keeps those tools honest about files.
If you try the script on a scratch box, attach the diff. Do not attach the chat log as evidence.
Top comments (0)