Last Friday your intern left a coding agent running overnight on the shared lab machine you all treat as a scratch box. Monday you open the branch and the patch looks plausible, tests are green, and nobody can say which prompt pack produced it. The free runtime has already moved on to another teammate's job, and the previous session log was rotated out. You are not blocked by missing talent so much as by a missing name on the wiki for this run.
Why a pin owner is not a diff signer
A diff signer attests that a patch is acceptable to merge after a human has actually read the change. A pin owner attests something earlier and quieter: which runtime, prompt pack, and input corpus created the candidate. Those jobs collide on small teams, and then Friday's agent output becomes Monday's folklore instead of an engineering artifact. You separate those jobs so a green test suite cannot hide an unrepeatable sandbox session from later review.
Shared free runtimes make the gap worse because the kitchen keeps changing cooks while you are asleep. If your lab already shares free model access and a free server, treat that box as a rented kitchen, not a personal workstation. Disclosure: This article was prepared as part of MonkeyCode's product outreach, and the product notes below stay limited to those two availability claims. MonkeyCode can host that shared lab with free model access and a free server option the whole team can reach.
You still need a named person who pins each run, because a free shared runtime will not pin itself. Write the four jobs on one wiki page so a weekend intern can follow them without a meeting. Keep the names human, because a channel mention is not ownership when the log has already rotated. Rotate the pin owner weekly if the lab is busy, but never leave the line blank during a run.
Four jobs in the handoff
You treat the handoff as a checklist, not a standup topic that dissolves after the call. Fill these four lines before the agent starts, and refuse to export files if any line is still empty. Read them aloud once if the intern is new, because the names are the whole control.
- You name a Pin Owner who writes the pin file before any agent output leaves the shared box.
- You name a Transcript Owner who archives the session log beside that pin, even when the log is messy.
- You name a Contention Owner who grants a time window on the free server and records who occupies it.
- You name a Promotion Gate who may move pinned artifacts toward review and must refuse unpinned ones.
These four names can be the same human on a two-person team, and that is still better than nobody. The wiki should show the current names at the top, plus the next rotation date in plain text. If a run spans a rotation, the original pin owner keeps the run until promotion or discard is recorded.
Paste this one-page wiki SOP
Copy the block below into your team wiki and fill the bracketed fields before the next shared agent session. Keep it to one page so people actually read it, and link the pin.json path from the run ticket. Do not replace this page with a slide deck, because decks do not travel with the intern at midnight.
# Shared free agent runtime — pin SOP
## Current roster (update weekly)
- Pin Owner: [name]
- Transcript Owner: [name]
- Contention Owner: [name]
- Promotion Gate: [name]
- Next rotation: [date]
## Purpose
A pin records which prompt pack, input pack, git SHA, and occupancy window produced a sandbox artifact.
Unpinned exports are folklore. They do not enter review.
## Before you occupy the free server
1. Ask the Contention Owner for a window, then write it on the ticket and in CONTENTION_WINDOW.
2. Set PIN_OWNER to your roster name. A handle in chat does not count.
3. Freeze the prompt pack and input pack directories. Do not edit them after the pin is written.
4. Run `python3 pin_run.py [run-id]` and confirm pin.json exists before launching the agent.
5. Start a transcript (`script` or `tee`) and leave it running until the agent stops.
## During the run
- Do not reuse the box for a second job inside someone else's window.
- If the runtime becomes unreachable, stop and record the failure on the ticket. Do not invent a pin after the fact.
- If you change prompts, you start a new run-id. You never amend a live pin.
## After the run
1. Transcript Owner stores `session.transcript.txt` next to `pin.json`.
2. Pin Owner confirms hashes still match the trees on disk.
3. Promotion Gate chooses promote, re-run, or discard using the table in the runbook.
4. Only then may a diff signer review a patch.
## Refuse list
- No pin.json beside artifacts/
- No human name on PIN_OWNER
- Transcript missing or truncated before the final agent message
- Customer data, secrets, or production credentials in the transcript
- Production incident work on the shared free server
A runnable pin file you can check in
Check in a tiny helper so pinning is a command, not a memory test after a long agent loop. The script below is a local proposal you run in your repo; it does not talk to any hosted API. It hashes the prompt pack and input pack, records git HEAD, and refuses to write a pin without a human name. You should still copy the session transcript beside the pin, because hashes cannot reconstruct a lost chat log.
#!/usr/bin/env python3
"""Write pin.json for a shared agent run. Local helper only."""
import hashlib
import json
import os
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
def sha256_tree(root: Path) -> str:
digest = hashlib.sha256()
if not root.exists():
return 'missing'
files = sorted(path for path in root.rglob('*') if path.is_file())
for path in files:
rel = path.relative_to(root).as_posix().encode()
digest.update(rel)
digest.update(bytes([0]))
digest.update(path.read_bytes())
return digest.hexdigest()
def git_sha() -> str:
try:
return subprocess.check_output(['git', 'rev-parse', 'HEAD'], text=True).strip()
except Exception:
return 'not-a-git-repo'
def main() -> int:
run_id = sys.argv[1] if len(sys.argv) > 1 else datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')
prompt_dir = Path(os.environ.get('PROMPT_PACK', 'prompts'))
input_dir = Path(os.environ.get('INPUT_PACK', 'inputs'))
out = Path(os.environ.get('PIN_PATH', 'pin.json'))
pin = {
'run_id': run_id,
'created_at_utc': datetime.now(timezone.utc).isoformat(),
'git_sha': git_sha(),
'prompt_pack_sha256': sha256_tree(prompt_dir),
'input_pack_sha256': sha256_tree(input_dir),
'hostname': os.uname().nodename if hasattr(os, 'uname') else 'unknown',
'pin_owner': os.environ.get('PIN_OWNER', ''),
'contention_window': os.environ.get('CONTENTION_WINDOW', ''),
'notes': os.environ.get('PIN_NOTES', ''),
}
if not pin['pin_owner']:
print('Set PIN_OWNER to a real human name before export.', file=sys.stderr)
return 2
out.write_text(json.dumps(pin, indent=2) + '\n')
print('wrote', out)
return 0
if __name__ == '__main__':
raise SystemExit(main())
Set the owner and window in the shell, then generate the pin before you launch the agent loop. If the command exits with status 2, you forgot the human name and you must not export artifacts yet. Commit pin.json with the branch, or attach it to the ticket if the branch must stay free of lab noise. Either place is fine so long as the Promotion Gate can find the pin without asking in chat.
export PIN_OWNER='sam.lee'
export CONTENTION_WINDOW='2026-09-16T14:00Z/2026-09-16T16:00Z'
export PROMPT_PACK='./prompts'
export INPUT_PACK='./fixtures'
python3 pin_run.py weekend-lab-47
test -s pin.json || { echo 'pin missing'; exit 1; }
# Proposal: capture a transcript beside the pin.
script -q session.transcript.txt
# ... launch your agent in this shell ...
exit
ls -l pin.json session.transcript.txt
Gate the export with a test
Add a cheap test so CI fails when someone copies an artifacts directory without a pin file sitting beside it. This does not prove the run is correct; it only proves somebody stopped long enough to name the run. Label it as a process test, and keep it out of unit test counts that you use for product quality.
# test_pin_gate.py — process test, not a product quality test
from pathlib import Path
def test_artifacts_require_pin():
artifacts = Path('artifacts')
if not artifacts.exists():
return
pin = Path('pin.json')
assert pin.is_file() and pin.stat().st_size > 0, (
'exporting artifacts without pin.json is forbidden'
)
How you promote a pinned run
Promotion is a separate hour from generation, even when the patch is small and the author is impatient. Walk the steps in order, and send the run back to the sandbox if any step cannot be answered from the pin. You do not debate taste at this stage; you only decide whether the sandbox output is eligible for review.
- You open pin.json and confirm the Pin Owner name matches a real person on the current wiki roster.
- You verify prompt and input hashes still match the trees on disk, or you record that the trees have moved.
- You skim the transcript for secrets, customer data, and licenses the intern was not allowed to paste.
- You replay or re-run only if the pin says the model access and server window are still the same kitchen.
- You hand the diff to the signer only after the Promotion Gate writes promote or discard on the ticket.
Use the table when people argue about re-running versus shipping, because argument without a pin is only folklore. The table is a discussion aid, not a compliance control, and you should say that on the wiki page. If two rows apply at once, choose the more conservative action and leave a note for the next pin owner.
| Situation | Action | Owner |
|---|---|---|
| pin.json missing | Discard the export. Do not review the diff. | Promotion Gate |
| Hashes match and transcript is present | Allow human review of the diff. | Promotion Gate, then diff signer |
| Hashes no longer match the trees | Re-run under a new run-id, or discard. | Pin Owner |
| Contention window expired and the server was reused | Treat as unreproducible and re-run. | Contention Owner |
| Secrets or customer data in the transcript | Delete artifacts and rotate the exposed secret. | Transcript Owner |
Limitations and who should skip this
A pin is a lab note, not a cryptographic proof that a vendor runtime stayed frozen underneath you. Free model access and a free server can change behavior without a notice that your hash will ever see. The helper does not record GPU SKUs, quotas, model names, or uptime, because those claims would be invented here. You will still lose runs when disks rotate, so the transcript copy matters as much as the hash.
Skip this ritual if you work alone on one laptop and you can already replay every command from your shell history. Skip it if your team already runs experiment tracking with dataset hashes, runtime snapshots, and mandatory export gates. Do not use it as evidence in a regulated audit, because a wiki SOP cannot stand in for a controlled environment. Do not use a shared free server for production incident work, customer data, or anything that needs a locked network.
Shared agent labs fail in boring ways: missing names, rotated logs, and patches that nobody can honestly replay. Name a pin owner before the next overnight intern run, and keep the one-page SOP where the intern will actually look. If the wiki line is filled, Monday becomes a review problem instead of a ghost-story problem about a vanished runtime.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Top comments (0)