DEV Community

Jordan Huang
Jordan Huang

Posted on

FAQ: Five Myths About Shipping From a Free Agent Host

I keep hearing the same merge story this week.
Someone ran an agent on a free remote box.
The chat printed done, so they opened a PR.

Did they actually keep the run at all?
Free model access changed the cost of trying.
It did not change what git will accept.

A borrowed host is not a lab notebook.
So why do we still merge from one?
This FAQ is about that exact gap.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.
MonkeyCode offers free model access and a free server option.
I treat that pair as a draft loop, never as CI.

You can strip every product name out today.
The review questions stay exactly the same anyway.

What this FAQ is not

This piece is not another product bake-off.
This piece is also not a latency chart.
I am not promising that free hosts last.

I will not name any models here.
I will not invent quotas or hardware specs.
I will not quote a benchmark I skipped.

Myth 1: The free host is the source of truth

The claim. The files live on the server, so merge.

What I hear. People paste a tree listing into Slack.
They call that listing the whole project.
They never fetch git objects at all.

Why it fails. You do not own that disk.
You also do not control snapshots there.
A directory listing is not a commit.

Corrected model. Local commits are the only truth.
Treat the free box like /tmp with SSH.
If you cannot clone it, you have a rumor.

Ask one blunt question before review starts.
Can I rebuild this state without the host?
If the answer is no, stop the merge.

# example export on the scratch host
git rev-parse HEAD
git status --porcelain=v1
git diff --stat
git bundle create /tmp/run.bundle HEAD
Enter fullscreen mode Exit fullscreen mode

Copy the bundle off the box immediately.
Commit or stash before you export anything.
Chat screenshots do not travel into git.

Myth 2: Free tokens mean I can skip an oracle

The claim. The model is free, so the essay is enough.

What I hear. People skip the failing unit test.
They also skip the typecheck command.
They never write the exact invocation.

Why it fails. Cheap inference can still lie.
It lies in fluent, confident English.
Your only honest signal is the exit code.

Corrected model. Write the oracle before the prompt.
Keep one command and one expected status.
Run it on the host, then run it at home.

# example oracles; swap in your real gate
python -m compileall -q src
pytest -q tests/test_contract.py
Enter fullscreen mode Exit fullscreen mode

No oracle means you only ran a demo.
Demos do not belong on main later.
Why would a free model change that?

I still want a free model for drafts.
I do not use it as the merge judge.
The judge is a command I can paste.

Myth 3: I'll just reproduce it locally later

The claim. The box is up, so tonight is fine.

What I hear. People leave the SSH tab open.
They close the laptop and switch tasks.
They assume the workspace will wait forever.

Why it fails. You do not set disk lifetime.
I will not guess that lifetime either.
If you did not export, you gambled.

Corrected model. Export before you context-switch.
Patch, manifest, and command log leave together.
"Later" is not a backup strategy here.

run-id: 2026-09-18T14-02Z
must-copy:
  - patch.diff
  - run_manifest.json
  - commands.log
rule: if it is not copied, it is gone
Enter fullscreen mode Exit fullscreen mode

Ask the ugly question out loud now.
If SSH dies now, what still exists?
Only the files you already copied off.

Myth 4: A free server can stand in for CI

The claim. It passed on the agent box, so ship.

What I hear. One green session becomes the gate.
There is no workflow file at all.
There is no pinned runner image either.

Why it fails. CI is a named identity.
CI is a pinned image and a log URL.
A borrowed shell is only a conversation.

Corrected model. The free host is a rehearsal.
CI is the performance you ship against.
Missing CI is not a cheap rehearsal.

Question Free agent host Real CI
Who owns the disk? Not you Your org
Can a neighbor change it? Unknown Isolated job
Is the image pinned? Often no Should be
Can a stranger replay it? Not from chat From the log
Valid merge evidence? No Yes

If you still live in the left column, wait.
A draft PR is the most I will allow.
The right column is the actual gate.

Would you accept a hallway laptop as CI?
Then do not accept a shared scratch shell.
Same shape of evidence. Same refusal.

Myth 5: Environment drift is a paid-plan problem

The claim. It is just Python, so laptops will match.

What I hear. People skip python -V entirely.
They skip the lockfile hash too.
They skip libc, locale, and working directory.

Why it fails. The free box is not your laptop.
python3 can be a different binary there.
A pass over there can fail right here.

Corrected model. Record the machine, not the vibe.
Hash whatever lockfile you actually use.
Store command, cwd, and version strings.

This is not another lockfile sermon today.
This is a drift sermon with a checklist.
Free hardware still has a personality.

uname -a
python -V
command -v python
pwd
sha256sum requirements.lock 2>/dev/null || true
sha256sum pnpm-lock.yaml 2>/dev/null || true
Enter fullscreen mode Exit fullscreen mode

If those lines are missing, the run is anecdotal.
Would you accept anecdotal CI at work?
Then do not accept it from a scratch host.

