DEV Community

Sam Rivera
Sam Rivera

Posted on

Build a Handoff Card Before a Free-Tier CLI Leaves Your Laptop

I want to hand a friend one small CLI tonight. I still lack a host log and a ceiling line. Those two gaps are enough to ban the share.

A laptop pass is not a real handoff. A free server can sleep, and a free model can wander. I want a fail-closed card before I paste any repo link.

The job of the card

This card does not try to grade model quality. It answers one narrower question for a solo builder. Can another person run one task and stop cleanly?

You copy the checker, fill one JSON file, and run it. A missing field exits with code 2. A soft warning would only train you to ignore it.

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

MonkeyCode is the free-model lane and free server in this walkthrough. I am not stating a quota, a machine size, or a lasting plan. Those facts belong on the live console, not in a blog sentence.

If you cannot screenshot the ceiling today, take the ban. Leave that field blank and let the checker refuse you. A remembered number from a post is not evidence.

Gates you can actually fail

Read each gate out loud before you edit the JSON. If you cannot point at evidence, the gate is closed. Hope is not a field in this file.

  1. Name the task in one sentence with one outcome. A second outcome means you need a second card.
  2. Lock the paths the tool is allowed to touch. Any extra path in git status fails this gate.
  3. Record the free-model ceiling you saw on today's console. An empty ceiling fails this gate on purpose.
  4. Name the free server as the host under test. Write when you abandon it if the host sleeps.
  5. Save the dry-run command and prove it refused writes. A dry-run that writes files is just a normal run.
  6. Feed one known-bad input and store the refusal log. A quiet success on garbage fails this gate.
  7. Name one command that restores the worktree cleanly. If rollback needs a hero, you are not ready.

Would you skip gate three because the console felt fine? That skip is the bug this checker exists to catch. A tired builder should not negotiate a blank field.

What proves the dry-run actually refused writes? A clean status log, saved beside the command, proves it. Your memory of a green terminal does not prove it.

Who rolls this back if you are offline tomorrow? A friend can, but only with a command you already rehearsed. If the answer is only you, the tool is not shared yet.

Evidence each gate must carry

A gate without a pasteable proof is still closed. Write the proof in the JSON, not in a chat scroll. If the proof lives only in your head, it does not count.

  1. Task evidence is the sentence a friend can repeat. If they add a second job, the card is already wrong.
  2. Path evidence is the short status after a dry-run. An empty status is the proof you actually wanted.
  3. Ceiling evidence is a same-day line from the console. A blog number, including any in this post, is not proof.
  4. Host evidence names the free server and the abandon trigger. Sleep, a blank ceiling, or a dropped session all count.
  5. Dry-run evidence is the command plus a clean status. A written file means you failed closed too late.
  6. Fixture evidence is the bad input and the exit code. Exit code 0 on garbage means the tool is unsafe.
  7. Rollback evidence is a command you already ran once. Untested rollback text is only a wish.

Is a blank ceiling really safer than a wrong number? Yes, because a blank gets banned and a rumor gets shipped. A copied figure from an old post is worse than empty.

A friendly model will agree with a bad edit if you let it. That is the yes-man failure, and the fixture is the antidote. Retrying the same prompt is not evidence of a fix.

Fill the card in order

Do these steps on a clean branch only. Stop at the first blank field you hit. Do not backfill a number from memory tomorrow.

  1. Write the task sentence and the allowed path list.
  2. Open the free-model console and copy today's ceiling line.
  3. Mark the free server as host and write the abandon rule.
  4. Run the dry-run and confirm that no file changed.
  5. Run the bad fixture and paste the refusal log.
  6. Write the rollback command and rehearse it once locally.
  7. Run the checker and keep exit code 2 until every field is real.

How long should this small handoff take you? Give it ninety minutes, then stop for the night. A second evening means the tool is not small enough yet.

The checker, labeled as a template

This script is a proposal you can run locally. It is not a benchmark, and it is not a hosted service. It only checks that required fields exist and flags are strict.

It does not read your worktree or call any model. You can still lie in a string field and earn a pass. The ban helps a tired builder, not a hostile one.

#!/usr/bin/env python3
"""Fail-closed handoff card. Template: fill fields from your own run."""
import json
import sys
from pathlib import Path

REQUIRED = [
    "task",
    "allowed_paths",
    "model_ceiling_seen",
    "ceiling_source",
    "host_kind",
    "abandon_rule",
    "dry_run_cmd",
    "dry_run_refused_writes",
    "bad_fixture_log",
    "rollback_cmd",
]

def load_card(path):
    data = json.loads(Path(path).read_text())
    missing = [key for key in REQUIRED if data.get(key) in (None, "", [])]
    return data, missing

