Skip to content

Build1 publisher3 min readPublished

Claude Code's Computer Use approval survives only inside the session that granted it

A strings trace of claude 2.1.266 puts the allowed-apps list in session memory with no key to pre-grant it, so one developer answered the dialog with a daemon that reads Apple Terminal tabs every two seconds.

The Engineer · Build desk

Illustration accompanying Claude Code's Computer Use approval survives only inside the session that granted it

What happened

  • Choosing "Allow for this session" on Claude Code's Computer Use dialog and pressing Enter gets you through, but the dialog comes back every single time you cross a session boundary.
  • A strings trace of the claude 2.1.266 binary found the approval accumulating only in computerUseMcpState.allowedApps, which starts empty, sits in session memory, and is gone across a process boundary.
  • The prompt is registered as kind=computer_use_approval in the requestDialog family, and the PermissionRequest hook does not fire for it.
  • The developer's answer is a Python daemon that polls every Apple Terminal tab every two seconds and writes a newline to the tty when the dialog text shows up.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Because the allowed-apps list cannot be written before a run begins, an unattended session that crosses a process boundary has to be answered by something outside Claude Code.
  • decision Operators who want hands-off screen control are choosing between keeping a person near the terminal and giving a daemon standing permission to press Enter on any dialog whose text it recognises.
  • cost The remedy is tied to macOS and Apple Terminal, so operators on other emulators inherit the diagnosis without the fix, and the polling load lands on the machine already running the agent.
  • precedent With no config key in this build, per-session consent is the working contract for screen control, and anyone integrating Claude Code has to put approval handling outside the CLI.

Reading a binary with `strings` shows you that a literal is present. It is thinner evidence that one is absent. The trace, published in a dev.to write-up, was run on claude 2.1.266 to answer one question: whether the Computer Use approval can be pre-granted in a config file [3]. For the negative result to transfer to your install, your build has to read that setting by a literal key name, and its string table has to resemble 2.1.266's.

Two keys in `~/.claude.json` do persist. `bypassPermissionsModeAccepted: true` and `projects[*].hasTrustDialogAccepted: true` both hold across sessions, and the author set 85 of the latter in a single pass [8][9]. They suppress the dangerous-operation confirmation, which is a different dialog; with bypass accepted, the Computer Use prompt still appears [7][8]. "In other words, there's no room to fix this on the settings side," the author wrote [10]. The same pass turned up a parser detail: a `*` in the middle of an allow rule string, such as grep's `[^}]*`, draws a "wildcard before the rest" warning and the rule is rejected, while a trailing wildcard is accepted [11].

The first version of the daemon never pressed anything. Launched from launchd, it logged nine osascript timeouts at 22-second intervals, about 198 seconds of attempts with no keystroke delivered [13][1]. Run as a child of Terminal, it got `\r` to the dialog within seconds [14]. The post reports the reparenting as the fix and does not diagnose the cause.

The read path is where the daemon's cost sits. Terminal's `history` property is around 600KB per tab, so the script reads `contents of tab i of w`, the visible screen only [15]. Reading history instead, at a two-second poll, would move 300KB per second per tab, about 26GB a day [2]. There is an AppleScript trap in the loop: `repeat with t in tabs` with `contents of t` hands back the tab object rather than its text, so the tab has to be indexed explicitly [16].

Before sending anything, the script checks which option the cursor is on. It fires only when a tab contains both "Computer Use wants to control these apps" and "Enter to confirm" [19]. It then walks back from the confirm line to the highlighted option, the line beginning with the pointer glyph or with ">" in ASCII-only terminals, and skips unless that line contains "Allow for this session" [17]. Press Enter with the cursor on Deny and you have denied the request [18]. Sends are deduplicated per tty over 8 seconds, so at a two-second poll at most one Enter goes out per four sightings, and `fcntl.flock` stops a second instance racing the first [20][3].

Delivery is the neatest part of it. `do script "" in t` writes a single newline byte to that tab's tty and does not activate the window [21]. An approver that stole focus every few minutes would be worse than answering the dialog by hand.

On one mac, with Apple Terminal, I would run this. Anything portable has a harder problem: the trigger is a string match on the dialog's own wording [19], and the wording belongs to Anthropic.

What to watch

  • A persistable allowed-apps key appearing in the string table of a later claude release.
  • PermissionRequest hook coverage extended to requestDialog-family dialogs, so a hook can answer instead of a screen reader.
  • Anyone reproducing the trace outside claude 2.1.266, or outside Apple Terminal on macOS.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories