A free server does not earn trust in your repo. A free model does not earn your secrets either. You still review the path before either one runs.
Free capacity changes your bill, not your trust boundary. You can spend less and still leak the same files. That is the review you owe the job before you call anything remote.
Picture a borrowed workshop two blocks from your house. You may use the bench while the lights stay on. You do not nail your house keys to that bench.
MonkeyCode offers free model access and a free server option. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Treat both offers as capacity, not as a trust upgrade.
Write the constraints first
Write the constraints before you write the prompt. Your repo stays on a machine you control. The free server may run builds, not hold your secrets.
The free model may draft text, not apply a patch. Context you send must be the smallest pack that still works. You do not know the quota, the reset, or the preemption window.
You also do not know how long the free server option lasts. So your design must survive a sudden stop. A vanished bench should leave your house intact.
Name the three lines in a file you can diff. The first line is custody of the repo. The second line is custody of the prompt pack.
The third line is custody of the result you accept. If a line is fuzzy, you do not cross it yet. Fuzzy custody turns a convenience plane into a trust plane.
Follow one job across the lines
Follow one coding job from intent to a local result. You write the task in a file on your machine. You pack only the files the task names.
That pack crosses the network to the free model. The model returns a proposal, not a merged commit. You read the proposal on the host before anything applies.
A later build may run on the free server. The build log comes back as evidence, not as authority. You decide on the host whether the evidence is enough.
Think of the flow as a relay with three batons. The first baton is intent, and it never leaves home. The second baton is the pack, and it is the only remote copy.
The third baton is a proposal you can throw away. A build on the free server is a fourth lap, not a new owner. Ownership stays with the machine that holds the git directory.
Notice what never belongs on the free server. Your credentials, your full history, and your private notes stay home. The server sees a build input you already decided to share.
Notice what never belongs in the model call. A dump of the whole tree is not a context pack. A pack is a named list with a reason for each path.
Do not merge the failure domains
A timeout in the model is not a failure of your repo. A preempted free server is not a failure of your tests. A bad proposal is not a failure of your git history.
Those are three domains, and you should not merge them. If you merge them, one stall looks like a broken tree. You then retry the whole job and send context again.
That retry spends more free capacity and widens egress. Separate domains let you retry the cheap part only. You resend a pack, or you rerun a build, not both by habit.
Give each domain a local status the other cannot overwrite. Model status lives next to the proposal hash. Server status lives next to the build log hash.
Repo status lives in git, and only you move it. A remote log must not flip that status by itself. That rule is the whole point of the review.
Run a gate before the call
The next change is a gate that runs before any free call. The gate reads a small job file you keep beside the repo. It refuses the call when a line is crossed.
This script is an example you can copy and run locally. It is not a benchmark, and it is not a product feature. It only checks the manifest you wrote by hand.
#!/usr/bin/env python3
# Local architecture gate for a free-capacity coding job.
# Example only. It does not call a model or a server.
import json
import sys
from pathlib import Path
SECRET_PARTS = (".env", "id_rsa", "credentials", ".pem", "secret")
REMOTE_APPLY = {"remote", "server", "model"}
def load(path):
return json.loads(Path(path).read_text())
def problems(job):
found = []
if job.get("repo_custody") != "host":
found.append("repo custody must stay on the host")
if job.get("apply_site") in REMOTE_APPLY:
found.append("apply must not run on the free path")
if job.get("prompt_custody") != "host":
found.append("prompt pack must be built on the host")
for rel in job.get("context_paths", []):
low = rel.lower()
if any(part in low for part in SECRET_PARTS):
found.append("secret-like path in pack: " + rel)
if rel.startswith("/") or rel.startswith(".."):
found.append("path escapes the repo: " + rel)
if not job.get("context_paths"):
found.append("empty pack is not a reviewed pack")
if job.get("result_custody") != "host":
found.append("result custody must return to the host")
return found
def main():
if len(sys.argv) != 2:
print("usage: python3 review_free_path.py job.json")
return 2
job = load(sys.argv[1])
found = problems(job)
if found:
print("BLOCK")
for item in found:
print("- " + item)
return 1
print("PASS")
print("task=" + job.get("task_id", "unset"))
print("paths=" + str(len(job.get("context_paths", []))))
return 0
if __name__ == "__main__":
sys.exit(main())
Pair the script with a manifest you can review in git. The sample below is intentionally boring and small. Boring is what you want before a remote call.
{
"task_id": "job-184",
"repo_custody": "host",
"prompt_custody": "host",
"apply_site": "host",
"result_custody": "host",
"context_paths": ["src/retry.py", "tests/test_retry.py"]
}
Run the gate, then read the verdict before you spend capacity. A pass does not mean the model is right. A pass means your lines are still drawn.
python3 review_free_path.py job.json
python3 review_free_path.py job-bad.json
A clean manifest should print PASS and the task id. A bad manifest should print BLOCK and the crossed line. Keep both files so the drill stays repeatable.
Break the sample on purpose so you trust the gate. Point apply_site at server and expect a block. Add a secret-like path and expect a second block.
That drill is the architecture review, not a quality demo. You are testing your lines, not the model. The free server stays idle until the gate prints PASS.
What you would change next
After the gate is boring, split status by domain. Write model state, server state, and repo state in three fields. Do not let one field stand in for the others.
Next, cap the pack by an explicit file list. If the task needs a fourth file, you edit the list. You do not let a tool widen the list in silence.
Next, store the proposal hash beside the task id. You can drop the proposal without dropping the task. The task remains yours even if the free call dies.
Next, treat a free-server build as optional evidence. If the server vanishes, your local tests still run. The missing log is a server-domain failure, not a repo failure.
Do not add a scheduler that retries every domain together. A combined retry hides which line actually broke. You want a small retry that names its domain.
Who should leave this path alone
Skip this path if the repo holds regulated data. Skip it if you cannot read every file you might send. Skip it if a failed build must page someone at night.
A free server is a poor home for that pager duty. Skip it when you need a verified quota, duration, or hardware spec. Write those facts down only after you check them yourself.
This review does not prove the free offer will remain. It does not measure speed, quality, or uptime. It only checks whether your path respects the lines.
You can try the free model path on a throwaway repo. Run the gate before you touch the free server option.
Top comments (0)