The kitchen light hummed over a closed laptop lid.
A solo founder opened it at twenty-one zero seven.
One billing screen still blocked the Saturday launch.
Stripe tabs glowed beside a mug gone cold.
An agent video promised patches while nobody watched.
That theater needed a card the wallet refused.
The founder did not need a roaming intern.
The founder needed a clerk with one stamp.
A clerk reads a form, writes once, then stops.
Most public agent demos hide a costly loop.
Each retry burns tokens and invents extra files.
A Saturday ship cannot afford that fog.
This workflow treats the model as a clerk.
The clerk receives a touch list and one prompt.
Local tests run hard after that single reply.
No cloud queue waits in another region.
No agent framework sits between git and the patch.
The laptop stays the only machine that matters.
The product was a tiny usage dashboard.
Customers could already log in and see counts.
They could not download a CSV of those counts.
That remaining gap was small and painfully specific.
It lived in two existing TypeScript source files.
It did not need a queue or a new service.
Fence the garden
The founder wrote a touch list before any prompt.
The list named files the clerk could change.
Anything outside that list failed the window.
# touch.allow
src/pages/Usage.tsx
src/lib/usageExport.ts
src/pages/Usage.test.tsx
A touch list is a fence around a garden.
The clerk may pick tomatoes inside the fence.
The clerk may not pave a road outside.
Agent loops look busy and feel like progress.
They retry, replan, and reopen the same wound.
A clerk stamps the form a single time.
The founder saved a prompt with hard edges.
The prompt named the gap and the allowed files.
It banned new dependencies and new cloud calls.
# prompt.txt
Task: add a CSV export on the usage page.
Touch only the files listed in touch.allow.
Reuse the existing usage fetch in src/lib.
Do not add dependencies, queues, or env vars.
Do not create new folders or config files.
Return a unified diff and nothing else.
Short prompts starve the urge to invent scenery.
Long prompts invite extra architecture from a stranger.
The Saturday clerk gets a narrow ticket only.
Stamp once
A small shell script owned the ship window.
It refused a dirty tree and a missing allow list.
It prepared one call, then refused a second.
#!/usr/bin/env bash
# clerk.sh — one shot, then tests. No retry loop.
set -euo pipefail
MINUTES="${1:-90}"
ROOT="$(git rev-parse --show-toplevel)"
cd "$ROOT"
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "dirty tree; commit or stash first" >&2
exit 1
fi
test -f touch.allow
test -f prompt.txt
test -x ./call_once.sh
test -x ./apply_once.sh
test -x ./verify.sh
echo "ship window: ${MINUTES} minutes, one model call"
./call_once.sh
./apply_once.sh /tmp/clerk.diff
./verify.sh
echo "clerk finished; founder still reads the diff"
The clock belongs to the founder, not the model.
Ninety minutes is a hard cap, not an SLA.
When the ninety minutes end, the window is over.
The clerk writes one unified diff to disk.
A tiny filter then checks every touched path.
A second model call is forbidden on purpose.
#!/usr/bin/env bash
# apply_once.sh
set -euo pipefail
DIFF="${1:-/tmp/clerk.diff}"
ALLOW="touch.allow"
test -s "$DIFF"
awk '/^+++ b\// { print substr($0,7) }' "$DIFF" | while read -r path; do
if [[ "$path" == "/dev/null" ]]; then
continue
fi
if ! grep -qxF "$path" "$ALLOW"; then
echo "clerk left the garden: $path" >&2
exit 1
fi
done
if grep -E '^(\+\+\+ b/)(package-lock\.json|pnpm-lock\.yaml|Dockerfile|terraform/)' "$DIFF"; then
echo "clerk tried to pave a road" >&2
exit 1
fi
git apply --check "$DIFF"
git apply "$DIFF"
The garden metaphor stays cheap and strictly local.
A paved road is a new bill in disguise.
The script treats that road as a hard error.
#!/usr/bin/env bash
# verify.sh
set -euo pipefail
npm test -- src/pages/Usage.test.tsx
npx tsc --noEmit
if ! git diff --quiet -- package.json; then
echo "package.json moved; revert and rewrite by hand" >&2
exit 1
fi
Green tests still do not prove product taste.
They prove the clerk stayed inside the fence.
The founder still reads the diff before push.
Accept the slow desk
A closed wallet still needs a place for the prompt.
Paid agent hosts turn a CSV button into a tab.
The founder wanted that tab to stay at zero.
MonkeyCode offered free model access for this clerk call.
It also offered a free server option for the same desk.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
The same files run against a local endpoint.
They also run against any OpenAI-compatible chat URL.
The allow list and the tests remain the source of truth.
A sample call kept the retry count at zero.
The script below posts once and then exits.
Empty bodies fail closed instead of silent retrying.
#!/usr/bin/env bash
# call_once.sh
set -euo pipefail
ENDPOINT="${MODEL_ENDPOINT:?set MODEL_ENDPOINT}"
BODY="$(jq -n --rawfile p prompt.txt '{
messages: [{role:"user", content:$p}],
stream: false
}')"
curl -sS --max-time 120 -X POST "$ENDPOINT" \
-H "content-type: application/json" \
-d "$BODY" \
-o /tmp/clerk.json
jq -r '.choices[0].message.content // .content // empty' \
/tmp/clerk.json > /tmp/clerk.diff
if ! grep -qE '^(diff --git|--- )' /tmp/clerk.diff; then
echo "no diff in clerk body; founder writes it" >&2
exit 1
fi
The response JSON shape still varies across hosts.
The founder kept a small jq fallback on purpose.
If the body lacked a diff, the window failed closed.
No second curl appears anywhere in this script.
Failure means the human writes the patch instead.
That rule is the whole point of a clerk.
The first useful diff changed Usage.tsx in place.
It reused the existing fetch, not a new client.
The test file asserted a CSV header and one row.
// src/pages/Usage.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Usage } from "./Usage";
test("exports a csv with the usage header", async () => {
const user = userEvent.setup();
render(<Usage />);
await user.click(screen.getByRole("button", { name: /export csv/i }));
expect(screen.getByTestId("last-export")).toHaveTextContent("date,count");
});
That test is a receipt, not a novel.
A shop receipt lists items and a total.
The founder reads that receipt the same way.
The clerk tried to add a helpers folder once.
apply_once.sh rejected the path and stopped cold.
The founder reset the tree with git checkout.
git checkout -- src
rm -f /tmp/clerk.diff
# start a new window; do not hide a retry
A hidden retry would paper over the fence.
A new window makes the fence visible again.
The CSV button then shipped quietly before midnight.
No queue, no worker, and no extra vendor row.
The bill for the night stayed a round zero.
The founder accepted slow answers as the tax.
Free model access is not a quality contract.
A clerk can still write a wrong export.
Tests catch crashes, not ugly product copy choices.
A free server option can pause or slow down.
This workflow assumes the founder can wait longer.
It also assumes the founder can patch by hand.
Do not send secrets, tokens, or customer rows.
The prompt holds file names and a public gap.
Anything private stays off the wire tonight.
Skip this approach for any multi-service redesign.
Skip it when compliance needs a paper trail.
Skip it when the change set is unknown.
Teams with a paid agent budget can ignore this.
They already bought the roaming intern on purpose.
A solo founder with a closed wallet stays here.
The method also fails when the allow list lies.
If every file is allowed, the fence is theater.
Keep the list shorter than a grocery note.
The agent video will still play tomorrow morning.
It will still look like a factory after dark.
A Saturday product needs a stamp, not a factory.
The clerk stamps once and the tests speak next.
The founder reads, then pushes, then finally sleeps.
The wallet stays closed through all three steps.
A quiet weekend trial of that free desk is enough.
Keep these scripts as the real control plane.
No extra pitch belongs on a closed wallet.
Top comments (0)