Three layers in lemon-code: what never runs, what depends on the permission mode, and what always goes through you
Published: October 28, 2026
Reading time: 9 min
Series: lemon-code in 30 days, part 5 of 13
The CLI's --yolo flag selects bypassPermissions, the most permissive mode. It skips permission prompts, but the blocklist still applies: if the model proposes rm -rf ~, the answer is no.
That refusal doesn't come from the model or from a prompt asking it to be careful. It comes from a rule in code that no permission mode can turn off. This post shows how lemon-code stacks guardrails in three layers and why their order matters.
--yolo selects bypassPermissions.plan is read-only; dontAsk denies actions that would require approval.Picture an office building. The front desk has a list of things that never get in, badge or not. Then your badge decides which floors you can reach. And to enter the vault, someone has to open the door with you.
The front desk is the first layer. It sits before everything, so no badge overrides it.
// minimal destructive blocklist (rewritten and simplified)
const DESTRUCTIVE: Array<{ pattern: RegExp; reason: string }> = [
{ pattern: /\brm\s+-rf\s+\/(\s|$)/, reason: "wipe root" },
{ pattern: /\brm\s+-rf\s+(~|\$HOME)(\s|$)/, reason: "wipe home" },
{ pattern: /\bmkfs\b/, reason: "format partition" },
{ pattern: /\bdd\b.*\bof=\/dev\/(sd[a-z]|hd[a-z]|nvme\d|disk\d)\b/i, reason: "write to block device" },
];
export function isDestructive(command: string) {
const hit = DESTRUCTIVE.find((e) => e.pattern.test(command.trim()));
return hit ? { blocked: true, reason: hit.reason } : { blocked: false, reason: "" };
}
console.log(isDestructive("rm -rf ~")); // { blocked: true, reason: "wipe home" }
console.log(isDestructive("rm -rf ./dist")); // { blocked: false, reason: "" }
The function doesn't take the mode as input. Configuration can't relax it, on purpose.
Free and paid products to turn ideas into a foundation you can actually ship.
13 products availableContinue exploring similar topics
I reached for an HTTP provider on tasks an installed CLI could handle. lemon-code's CLI-first rule fits in four lines of precedence.
For HTTP-provider routes, lemon-code records score factors. This teaching example shows how to read the sum and distinguish it from the JEV layer.
lemon-code has six ADRs numbered 0049, all created on the same day. That mistake teaches more about project memory with multiple agents than any well-numbered ADR.
A practical checklist to validate security, cost, evals, and observability before you ship your AI app to production.
Production-tested templates trusted by developers. Save weeks of setup on your next project.
The DESTRUCTIVE_BLOCKLIST covers catastrophic or irreversible operations: wiping root or home, recursive chmod 777 on root, mkfs, dd writing to a block device, and DROP DATABASE or DROP TABLE without a specific target. It applies even in bypassPermissions.
A regex blocklist is never complete and doesn't replace a sandbox. Its job is catching the gross, cheap-to-detect mistake a confused model might produce at 3 a.m. during an autonomous mission.
| Mode | Behavior |
|---|---|
default | asks before sensitive actions |
acceptEdits | accepts edits inside the project, asks before risky commands |
plan | read-only: read, list, search; writes and execution denied |
dontAsk | never asks; anything needing approval is denied |
bypassPermissions (--yolo in the CLI) | skips permission prompts; the destructive blocklist still applies |
I use plan to explore unfamiliar repos: the agent can read without changing files. dontAsk is not auto-approval; actions that would require confirmation are denied. In the CLI, --yolo selects bypassPermissions.
Depending on the mode and applicable rule, some actions go through you: writes outside the project root, sensitive commands and Git operations like push. The menu offers approve once, for the session, permanently, or deny.
The workspace informs that decision: paths outside the root and protected directories can enter the approval flow. That's a path check, not full process isolation.
Execution guardrails don't help if an API key shows up in output. lemon-code scrubs known secret patterns from tool outputs before reuse and masks configured secrets as [REDACTED] in the terminal and UI. Credential config files receive 600 permissions on POSIX systems on a best-effort basis.
Some path checks already exist. ADR 0024, still proposed, describes stronger executor containment: a workspace jail and explicit rules for protected directories such as .git/hooks. The blocklist and approval flow reduce risk, but they aren't process sandboxing.
dontAsk denies actions that would otherwise require confirmation.Good guardrails are a stack with the hardest layer in front. The blocklist ignores the mode, the mode sets autonomy and approval handles the rest. None of them relies on the model behaving.
Friday's post moves from code to memory: how I use ADRs to keep several agents aligned on one project.
If your team is giving coding agents access to local environments and wants a review of the permission model, that's work I do at LEMON.DEV.