<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jessy Brenenstahl</title>
    <description>The latest articles on DEV Community by Jessy Brenenstahl (@jbrenens).</description>
    <link>https://dev.to/jbrenens</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4188789%2F209c3410-5e2e-4279-bdf3-0a685a483552.png</url>
      <title>DEV Community: Jessy Brenenstahl</title>
      <link>https://dev.to/jbrenens</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jbrenens"/>
    <language>en</language>
    <item>
      <title>macOS TCC permissions for unattended AI agents: stop losing nights to hidden prompts</title>
      <dc:creator>Jessy Brenenstahl</dc:creator>
      <pubDate>Fri, 16 Oct 2026 11:45:47 +0000</pubDate>
      <link>https://dev.to/jbrenens/macos-tcc-permissions-for-unattended-ai-agents-stop-losing-nights-to-hidden-prompts-27hb</link>
      <guid>https://dev.to/jbrenens/macos-tcc-permissions-for-unattended-ai-agents-stop-losing-nights-to-hidden-prompts-27hb</guid>
      <description>&lt;p&gt;If you run AI agents unattended on a Mac (Claude Code in iTerm, a launchd job driving &lt;code&gt;osascript&lt;/code&gt;, Hammerspoon clicking buttons), you've probably woken up to find nothing happened overnight. The cause is usually one dialog sitting on an unwatched screen: &lt;em&gt;"Terminal" would like to control "System Events"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That's macOS TCC (Transparency, Consent and Control). Here's how to set it up once so it stops eating your nights.&lt;/p&gt;

&lt;h2&gt;
  
  
  The key idea: permissions belong to the host app
&lt;/h2&gt;

&lt;p&gt;TCC grants go to the app that launches the process, not to your script. If &lt;code&gt;claude&lt;/code&gt; runs inside iTerm, iTerm needs the grant. If a launchd job runs &lt;code&gt;/bin/bash script.sh&lt;/code&gt;, the grant goes to whatever binary macOS names in the prompt.&lt;/p&gt;

