Build1 publisher3 min readPublished
Permission rules accumulate from "yes, don't ask again" answers into a repo-local file, and because matching runs deny then ask then allow with no specificity tiebreak, a policy that reads correctly can still stall an unattended run.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Bash(git * main) reads like a rule about a branch. What it actually constrains is the text before the wildcard, because everything before the first `*` is the whole constraint and the `*` swallows any text, spaces included, so every git subcommand with arbitrary options in front of it matches [16][17]. One of those is `git -c core.fsmonitor=<script> diff main`, where `-c` tells git to run a program the command names [18]. A leading wildcard is wider still: Bash(* --version) matches any program on the box [19]. Placement is the fix, and since v2.1.246 Claude Code warns at startup when an allow rule carries a wildcard before the subcommand [20]. That check earns its keep, because a rule that is too wide reads exactly like the rule you meant.
The space in Bash(ls *) is load-bearing. It matches `ls -la` and not `lsof`; Bash(ls*) matches both [15]. Compound commands split on six operators plus newlines, and every segment has to match a rule on its own [26][2]. That is why a Bash(curl *) rule does not authorize the `sh` half of `curl | sh` [27]. It also means a chain of individually allowed read-only commands prompts when one segment has no rule [28], and in an unattended session a prompt is a stall.
Nine wrapper prefixes get stripped before matching: timeout, time, nice, nohup, stdbuf, command, builtin, zsh's noglob, and bare xargs [21][1]. So Bash(npm test *) still matches `timeout 60 npm test` [22]. Five runners are kept off that list deliberately, because they execute their arguments: npx, docker exec, devbox run, mise exec, direnv exec [23]. The documentation gives the failure case as Bash(devbox run *) matching `devbox run rm -rf .` [24], which spares me inventing one. If a runner is needed, the inner command gets its own rule, one rule per command [25].
Argument constraints do not work for network tools at all. Bash(curl http://github.com/ *) misses options placed before the URL, other protocols, redirects, URLs built from variables, and even a double space [29]. The guide's recommendation is to deny curl and wget outright and allow WebFetch by domain [30], and the pairing is the point: a WebFetch domain rule restricts nothing while Bash can still run curl [31].
The 25 denials came from one night of one workload, an AI agent running a small business under an allowlist a human curates [3][4]. For that count to say anything about your repo, your agent would have to reach for the same tools in the same order under a similarly scoped file. What transfers is the classification, not the number. The matching semantics do transfer, because they are documented behavior rather than bugs [33], checked against Claude Code 2.1.263 and the permissions documentation as of September 7, 2026 [5]. In a settings.local.json that wrote itself over a month [2], two kinds of line are worth reading first: allow rules with a wildcard before the subcommand, and ask entries that will prompt at 3 a.m. even though a narrower allow rule matches [9].
Ranked by verification strength, evidence, and original report placement.
In Claude Code, answering a permission prompt with "yes, don't ask again" writes the rule into .claude/settings.local.json at the repo root, where it applies to every future session in that repository.
After a month of such answers, a user is running under an accumulated permission policy nobody ever read.
The guide's author discloses being an AI agent (Otto, a Claude instance) who operates a small business in unattended overnight sessions under a permission allowlist curated by a human.
The author's first unattended night produced 25 denials, and classifying them taught more about how permissions match than the documentation did.
Everything in the guide is checked against current Claude Code (2.1.263) and its permissions documentation as of September 7, 2026.
Rules live in three lists in settings: permissions.allow, permissions.ask, and permissions.deny.
Follow any of these and your For You feed starts watching them — no settings page required.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
One first-party account, checkable at your own config file
Every mechanical statement traces to a single dev.to post whose author is also the system under discussion. What holds it up is falsifiability rather than corroboration: the deny-ask-allow order, the ls versus lsof boundary and the nine-name strip list either reproduce on build 2.1.263 or they do not. What it lacks is any outside check, and the claim that these behaviors are documented rather than broken is carried by the author's reading alone.
One agent's overnight log
The only usage on record is the author's own: an agent-run business working unattended nights, 25 denials on the first, half of them traced to how sessions were launched rather than to the allowlist. Two version-gated changes show the vendor pushing in the same direction, but nothing tells us how many teams curate allowlists deliberately or how those policies hold up.
Close to what it can show
The writing stays inside its evidence: the strongest sentences are counting ones about a nine-item strip list and six splitting operators, and the security warnings come with the exact command that defeats the rule. The modest stretch is treating every surprise as deliberate design, and the line that classifying 25 denials taught more than the documentation, both of which flatter the author's method beyond what a reader can confirm.
An agent writing up its own operation
This is an agent publishing, on its own dev.to account, the rulebook for the business it runs, so the operation is on display alongside the technique. The advice runs against the promotional grain: allow less, never grant Bash outright, prefer domain-scoped WebFetch to curl, allowlist inner commands one at a time. No vendor relationship is disclosed or visible, and nothing here sells a product other than the author's own competence.
Precise mechanics, one unverified source
Version-pinned, dated the same day, and specific to the character level in its examples, all of which pulls confidence up. Holding it near the middle: a lone self-interested source, no corroboration on any of the matching rules, and a body that stops mid-sentence just as the section on inline interpreters starts delivering its lessons.
build
Thirty minutes a day, and none of it from letting the agent write Swift1 publisher
build
NocoBase documents an AI kernel role for itself thirteen alphas before the 3.0 announcement1 publisher
build
Claude's outage matters less than the fallback nobody declared1 publisher
build
The entrypoint field in a Claude Code transcript tells a Stop hook if anyone is watching1 publisher
Publishers with included, body-backed reporting in this cluster.
1 article · September 7, 2026