After this guide, your chief of staff can run under a default-deny shell allowlist that names entry-point scripts rather than interpreters, and treat every block as a decision point — run the one-off by hand, add an entry only for the routine.

The problem

If you run a personal chief-of-staff system, you already govern it with a constitution: charters, decision records, scope rules. That’s the layer most teams build, and it’s genuinely good. But every one of those documents is, mechanically speaking, prose addressed to a language model. A charter tells the assistant what it should do. Nothing in prose binds what it could do.

This matters because the assistant runs commands. A prompt-injected message, a misread instruction, an over-eager generalization from one approved action to a family of similar ones — any of these can produce a shell command no charter anticipated. When that happens, the question “did the charter allow this?” is settled after the fact, by a human reading a log. The action has already run.

A prompt is not an enforcement mechanism. Enforcement lives in the execution layer, and in most assistant setups the execution layer is wide open: the model can invoke the shell, and the shell can do anything the user could do.

The philosophy behind the choice

Under the trusted chief of staff sits a hard permission floor: a default-deny shell with an explicit allowlist of permitted command patterns. Vault edits, reads, searches, and the approved delivery flows run freely. Everything else is blocked mechanically — before execution, regardless of what the model intended, regardless of how the instruction reached it.

Three properties make this the right shape:

It is interpretation-free. The allowlist doesn’t reason about intent. It matches command patterns. A prompt injection that convinces the model it must urgently run some never-approved command simply fails, the same way a wrong password fails. The model’s sophistication is irrelevant to the check, which is exactly the point — the check exists for the cases where the model’s sophistication is pointed the wrong way.

It inverts the default. Most permission systems are deny-lists: block the scary commands, allow the rest. That fails because you can’t enumerate scary. curl is fine when fetching docs and not fine when exfiltrating files. Default-deny flips the burden: you enumerate the good, which is finite and known, and everything unanticipated — the entire class of commands you didn’t think of — is blocked by construction.

The friction is the feature. A default-deny floor means every genuinely new capability passes through a human decision: the assistant hits the block, the block is visible, and the principal decides whether to widen the rules or to just do the thing by hand. That decision point is where scope creep dies. A system with no friction has no moment where a human reconsidered; it just has a growing surface area.

How it’s wired at a high level

The allowlist shape. In the reference system the assistant runtime (a coding agent the chief-of-staff workers run inside) has a config with per-tool permission rules. The shape, anonymized:

  • File edits and reads inside the workspace: allowed. The vault is the workspace; editing it is the job.
  • Paths outside the workspace: denied, with two or three narrow exceptions (a temp directory the triage procedure writes its replies to).
  • Shell commands: a first rule of * → deny, followed by explicit allow patterns for the specific things the system does. Task-database commands. Git. Date. Read-only text tools (cat, ls, grep, head, tail, find). A short list of delivery scripts — the mail desk, the caller, the search scripts — each allowlisted as python3 delivery/<script>.py *, never bare python3 *.

Two details carry most of the safety. First, scripts, not interpreters: the allowlist names individual entry-point scripts, so the assistant can run the sanctioned mail or call tooling but cannot run arbitrary Python. Second, the deny-all default is first and everything else is an exception, so adding a capability is always a conscious diff against a baseline of nothing.

New capabilities get added by decision, not by need. When the system legitimately needs a new command — a new helper, a new script — the change is a one-line allowlist addition, made in a session where the human can see it, ideally alongside the decision record that says why. The allowlist lives in version control like everything else, so its history reads as the story of what the assistant was ever trusted with.

The honest cost, and a real example. Blocks on legitimate work are real and frequent early on. The instructive case from the reference system: the assistant needed to make an outbound API call — a one-time registration request to a new external service. The allowlist had no pattern for it. The call was blocked, mechanically, even though the intent was fine and the principal was standing right there. The resolution was not to widen the rules on the spot. The principal ran the call by hand instead, and handled the resulting credential himself, storing it outside the repository per the system’s standing rules. The block had surfaced a decision that mattered — a first contact with a new external service, plus a new secret — and made it a human decision.

That’s the pattern to internalize. When the allowlist stops something legitimate, the default response is run it by hand, not add it to the list. Allowlist entries should be added when a capability is routine — part of a flow you’ll want the assistant doing unattended. One-off actions with side effects outside the vault are precisely what should stay manual.

What your chief of staff should be able to do afterwards

  • Add a default-deny shell allowlist to your assistant runtime’s configuration, with edits allowed in the workspace, external paths denied with narrow exceptions, and delivery tooling allowlisted as named scripts rather than bare interpreters.
  • Operate the friction loop correctly: when a legitimate action is blocked, choose between running it by hand (default for one-offs) and adding a scoped allowlist entry (for routine flows), and record the addition as a decision.
  • Audit trust as a layered property: the charter layer says what the assistant should do and is read by the model; the sandbox layer says what it may do and is read by the executor. Know which of your protections live in each layer — and be suspicious of anything whose only enforcement is prose.

A chief of staff you trust is not one that never misbehaves. It’s one whose misbehavior cannot execute.

#permissions · #allowlists · #sandboxing · #prompt-injection · #security

Hand this to your chief of staff. Plain Markdown: /guides/contributed/the-sandbox-constitution.md. Tell it: "Read this guide and tell me what in our system it would change."