New request
#1485: bug(macos): repeated TCC 'Terminal would like to access data from other apps' prompts during agent file searches
We'll provision a sandbox, run an agent against the issue, and open a draft PR. You can pull the branch and iterate from there.
Summary
On macOS, users hosting the WebUI / running the Mac app see repeated TCC permission prompts like:
"Terminal" would like to access data from other apps. Keeping app data separate makes it easier to manage your privacy and security. [Don't Allow] [Allow]
Reported by @Cygnus on Discord (May 02 2026):
"I'm trying to figure out what code keeps on giving me this several times in a row, but I can't expand and see the code it's running when it does"
(The "can't expand and see the code" part is the rendering bug captured in #1484 — separate fix. This issue is about why the prompt fires at all and how to stop the repetition.)
Root cause
macOS's TCC (Transparency, Consent, and Control) framework fires a permission prompt when a process touches files inside an app's protected container — typically:
~/Library/Containers/<bundle.id>/— every sandboxed Mac App Store app~/Library/Group Containers/<group.id>/~/Library/Mail/,~/Library/Messages/,~/Library/Calendars/,~/Library/Reminders/~/Library/Application Support/<vendor>/<app>/for some vendors~/Library/Mobile Documents/(iCloud Drive)~/Pictures/Photos Library.photoslibrary/- Under macOS Sequoia (15.x) and later, additional
~/Librarysubtrees
The TCC prompt is per-container, so a single user-initiated file walk that touches 30 apps' containers fires up to 30 prompts. If the user clicks "Don't Allow" once, the prompt re-fires on the next unrelated container the same scan happens to traverse. A single broad "find a file in my home directory" can produce a deluge.
The shape of our trigger (verified in code):
tools/file_operations.py (in hermes-agent, used by WebUI as the file-search engine) calls rg --files (or rg for content search) with the user's path as the root. Two paths today exclude only dot-prefixed hidden directories (line 975 for find fallback, line 1169 for grep fallback) — ~/Library/Containers is not dot-prefixed and is not excluded.
So when a search runs with a wide path:
search_files(target='files', path='~')— walks all of$HOMEincluding~/Library/Containers/*etc. → many TCC promptssearch_files(target='content', path='~')— same- Even
path='~/Library'directly (some skills do this, e.g. credential auditing) → guaranteed to hit containers
Workspace-rooted searches (path is the active workspace) usually don't hit this — most users' workspaces are outside ~/Library. So the trigger is wide-scope user paths, not the workspace.
The TCC prompt that fires says "Terminal" because Hermes runs as a child of the user's terminal session under launchd / bash and inherits the terminal's TCC identity. (Or the Mac app's identity if running under that wrapper — depends on how it was launched.)
What to fix
1. Default-exclude TCC-protected paths from file walks (primary fix)
tools/file_operations.py — extend the existing hidden-dir exclusion list with a macOS-specific TCC-protected path list. Apply across all four search paths (rg --files, rg content, find fallback, grep fallback).
Default exclude list (only on macOS — sys.platform == 'darwin', gated):
_MACOS_TCC_EXCLUDED_GLOBS = [
'!Library/Containers/**',
'!Library/Group Containers/**',
'!Library/Mail/**',
'!Library/Messages/**',
'!Library/Calendars/**',
'!Library/Reminders/**',
'!Library/Mobile Documents/**',
'!Library/Application Support/com.apple.sharedfilelist/**',
'!Library/Application Support/AddressBook/**',
'!Pictures/Photos Library.photoslibrary/**',
'!Library/CloudStorage/**', # iCloud, Dropbox, Google Drive sync mounts
]
For rg, these become --glob '!Library/...' flags. For find, -not -path '*/Library/Containers/*' predicates. For grep, --exclude-dir=Library/Containers (note: grep's --exclude-dir is per-component, not path; need find-prefilter or skip-grep-fallback for these).
2. Make the exclusion overridable
Some workflows legitimately want to read inside containers (e.g. agent inspecting iMessage exports the user dropped there). Two override paths:
- Per-call: new
include_tcc_paths=Truearg tosearch_files()/search_content()— when explicitly true, skip the TCC exclusion. Document in the tool description that this triggers macOS prompts. - Per-config:
agent.search.include_tcc_paths: trueinconfig.yamlfor the rare user who wants the old behavior.
Default is exclusion. Opting in is loud.
3. Pre-emptive guidance in the agent
Inject into the agent's system context on macOS only:
macOS file-search note: searches inside
~/Library/Containers,~/Library/Group Containers,~/Library/Mail,~/Library/Messages,~/Library/Calendars, and similar protected paths are excluded by default to avoid TCC permission prompts. If the user needs to inspect those, ask them to grant Full Disk Access to their terminal or passinclude_tcc_paths=Trueexplicitly.
~5 lines added to the macOS branch of agent context. Prevents the agent from repeatedly attempting the same scan and re-triggering prompts.
4. Document the fix in our README
A "macOS permission prompts" section explaining:
- TCC prompts are macOS-level, not Hermes-controlled
- Default behavior excludes TCC-protected paths
- To grant access permanently: System Settings → Privacy & Security → Full Disk Access → add Terminal (or the Mac app)
- To opt in per-call: explicit
include_tcc_paths=True
What this is NOT
- Not a request to suppress TCC at the OS level. We can't and shouldn't.
- Not a hard refusal. If the user wants the access, the override path exists.
- Not breaking workspace searches (workspace is normally outside
~/Library, unchanged).
Cross-repo note
The actual code change lives in hermes-agent (tools/file_operations.py) since that's where the file-search runs. The WebUI inherits the fix automatically. Filing here because:
- WebUI is the user-visible product where Cygnus hit it
- The Mac-app + WebUI combo is a primary affected configuration
- We track parity issues that fix with us
Once accepted, mirror the fix to the agent repo or coordinate the change there. May also want a short "macOS prompts" note in our docs even if the underlying fix is upstream.
Reproducer
On any macOS machine running the WebUI / Mac app:
- Have at least one Mac App Store app installed (creates
~/Library/Containers/<bundle>) - In a session, ask the agent: "Find any file named
config.yamlin my home directory" - Agent calls
search_files(target='files', pattern='config.yaml', path='~') - ripgrep walks
~/Library/Containers/com.apple.X/,~/Library/Containers/com.somevendor.app/, etc. - macOS fires TCC prompt for the first protected container
- User dismisses; ripgrep walks the next container; prompt re-fires
- Repeat N times where N = number of distinct TCC-protected containers in the user's
$HOME
After fix: zero prompts for the same call.
Files
tools/file_operations.py(in hermes-agent) — exclude-list constants, gating, plumbing through_search_with_rg,_search_with_grep,_find_files,_find_contenttools/registry.py(in hermes-agent) — extend tool schema forinclude_tcc_pathsargagent/system_context.pyor wherever macOS-specific context goes (in hermes-agent) — note injection- README + Mac install docs (in hermes-webui and hermes-agent) — TCC explanation
- Tests covering: default-exclude on darwin, no-exclude on linux, override flag, override config
Estimated effort
~80 LOC code + ~120 LOC tests + docs. Most of the complexity is in plumbing the override flag through 4 search paths consistently. Single PR. P2 — not user-blocking but high annoyance for any macOS user who runs a wide search.
Reporter / context
- @Cygnus, Discord #testers-talk, May 02 2026
- Surfaced as one of two screenshots in the same morning's batch (other was the tool-card-args readability bug → #1484)
- Affects every macOS user; severity proportional to how often they run wide-scope searches
macOS-specific TCC permission bug in agent file-search logic requires protected-path exclusions and possibly build-configuration or entitlement updates.
- api/agent_tools.py
- api/file_search.py
- infra/config/macos-entitlements.plist
- tests/file_search_regression.py