&lt;p&gt;So the first rule is: &lt;strong&gt;pick one terminal app as your agent host&lt;/strong&gt; and grant everything there. Spreading agents across Terminal, iTerm, Warp and VS Code means four sets of grants that drift out of sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each agent task needs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent task&lt;/th&gt;
&lt;th&gt;Privacy &amp;amp; Security pane&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Click/type into other apps (AX, Hammerspoon)&lt;/td&gt;
&lt;td&gt;Accessibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;osascript&lt;/code&gt; controlling another app&lt;/td&gt;
&lt;td&gt;Automation (once per target app)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screenshots / screen reading&lt;/td&gt;
&lt;td&gt;Screen &amp;amp; System Audio Recording (relaunch after granting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;~/Documents, Desktop, Downloads&lt;/td&gt;
&lt;td&gt;Files and Folders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mail, Messages, Safari data&lt;/td&gt;
&lt;td&gt;Full Disk Access (only if really needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global hotkeys&lt;/td&gt;
&lt;td&gt;Input Monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Trigger the prompts while you're watching
&lt;/h2&gt;

&lt;p&gt;Automation prompts only appear the first time an app tries to control a target. Run each one deliberately during setup, not at 3am:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;osascript &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'tell application "System Events" to get name of first process'&lt;/span&gt;
osascript &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'tell application "Finder" to get name of startup disk'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click Allow on each, then you're done for that host/target pair.&lt;/p&gt;

&lt;h2&gt;
  
  
  A read-only health check before bed
&lt;/h2&gt;

&lt;p&gt;Don't edit the TCC database (and don't disable SIP). Just check that things still work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;osascript &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'tell application "System Events" to get name of first process'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"automation OK"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"automation BROKEN"&lt;/span&gt;
screencapture &lt;span class="nt"&gt;-x&lt;/span&gt; /tmp/tcc-check.png &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"screen OK"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If either fails, fix it now instead of finding out in the morning.&lt;/p&gt;

&lt;h2&gt;
  
  
  After macOS updates
&lt;/h2&gt;

&lt;p&gt;Updates and app re-signing can silently invalidate grants: the toggle still looks on, but it no longer applies. The fix that works most often is to remove the app from the list with the minus button, add it back, and relaunch it.&lt;/p&gt;




&lt;p&gt;The free first-time setup checklist is on GitHub: &lt;a href="https://github.com/jessybrenenstahl/agent-ops-samples" rel="noopener noreferrer"&gt;agent-ops-samples&lt;/a&gt;.&lt;br&gt;
The full &lt;a href="https://ko-fi.com/s/5cbe58c175" rel="noopener noreferrer"&gt;macOS TCC Agent Fleet Runbook ($12)&lt;/a&gt; adds the complete permission map, symptom-to-fix recovery steps and a fleet log for tracking grants across machines.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Your AI coding agents are reading conflicting instructions</title>
      <dc:creator>Jessy Brenenstahl</dc:creator>
      <pubDate>Fri, 16 Oct 2026 11:45:00 +0000</pubDate>
      <link>https://dev.to/jbrenens/your-ai-coding-agents-are-reading-conflicting-instructions-1ie4</link>
      <guid>https://dev.to/jbrenens/your-ai-coding-agents-are-reading-conflicting-instructions-1ie4</guid>
      <description>&lt;p&gt;Run Claude Code, Codex and Cursor on the same repo for a week and you'll end up with a &lt;code&gt;CLAUDE.md&lt;/code&gt;, an &lt;code&gt;AGENTS.md&lt;/code&gt;, a &lt;code&gt;.cursor/rules&lt;/code&gt; folder and a README that each say something slightly different. One says "use pnpm", another says "npm is fine". One says "never touch migrations", another has a migration workflow.&lt;/p&gt;

&lt;p&gt;Agents don't flag these conflicts. They just follow whichever rule they read last, or whichever one is closest to the task. So you get behavior that changes depending on which tool you opened that morning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: find every instruction file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 4 &lt;span class="se"&gt;\(&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'CLAUDE.md'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'AGENTS.md'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'.cursorrules'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s1"&gt;'*/.cursor/rules/*'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'GEMINI.md'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'RULES.md'&lt;/span&gt; &lt;span class="se"&gt;\)&lt;/span&gt; &lt;span class="nt"&gt;-not&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s1"&gt;'*/node_modules/*'&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; ~/.claude/CLAUDE.md ~/.codex/AGENTS.md 2&amp;gt;/dev/null   &lt;span class="c"&gt;# global files follow you into every repo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Global home-dir files are the sneaky ones. They're applied to every project and quietly override project facts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: list the contradictions
&lt;/h2&gt;

&lt;p&gt;Go through the files topic by topic: package manager, test command, branch/commit rules, what counts as "done", forbidden directories. Write each conflict down as "File A says X, file B says Y".&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: declare a precedence order, and tell the agents
&lt;/h2&gt;

&lt;p&gt;When two rules disagree, the higher one wins:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The live human message in the current session&lt;/li&gt;
&lt;li&gt;Safety rules (no force-push, no secrets, no deleting outside the repo). Never overridden by anything lower.&lt;/li&gt;
&lt;li&gt;The nearest scoped file (&lt;code&gt;sub/dir/RULES.md&lt;/code&gt; beats root for files under &lt;code&gt;sub/dir&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The canonical root &lt;code&gt;RULES.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Agent-specific pointer files (CLAUDE.md, AGENTS.md, .cursor/rules), for tool quirks only&lt;/li&gt;
&lt;li&gt;Global home-dir files, for personal defaults only&lt;/li&gt;
&lt;li&gt;README / docs prose: background, not instructions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Paste this at the top of your canonical file:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Precedence: the user's current message &amp;gt; Safety section below &amp;gt; the nearest RULES.md in the directory tree &amp;gt; this file &amp;gt; agent-specific files &amp;gt; global defaults. If two rules conflict and this order doesn't settle it, stop and ask. Don't pick one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That last sentence matters most. "Stop and ask" turns a silent wrong guess into a visible question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: one source, thin pointers
&lt;/h2&gt;

&lt;p&gt;Put the real rules in one &lt;code&gt;RULES.md&lt;/code&gt;. Make &lt;code&gt;CLAUDE.md&lt;/code&gt; and &lt;code&gt;AGENTS.md&lt;/code&gt; a few lines each: "Read RULES.md first. Tool-specific notes: ..." Now there's only one place to edit, and the agents can't drift apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: log decisions
&lt;/h2&gt;

&lt;p&gt;Keep a short conflict log ("2026-10-12: pnpm wins, npm lines removed from AGENTS.md"). Without it, an agent will happily reintroduce the rule you deleted last week because it found it in an old commit message.&lt;/p&gt;




&lt;p&gt;The free audit checklist is on GitHub: &lt;a href="https://github.com/jessybrenenstahl/agent-ops-samples" rel="noopener noreferrer"&gt;agent-ops-samples&lt;/a&gt;.&lt;br&gt;
If you want the full set (precedence model, single-source templates for RULES.md / CLAUDE.md / AGENTS.md / Cursor, conflict log), it's the &lt;a href="https://ko-fi.com/s/8d0252f4dc" rel="noopener noreferrer"&gt;Agent Instructions Conflict Kit ($9)&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
