diff --git a/docs/backlog/no-folder-usage-strings-in-info-plist.md b/docs/backlog/no-folder-usage-strings-in-info-plist.md new file mode 100644 index 00000000..73d8130c --- /dev/null +++ b/docs/backlog/no-folder-usage-strings-in-info-plist.md @@ -0,0 +1,25 @@ +--- +worth: later +where: agterm/Info.plist:37 +added: 2026-08-20 +--- +# Info.plist declares no usage string for the protected folders + +The sixteen `NSxxxUsageDescription` strings cover the entitlement-gated services and none of the +Files & Folders family. macOS defines an optional string per protected folder — +`NSDesktopFolderUsageDescription`, `NSDocumentsFolderUsageDescription`, +`NSDownloadsFolderUsageDescription`, `NSNetworkVolumesUsageDescription`, +`NSRemovableVolumesUsageDescription` — and with none present it falls back to its own copy, measured in +`TCC.framework/Versions/A/Resources/Localizable.loctable` as +`REQUEST_ACCESS_SERVICE_kTCCServiceSystemPolicyDownloadsFolder` = `“%@” would like to access +files in your Downloads folder.` So the user is asked why agterm wants his Downloads and told nothing. + +Every other family already explains hosted-CLI responsibility in its string, so the same pattern applies: +"Command-line tools you run inside agterm may request access to your Downloads folder through agterm." +WezTerm ships two of these written for exactly that case; Ghostty, kitty and iTerm2 ship none. + +Deferred because it fixes nothing. The strings are not a gate — agterm can obtain these grants today +without them — so this repairs no denial and adds no access, and the only change is five pieces of prompt +copy. It also cannot be proven by CI, which pins the entitlement set and asserts nothing about +`Info.plist`: confirming the custom text actually renders needs a signed build and a fresh TCC state by +hand. Surfaced investigating #468, where the missing strings turned out not to be the cause. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index bf8724f6..73b2bc3f 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -132,6 +132,7 @@ Reload with **File ▸ Reload Config** or `agtermctl config reload`. The keybind To tell "never posted" from "posted but not shown", run `agtermctl notify "test"` and check two things: `agtermctl tree --json` — a rising `unseen` on the target session proves the command reached the notification path — and the log below, which now records every posted and every suppressed notification. - **A permission prompt carrying agterm's name, or a tool that cannot get one.** Command-line tools request Automation, Camera, Microphone, Contacts, Calendars, Reminders, Photos, Location, Bluetooth, local network, speech recognition, system administration and system audio recording *through* agterm, so the prompt names agterm rather than the tool. A dismissed prompt is not re-offered, the tool just keeps failing (`osascript` reports "Not authorized to send Apple events"). See [Why agterm asks for camera, microphone and the rest](#why-agterm-asks-for-camera-microphone-and-the-rest) for why, what a grant then covers, and where to change your answer. +- **A command cannot read `~/Downloads`, `~/Desktop` or `~/Documents`.** Those folders are protected by macOS itself, separately from the services above, and the grant is per application — another terminal reading them says nothing about agterm. See [A command cannot read ~/Downloads, ~/Desktop or ~/Documents](#a-command-cannot-read-downloads-desktop-or-documents). - **Agent-status glyph does not update.** Install the hooks from Help ▸ Install Agent Status Hooks…. For shell-integrated agents, start a fresh shell so the `source` line added to your shell rc takes effect. For Pi, restart it or run `/reload` so it loads `~/.pi/agent/extensions/agterm-status.ts`; Pi status is only installed when `~/.pi/agent` already exists. For OpenCode, restart it so it loads `~/.config/opencode/plugins/agterm-status.js`; the plugin installs only when `~/.config/opencode` already exists. The hooks call `agtermctl session status`, so `agtermctl` must resolve first (see above). - **Agent-status glyph updates the wrong session.** One session's glyph blinks while the work happens in another — typically when agents run inside tmux (or a tmux-backed session manager such as agent-deck). The working process inherited another session's `AGTERM_SESSION_ID`: the status hooks target whatever id is in their environment, and a long-lived daemon started from inside an agterm session (a tmux server is the usual carrier) captures that session's `AGTERM_*` variables into its global environment and passes them to every child it ever creates. Check `tmux show-environment -g | grep AGTERM` — if present, clear them with `tmux set-environment -g -r AGTERM_SESSION_ID` (and the other `AGTERM_*` names), then restart the affected panes. To avoid it, start such daemons with the variables scrubbed (`env -u AGTERM_SESSION_ID … `) or from a terminal outside agterm. @@ -192,6 +193,30 @@ obtain permissions at all, and it is worth knowing before approving something yo matching service, listed as agterm, for example Automation ▸ agterm. A dismissed prompt is not re-offered, so if a tool keeps failing after you dismissed one, that is where to fix it. +## A command cannot read ~/Downloads, ~/Desktop or ~/Documents + +`ls ~/Downloads` fails for a directory that belongs to you, and another terminal on the same Mac lists it +without complaint. + +Those three folders, along with removable and network volumes, are protected by macOS directly. It is a +different mechanism from the section above: agterm is not sandboxed, and unlike the services listed there no +missing entitlement can suppress this family's prompt. macOS defines an optional usage-description string per +folder and agterm ships none, so the prompt carries macOS's own wording rather than agterm's. What matters is +that the answer is recorded against the application macOS holds responsible. Approving kitty or +Terminal says nothing about agterm, so a Mac where every other terminal reads the folder can still refuse +this one, and as with the services above a dismissed prompt is not re-offered and the command just keeps +failing. + +Grant it in System Settings ▸ Privacy & Security ▸ Files & Folders, where agterm appears with a switch per +folder once something in a session has asked. Full Disk Access covers all of them at once and accepts agterm +from the + button without waiting for a request, at the cost of giving every program you ever run in a +session that same reach — the section above covers what a grant gives away. + +To tell a privacy denial from ordinary permission bits, run `/bin/ls -la ~/Downloads` — the real `ls`, +against the folder itself, rather than a replacement such as `eza`. A privacy denial usually reads as +`Operation not permitted` and ordinary permission bits as `Permission denied`, and some replacements print +the same wording for both. + ## Reporting a problem Collect this before filing: diff --git a/plugins/agterm/skills/agterm/troubleshooting.md b/plugins/agterm/skills/agterm/troubleshooting.md index cae1fe2c..33ce9044 100644 --- a/plugins/agterm/skills/agterm/troubleshooting.md +++ b/plugins/agterm/skills/agterm/troubleshooting.md @@ -147,6 +147,19 @@ further prompt, and a dismissed prompt is never re-offered (`osascript` keeps re to send Apple events"). The user changes the answer in System Settings ▸ Privacy & Security under the matching service, e.g. Automation ▸ agterm. This is macOS policy, not an agterm bug: do not file it. +### "a command cannot read ~/Downloads, ~/Desktop or ~/Documents" + +macOS protects those folders, plus removable and network volumes, on its own: a separate mechanism from the +services above, gated by no entitlement, and agterm is not sandboxed. The per-folder usage-description +strings are optional and agterm ships none, so the prompt carries macOS's own wording. The answer is +recorded against the app macOS holds responsible, so another terminal listing the folder proves nothing +about agterm. The user grants it in System Settings ▸ Privacy & Security ▸ Files & Folders ▸ agterm, or +gives agterm Full Disk Access, which covers all of them at once. A dismissed prompt is never re-offered. +`/bin/ls -la `, against the failing folder itself, usually tells the two causes apart: `Operation +not permitted` for the privacy denial, `Permission denied` for ordinary permission bits, and some `ls` +replacements print the same wording for both. Needing the grant is macOS policy, not an agterm bug: do not +file it. + ### "The agent-status glyph does not update" Install the hooks from Help ▸ Install Agent Status Hooks…. For shell-integrated agents, start a fresh shell