Artifact: a run manifest you copy off the box

I want one JSON file beside the diff.
The script below is an example workflow.
Treat it as unexecuted until you run it.

It writes local facts only.
It does not call a vendor API.
It never sets merge_gate to true.

#!/usr/bin/env python3
"""Write run_manifest.json next to a patch. Example workflow."""
from __future__ import annotations

import hashlib
import json
import os
import platform
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path


def sh(args: list[str]) -> tuple[int, str]:
    p = subprocess.run(args, text=True, capture_output=True)
    out = (p.stdout or "") + (p.stderr or "")
    return p.returncode, out.strip()


def sha256_if_exists(path: Path) -> str | None:
    if not path.is_file():
        return None
    h = hashlib.sha256()
    h.update(path.read_bytes())
    return h.hexdigest()


def main() -> int:
    root = Path.cwd()
    oracle = os.environ.get("ORACLE_CMD", "python -m compileall -q .")
    code, log = sh(["bash", "-lc", oracle])
    git_head, head_txt = sh(["git", "rev-parse", "HEAD"])
    dirty_code, dirty = sh(["git", "status", "--porcelain=v1"])
    manifest = {
        "schema": "run_manifest.v1",
        "recorded_at": datetime.now(timezone.utc).isoformat(),
        "note": "Scratch host evidence. Not CI.",
        "host": {
            "platform": platform.platform(),
            "python": sys.version,
            "cwd": str(root),
            "hostname_hash": hashlib.sha256(
                platform.node().encode()
            ).hexdigest()[:12],
        },
        "git": {
            "head_ok": git_head == 0,
            "head": head_txt if git_head == 0 else None,
            "dirty": dirty.splitlines() if dirty_code == 0 else ["status-failed"],
        },
        "lock_sha256": sha256_if_exists(root / "requirements.lock")
        or sha256_if_exists(root / "pnpm-lock.yaml"),
        "oracle": {"cmd": oracle, "exit": code, "tail": log[-2000:]},
        "merge_gate": False,
    }
    out = root / "run_manifest.json"
    out.write_text(json.dumps(manifest, indent=2) + "\n")
    print(f"wrote {out} exit={code} merge_gate=false")
    return 0 if code == 0 else 2


if __name__ == "__main__":
    raise SystemExit(main())
Enter fullscreen mode Exit fullscreen mode

Run it on the scratch host like this:

export ORACLE_CMD='pytest -q tests/test_contract.py'
python3 write_run_manifest.py
scp user@host:~/proj/run_manifest.json .
scp user@host:~/proj/patch.diff .
scp user@host:/tmp/run.bundle .
Enter fullscreen mode Exit fullscreen mode

Then verify at home with this snippet:

python3 - <<'PY'
import json
from pathlib import Path
m = json.loads(Path("run_manifest.json").read_text())
assert m["schema"] == "run_manifest.v1"
assert m["merge_gate"] is False
print("oracle_exit", m["oracle"]["exit"])
print("dirty", m["git"]["dirty"])
print("rehearsal_only", m["host"]["platform"])
PY
Enter fullscreen mode Exit fullscreen mode

If dirty is not empty, stop immediately.
Do not "clean it up in the PR."
Finish the commit on a clone you own.

Why hash the hostname in that JSON?
Because tickets leak into search later.
You need host identity without a hostname paste.

When the free host is allowed

Use the free host when all of these hold:

  • The repo is public or already sanitized
  • You can state the oracle in one line
  • You will export bundle, diff, and manifest
  • CI still runs on runners you control

Skip the free host when any of these hold:

  • Production secrets can leak into cwd
  • You need an SLA or a retention policy
  • Regulated data cannot leave your network
  • You cannot name the merge command

Free is a price, not a control plane.
Did that sentence feel too sharp today?
Good. Keep it in the review template.

Limitations you should expect

This manifest is not real provenance.
It is a note you wrote to yourself.
A compromised host can lie in JSON.

Do not store secrets in that file.
Do not paste raw hostnames into tickets.
Do not pretend compileall catches logic bugs.

Your oracle is only as strict as you wrote.
pytest will miss files you never added.
A green rehearsal is still a rehearsal.

A free server option does not fix that.
Free model access does not fix that either.
The habit is the only durable part.

Who should not treat this as a license

If you handle payments, skip shared scratch hosts.
If you cannot explain the PR, skip the merge.
If you need a lawyer-readable audit, build CI.

This FAQ will not replace that work.
It will not bless a secret-laden workspace.
It will not make a neighbor's disk yours.

The review questions I actually want

Ask these on every free-host pull request:

  1. Where is the git bundle?
  2. Where is run_manifest.json?
  3. What command is the oracle?
  4. Did CI run it, not the chat?
  5. What dies if the SSH session dies?

If any answer is a shrug, stop.
That PR is a rehearsal that escaped.
Engineering starts after the export.

Steal the manifest if it helps.
Keep the five questions either way.
That is the only ask I have.

Top comments (0)