Name a Data Boundary Keeper: A One-Page Wiki SOP for What Leaves Your Laptop
The failure mode this playbook prevents
The opening story is a composite scenario, not a specific incident I can cite.
Imagine your team gets free remote capacity for an agent session and moves fast to use it. On Thursday a teammate asks the agent to "make the failing auth test pass" and hands over the repository context, which quietly includes .env.staging. The session succeeds, the test passes, and a transcript containing the staging database URL lands in a shared channel three hours later. Nobody was careless in a dramatic way; the workflow simply had no named person who owned the sentence "this may leave the laptop."
That story is a composite, but the shape of it is familiar to anyone who watched remote AI tooling spread through a team faster than its rules did. The fix is not a smarter model or a stricter vendor. It is one named owner, one committed config file, and one command that runs before any context is uploaded.
Why the usual controls do not cover this
Most teams already have secret scanning at commit time and access reviews at quarter end, and both are genuinely useful. Neither answers the question a remote session raises, which is: what bytes are we about to send outside the building?
Local tooling makes that question invisible because nothing leaves your machine. Remote model access and hosted agent servers turn it into a per-task decision, and per-task decisions without an owner drift within a week. That is why a reviewer who checks "did we scan the repo" will keep missing the actual gap.
So treat the boundary as a routing problem rather than a trust problem. You are not deciding whether a provider is trustworthy; you are deciding which classes of data may go there, and who signs each decision.
Step 1 - Classify every task with a routing table
Write the table once, paste it into the wiki, and refuse to relitigate it during incidents. The right-hand column matters more than the middle one, because a rule without a signer is only a suggestion.
| Data class | Typical files | Allowed destination | Signer |
|---|---|---|---|
| Public | Open-source code, published docs | Any model, any host | Task Author |
| Internal, no secrets | Private source, internal docs | Remote model or hosted server, after the check passes | Boundary Keeper |
| Secrets |
.env*, keys, service accounts, dumps |
Local session only | Boundary Keeper + Restore Reviewer |
| Regulated | Customer PII, health, payment data | Local only; this SOP is not sufficient | Platform or legal owner |
Two rules keep the table honest over time. If a file is not on the allow list, it counts as secrets by default until the Keeper moves it. And if you cannot name the signer at that moment, the answer is local, not "probably fine."
Step 2 - Name four roles and one handoff line
Roles fail when they are fuzzy, so give every role exactly one verb and one artifact.
- Task Author - describes the task, lists the minimum files the session needs, and never widens that list mid-run.
-
Boundary Keeper - owns
.agentboundary.toml, runs the pre-flight check, and is the only person who edits the allow list. - Session Runner - starts the remote session with the approved file set only, and stops it when the ticket closes.
- Restore Reviewer - reads the audit log weekly and confirms blocked patterns were fixed or promoted deliberately.
The handoff between Author and Keeper is a single line appended to the ticket, and it is the artifact auditors actually ask for later:
route=remote-ok keeper=@alex rule=v3 files=7 bytes=184320 at=2026-09-15T09:12:04Z ticket=ENG-4821
Keep that line out of chat and inside the ticket, so the decision survives the next reorg. A grep-friendly format beats a paragraph of prose describing what everyone agreed to.
Step 3 - Commit a boundary file
Put the policy inside the repository instead of inside someone's memory. This file is intentionally boring: globs, size caps, and secret patterns that reviewers can read in one pass.
# .agentboundary.toml
version = 3
[allow]
globs = ["src/**/*.py", "tests/**/*.py", "docs/**/*.md", "pyproject.toml"]
max_file_bytes = 200000
max_total_bytes = 2000000
[deny]
globs = ["**/.env*", "**/*.pem", "**/*.key", "**/id_rsa*", "**/secrets/**",
"**/fixtures/prod/**", "**/*.sqlite", "**/*.parquet"]
[secrets]
patterns = ["AKIA[0-9A-Z]{16}", "sk-[A-Za-z0-9]{20,}", "-----BEGIN [A-Z ]*PRIVATE KEY-----"]
entropy_threshold = 4.0
min_token_length = 24
Deny always wins over allow, and the size caps matter because context is not free on any tier. The 200 KB per-file cap is arbitrary but enforceable, which is the point; choose your own number and keep it where a reviewer can see it.
Step 4 - Run the pre-flight check
The script below is a reference implementation you can adapt rather than a tool I ran against a live service while writing. It requires Python 3.11 or newer because it reads TOML with tomllib from the standard library.
#!/usr/bin/env python3
"""boundary_check.py - pre-flight gate before a remote agent session.
Reads .agentboundary.toml, checks a candidate file list, prints a verdict,
and appends one audit line. Exit codes: 0 = remote-ok, 2 = blocked, 3 = usage.
"""
from __future__ import annotations
import fnmatch, math, os, re, sys, tomllib
from collections import Counter
from datetime import datetime, timezone
from pathlib import Path
CONFIG = Path(".agentboundary.toml")
AUDIT = Path(".agentboundary.audit.log")
def shannon_entropy(value: str) -> float:
counts = Counter(value)
length = len(value)
return -sum((n / length) * math.log2(n / length) for n in counts.values())
def matches_any(rel: str, globs: list[str]) -> bool:
return any(fnmatch.fnmatch(rel, g) for g in globs)
def scan(path: Path, cfg: dict) -> list[str]:
problems: list[str] = []
try:
text = path.read_text(encoding="utf-8")
except (UnicodeDecodeError, OSError):
return [f"{path}: not UTF-8 text, treat as local-only"]
for pattern in cfg["secrets"]["patterns"]:
if re.search(pattern, text):
problems.append(f"{path}: matched secret pattern {pattern}")
min_len = cfg["secrets"]["min_token_length"]
for token in re.findall(r"[A-Za-z0-9+/=_\-]{%d,}" % min_len, text):
if shannon_entropy(token) >= cfg["secrets"]["entropy_threshold"]:
problems.append(f"{path}: high-entropy token, review before sending")
return problems
def main(argv: list[str]) -> int:
with CONFIG.open("rb") as fh:
cfg = tomllib.load(fh)
raw = argv or (sys.stdin.read().split() if not sys.stdin.isatty() else [])
if not raw:
print("usage: boundary_check.py FILE [FILE...] (or pipe a file list on stdin)")
return 3
blocked: list[str] = []
total = 0
for name in raw:
path = Path(name)
rel = path.as_posix()
if matches_any(rel, cfg["deny"]["globs"]):
blocked.append(f"{rel}: denied by glob")
continue
if not matches_any(rel, cfg["allow"]["globs"]):
blocked.append(f"{rel}: not on the allow list, ask the Boundary Keeper")
continue
size = path.stat().st_size
if size > cfg["allow"]["max_file_bytes"]:
blocked.append(f"{rel}: {size} bytes over the per-file cap")
continue
total += size
blocked.extend(scan(path, cfg))
if total > cfg["allow"]["max_total_bytes"]:
blocked.append(f"total payload {total} bytes over cap")
verdict = "BLOCK" if blocked else "REMOTE_OK"
stamp = datetime.now(timezone.utc).isoformat(timespec="seconds")
line = (f"{stamp} verdict={verdict} keeper={os.environ.get('BOUNDARY_KEEPER', 'unset')} "
f"files={len(raw)} bytes={total}")
with AUDIT.open("a", encoding="utf-8") as fh:
fh.write(line + "\n")
print(line)
for item in blocked:
print(f" - {item}")
return 2 if blocked else 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))
Wire it into the ticket workflow with two commands, one for a quick audit of the whole tree and one for the exact file set a session will use:
# Audit what the tree currently contains
git ls-files -co --exclude-standard | BOUNDARY_KEEPER=@alex python3 boundary_check.py
# Approve one ticket's minimal payload
BOUNDARY_KEEPER=@alex python3 boundary_check.py src/agent/runner.py tests/test_runner.py
echo "exit=$?"
A blocked run should look boring and specific, which is what makes it actionable:
2026-09-15T09:12:04+00:00 verdict=BLOCK keeper=@alex files=7 bytes=0
- .env.staging: denied by glob
- tests/fixtures/urls.txt: high-entropy token, review before sending
Step 5 - Paste the one-page run into the wiki
A numbered run that fits on one screen beats a policy document nobody opens during a deadline push.
- Task Author opens the ticket and lists the minimum files the session requires.
- Boundary Keeper confirms each path against the routing table and runs the check.
- If the verdict is BLOCK, Author trims the payload or swaps secrets for fixtures.
- Keeper appends the handoff line and approves with an explicit timestamp.
- Session Runner starts the remote session with only those paths available to it.
- Runner closes the session at ticket close; no long-lived background loops.
- Restore Reviewer reads the weekly audit log and proposes config changes as pull requests.
- Anyone may revoke an approval; stop the session first, then ask questions.
Steps five and six are where most leaks happen in practice, because a session left running keeps reading whatever the working tree happens to contain. If your team only remembers one line from this article, remember that one.
Limitations, and who should not use this
Be honest about the ceiling here. Glob rules and entropy checks catch careless mistakes; they do not inspect what happens to data after upload, and they cannot enforce provider-side retention or training policies.
Entropy heuristics also cut both ways. Minified bundles and base64 fixtures trip the threshold, while a short but valid credential can slip underneath it, so expect to tune min_token_length for your repository instead of trusting the default. Treat every BLOCK as a conversation starter, not a verdict from a scanner.
The SOP is a social control, not a sandbox. If you need a hard technical boundary, put an egress proxy or a DLP tool in front of the session and keep this file as the human-readable companion.
Do not use this approach on its own for regulated data, contractual restrictions, or anything your security team classifies as sensitive. If you cannot get a named Boundary Keeper with real authority to say no, writing the role down will not change anything.
Where a free remote session fits into the workflow
MonkeyCode is relevant here because the project offers free model access and a free server option, and the free server option is exactly the case this playbook was written for: the session runs somewhere other than your laptop. The operator states an allowance of 10 million free tokens, so verify the current terms on the project itself before you plan capacity around it.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
A sane first run on any free tier looks like this. Pick one small ticket, commit .agentboundary.toml with a conservative allow list, run the checker, and send only the approved paths into the session. Then compare the audit log against what the session actually touched, and tighten the file before you widen it.
Most teams discover the same thing at that point, which is that the boundary file is the cheap part and the named owner is the hard part. If you want to try the workflow, start with the checker on a single ticket rather than migrating an entire repository into a hosted session.
Top comments (0)