def main():
    if len(sys.argv) != 2:
        print("usage: handoff_card.py card.json")
        return 2
    data, missing = load_card(sys.argv[1])
    if missing:
        print("BAN: missing evidence")
        for key in missing:
            print(f"- {key}")
        return 2
    if data["dry_run_refused_writes"] is not True:
        print("BAN: dry-run did not refuse writes")
        return 2
    if data["host_kind"] != "free_server":
        print("BAN: this card is only for a free server handoff")
        return 2
    paths = data["allowed_paths"]
    if not isinstance(paths, list) or not paths:
        print("BAN: allowed_paths must be a non-empty list")
        return 2
    print("PASS: one-task handoff may leave your laptop")
    print(data["task"])
    return 0

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

A pass shape, with placeholders called out

Replace every placeholder before you trust a PASS line. Shipping the sample JSON would be cheating the gate. The sample only shows the expected shape, nothing more.

{
  "task": "rewrite the README usage block only",
  "allowed_paths": ["README.md"],
  "model_ceiling_seen": "paste-console-line-from-today",
  "ceiling_source": "provider console, same calendar day",
  "host_kind": "free_server",
  "abandon_rule": "stop if the host sleeps or the ceiling line is blank",
  "dry_run_cmd": "python3 tool.py --dry-run --path README.md",
  "dry_run_refused_writes": true,
  "bad_fixture_log": "empty diff requested; tool exited 2; worktree clean",
  "rollback_cmd": "git checkout -- README.md"
}
Enter fullscreen mode Exit fullscreen mode

Commands worth pasting into the README

Put this short sequence above the fold in the README. Your friend should not invent flags at midnight. Three commands are enough for the first careful share.

python3 handoff_card.py card.json
python3 tool.py --dry-run --path README.md
git status --short
Enter fullscreen mode Exit fullscreen mode

Did status show a file outside the allowed list? Stop, fix the tool, and rebuild the card. A surprise file is a failed scope gate, not a nit.

The bad card you should keep

Store this fixture next to the checker in the repo. It looks nearly done, which is why it is dangerous. Your checker must ban this file on every run.

{
  "task": "rewrite the README usage block only",
  "allowed_paths": ["README.md"],
  "model_ceiling_seen": "",
  "ceiling_source": "",
  "host_kind": "free_server",
  "abandon_rule": "stop if the host sleeps",
  "dry_run_cmd": "python3 tool.py --dry-run --path README.md",
  "dry_run_refused_writes": false,
  "bad_fixture_log": "",
  "rollback_cmd": "git checkout -- README.md"
}
Enter fullscreen mode Exit fullscreen mode

Run both lines and expect a hard ban. Exit code 2 is the success case for this fixture. A pass here means you delete the checker, not the fixture.

python3 handoff_card.py bad_card.json
echo $?
Enter fullscreen mode Exit fullscreen mode

A small decision table

Use this table when you feel the urge to negotiate. The left column is the excuse you will hear. The right column is the only allowed move.

Excuse you will hear Required move
Yesterday's console note is not today's evidence. Recopy today's ceiling line or accept the ban.
A probable refusal is not a saved dry-run log. Re-run the dry-run and keep the new log.
Usual uptime is not a written abandon rule. Write the abandon rule or stop the share.
The bad input feels too silly to keep around. Keep it, because quiet passes are the real bug.
An obvious rollback still needs a written command. Write that command before you share the repo.

What a PASS still does not mean

A pass means the card is complete, not that the diff is right. You still read the README change with your own eyes. The checker never opened your files and never will.

It also does not freeze the free tier in place. Free model access and a free server can change quietly. That is why the ceiling source must include the day.

Next week you fill a new card or you do not share. I am not naming a model or quoting a token pack. I am not quoting a region, a chip, or a speed number.

If a post states those without today's primary page, treat it as stale. Your card should cite the console you saw, not this paragraph. Stale numbers are how a small share becomes a bad promise.

Who should not use this card

Skip this card if paying users depend on the CLI. One JSON file is a solo handoff, not a release train. You need owners, alerts, and a real rollback drill.

Skip this if the change touches secrets or production data. The fixture assumes a README-sized edit and nothing wider. A wider blast radius needs a different, stricter gate.

Skip this if you cannot rehearse rollback in one command. Sharing a tool you cannot undo turns favors into incidents. Keep that build on your laptop until rollback is boring.

Cost and time boundary

Budget ninety minutes and add zero new services. The checker is one file, and the card is one file. If you are writing a dashboard, you left the experiment.

Abandon the share when the free server will not stay awake. Abandon it when the free-model console hides the ceiling. Your local demo can remain a local demo without shame.

That is a clean exit, not a failure of nerve. Small tools need a stop rule more than they need a sequel. Write the stop rule on the card before you feel brave.

Before the next iteration

Which blank field shows up first on a free server? I want the ceiling line, the dry-run proof, or the fixture log. That answer changes the next checker, not a slogan around it.

MonkeyCode is one place offering that free model lane and free server. Read the live limits before you copy any number down. Then let the checker ban you when the evidence is thin.

Top comments (0)