Agent access register
Generated 2026-10-21 12:48:52 ยท 11 agents in the registry ยท policy: Acceptable-use policy for scheduled agents (Adopted 2026-10-03 by the fleet owner, with edits to the 2026-10-02 draft. Rule AUP-05 (work systems) was considered and dropped, so the numbering skips it.)
Config allows, policy forbids
Declared access: it's in a settings file, a task approval, or the registry. Nothing here is a guess.
AUP-01GovernEvery agent is registered, with a named model and an explicit permission mode
- escalated-case-digest. SKILL.md has no model line; no permission mode in the registry (config)
AUP-02GovernNo agent runs with permission checks off
- old-rainfall-report. runs with permission checks off (config)
AUP-04MapAn agent runs from its own project folder, and no credential store sits inside it
- 9 agents. working directory is the home folder
which
daily-garden-check, escalated-case-digest, habit-nagger, inbox-junk-sweep, manual-backfill, morning-brief, old-rainfall-report, pickup-reminder, weekly-fleet-review
AUP-06MeasureNo secrets in instructions or allow rules
- ~/.claude/scheduled-tasks/daily-garden-check/SKILL.md line 10. long mixed string, 34 characters (value not shown, not verified as live) (config)
- ~/.claude/settings.local.json allow rule 1. long mixed string, 38 characters (value not shown, not verified as live) (config)
AUP-08ManageCredential files are off the allowlist and on the deny list
- All agents. ~/.claude/settings.json allows Read(~/.config/chat/.env), which covers Discord bot token
- All agents. no deny rule covers Discord bot token, GitHub CLI login, Salesforce CLI login, SSH private key
- 10 of 11 agents. no deny rule covers Weather API keys
AUP-09ManageNo wildcard interpreter in an allowlist
- All agents. ~/.claude/settings.json allows Bash(python3 *)
- 9 agents with working directory ~. ~/.claude/settings.local.json allows Bash(osascript -e ' *)
AUP-10ManageAgents message only through the approved channels
- 9 agents with working directory ~. send:imessage: mcp__messages__send_imessage
- pickup-reminder. send:imessage: mcp__messages__send_imessage (approved for this task)
AUP-11ManagePublishing is a person's decision
- daily-job-pipeline. publish:git-push: Bash(git push origin main) (git push) (approved for this task)
AUP-12ManageDeleting is a person's decision
- inbox-junk-sweep. delete:email: mcp__mail__trash_thread (approved for this task)
Instructions ask for what policy forbids
Inferred from each task's SKILL.md and the scripts it runs. Whether config would let these through isn't known for agents in auto mode, so they're kept apart from the list above.
AUP-10ManageAgents message only through the approved channels
- escalated-case-digest. send:slack: tool slack__slack_send_message (SKILL.md line 12)
- pickup-reminder. send:imessage: prose: โSend an iMessage to the saved contact with the pickup timeโ (SKILL.md line 7)
AUP-11ManagePublishing is a person's decision
- Excepted: ship-weekly, publish:git-push: command built in script. Reason on file: publishes the portfolio site on Sundays; owner approved 2026-09-14
- Excepted: ship-weekly, publish:github: command built in script. Reason on file: publishes the portfolio site on Sundays; owner approved 2026-09-14
Shared config: what every agent under it inherits
Allow rules aren't per-agent. Each settings file below applies to every agent listed against it, so its rows aren't repeated in the per-agent table.
| Settings file | Applies to | Rules | What stands out |
|---|---|---|---|
~/.claude/settings.json | all agents | 8 allow ยท 0 deny ยท 0 ask Bash 3, Read 2, Edit 2, mcp 1 |
|
~/.claude/settings.local.json | 9 agents with working directory ~ | 7 allow ยท 0 deny ยท 0 ask Bash 3, WebFetch 2, WebSearch 1, mcp 1 |
|
~/projects/jobs/.claude/settings.json | 1 agent with working directory ~/projects/jobs | 2 allow ยท 1 deny ยท 0 ask Bash 1, Edit 1 |
|
Credential stores
Existence and the rules that reach each one. No store is opened.
| Store | Path | Agents that reach it (declared) | Agents that use it (inferred) | Runs that used it (observed) | Deny rule |
|---|---|---|---|---|---|
| Discord bot token | ~/.config/chat/.env | 11 of 11 whichmorning-brief, daily-job-pipeline, escalated-case-digest, weekly-fleet-review, inbox-junk-sweep, daily-garden-check, ship-weekly, habit-nagger, pickup-reminder, old-rainfall-report, manual-backfill | weekly-fleet-review, habit-nagger | weekly-fleet-review 4/4 | none |
| Weather API keys | ~/.config/weather/.env | 9 of 11 whichmorning-brief, escalated-case-digest, weekly-fleet-review, inbox-junk-sweep, daily-garden-check, habit-nagger, pickup-reminder, old-rainfall-report, manual-backfill | none found | none seen | Read(~/.config/weather/.env) |
| GitHub CLI login | ~/.config/gh/hosts.yml | 9 of 11 whichmorning-brief, escalated-case-digest, weekly-fleet-review, inbox-junk-sweep, daily-garden-check, habit-nagger, pickup-reminder, old-rainfall-report, manual-backfill | none found | none seen | none |
| Salesforce CLI login | ~/.sf | 9 of 11 whichmorning-brief, escalated-case-digest, weekly-fleet-review, inbox-junk-sweep, daily-garden-check, habit-nagger, pickup-reminder, old-rainfall-report, manual-backfill | escalated-case-digest | escalated-case-digest 30/30 | none |
| SSH private key | ~/.ssh/id_ed25519 | 9 of 11 whichmorning-brief, escalated-case-digest, weekly-fleet-review, inbox-junk-sweep, daily-garden-check, habit-nagger, pickup-reminder, old-rainfall-report, manual-backfill | none found | none seen | none |
| Cloud credentials | ~/.aws/credentials | not on disk | |||
Every agent
declared is in permission config. inferred was read out of the task's instructions or a script they run; it can be wrong in both directions. Shared rules above apply on top of each row.
| Agent | Read | Write | Send | Credentials | Also |
|---|---|---|---|---|---|
| daily-garden-check enabledauto model opus ยท runs in ~ |
|
| nothing detected |
| 1 script/skill hop(s)
unknownscript ~/bin/rain_rollup.py is missing: what it reaches is unknown |
| daily-job-pipeline enabledauto model opus ยท runs in ~/projects/jobs ยท 2 task approvals |
|
|
|
| 1 thing(s) the instructions say not to do
1 script/skill hop(s)
|
| escalated-case-digest enabledmode unset model not set ยท runs in ~ |
| nothing detected |
|
| โ |
| habit-nagger enabledauto model haiku ยท runs in ~ |
|
|
|
| 1 script/skill hop(s)
|
| inbox-junk-sweep enabledauto model opus ยท runs in ~ ยท 2 task approvals |
|
| nothing detected |
| 1 thing(s) the instructions say not to do
|
| manual-backfill enabledauto model not set ยท runs in ~ |
|
| unknowninstructions missing |
| unknowninstructions missing: what this agent is told to do is unknown |
| morning-brief enabledauto model opus ยท runs in ~ ยท 2 task approvals |
|
|
|
| 1 script/skill hop(s)
|
| pickup-reminder enabledauto model opus ยท runs in ~ ยท 1 task approvals |
|
|
|
| โ |
| ship-weekly enabledauto model opus ยท runs in ~/projects/site |
|
|
|
| 1 script/skill hop(s)
|
| weekly-fleet-review enabledauto model haiku ยท runs in ~ |
|
|
|
| 1 thing(s) the instructions say not to do
1 script/skill hop(s)
|
| old-rainfall-report disabledbypassPermissions model opus ยท runs in ~ |
|
| nothing detected |
|
|
Just-in-time pass: what each agent's runs use of what it's granted
observedRead from the transcripts of 173 scheduled runs between 2026-09-22 and 2026-10-21 (a 30-day window). Every tool call is matched to the narrowest standing grant that covers it: a shared allow rule, a per-task approval, or the working directory. A grant every run used is one the agent needs each time. A grant only some runs used could be granted to the run that needs it and dropped when that run ends. Agents with fewer than 3 runs are listed but not sorted.
| Agent | Every run uses | Some runs use: grant per run, drop after | No run used | Ran on no standing grant | Where runs went |
|---|---|---|---|---|---|
| daily-garden-check 30 runs ยท 2026-09-22 to 2026-10-21 under 15 shared rules and 0 task approvals |
| none | 13 of 15 shared rules |
|
|
| daily-job-pipeline 22 runs ยท 2026-09-22 to 2026-10-21 under 10 shared rules and 2 task approvals |
|
| 9 of 10 shared rules; 0 of 2 task approvals | none |
|
| escalated-case-digest 30 runs ยท 2026-09-22 to 2026-10-21 under 15 shared rules and 0 task approvals |
| none | 14 of 15 shared rules |
|
|
| habit-nagger 30 runs ยท 2026-09-22 to 2026-10-21 under 15 shared rules and 0 task approvals |
| none | 14 of 15 shared rules | none |
|
| inbox-junk-sweep 30 runs ยท 2026-09-22 to 2026-10-21 under 15 shared rules and 2 task approvals |
| none | 13 of 15 shared rules; 1 of 2 task approvalswhich approvals
| none |
|
| morning-brief 22 runs ยท 2026-09-22 to 2026-10-21 under 15 shared rules and 2 task approvals |
| none | 14 of 15 shared rules; 0 of 2 task approvals | none |
|
| pickup-reminder 1 run ยท 2026-10-18 to 2026-10-18 under 15 shared rules and 1 task approval | too few runs1 run can't show what every run needs. | none | 15 of 15 shared rules; 1 of 1 task approvalswhich approvals
|
|
|
| ship-weekly 4 runs ยท 2026-09-30 to 2026-10-21 under 8 shared rules and 0 task approvals |
| none | 8 of 8 shared rules |
|
|
| weekly-fleet-review 4 runs ยท 2026-09-29 to 2026-10-20 ยท 1 with no transcript under 15 shared rules and 0 task approvals |
| none | 14 of 15 shared rules |
|
|
| manual-backfill 0 runs under 15 shared rules and 0 task approvals | No run in the window left a transcript with a tool call, so nothing can be said about what it uses. | ||||
| old-rainfall-report 0 runs under 15 shared rules and 0 task approvals | No run in the window left a transcript with a tool call, so nothing can be said about what it uses. | ||||
Shared rules any run used
5 of 17 shared allow rules covered at least one call in the window. The rest covered none. These files also apply to interactive sessions, which this pass doesn't read, so unused here means unused by scheduled runs.
| Rule | Settings file | Agents | Runs |
|---|---|---|---|
| Bash(python3 *) | ~/.claude/settings.json | daily-garden-check, habit-nagger, morning-brief, weekly-fleet-review | 86 |
| Edit(~/Trackers/**) | ~/.claude/settings.json | daily-garden-check, inbox-junk-sweep | 60 |
| Bash(sf *) | ~/.claude/settings.json | escalated-case-digest | 30 |
| mcp__mail__search_threads | ~/.claude/settings.json | inbox-junk-sweep | 30 |
| Bash(.venv/bin/python pipeline/run.py) | ~/projects/jobs/.claude/settings.json | daily-job-pipeline | 22 |
Matcher check. 398 of 406 calls carry Claude Code's own record of what allowed them; for the rest, attribution is this matcher alone. On 310 calls, Claude Code's own record says a standing rule let the call through. The matcher found a current rule of the same kind for 310 of them (100%). For 0 it found a rule of the other kind (a task approval where Claude Code named a settings rule, or the reverse), and for 0 it found none: a rule removed since, or one this matcher reads differently.
What this pass can't see
- Runs older than the window, and runs whose transcripts Claude Code has already cleaned up.
- Interactive sessions. The shared settings files apply to them too, so a rule no scheduled run used may still be in use by hand.
- What a script does once it runs. A call to python3 some_script.py is one call; the files and hosts inside the script don't show up as calls.
- Which rule Claude Code actually applied. Its record names the kind (settings rule, task approval, classifier, mode) but not the rule, so the narrowest current rule that covers the call is credited.
- Calls before Claude Code started recording decisions (late September 2026). For those, attribution is this matcher alone.
- Whether a grant could be dropped without breaking a run on a day the window didn't cover.
Where policy is silent
Access that shows up in config or instructions and that no policy rule speaks to, for or against. Silence isn't approval; each line is a decision nobody has written down.
| Access | Evidence | Where |
|---|---|---|
| write:~/Trackers | declaredinferred | shared config: ~/.claude/settings.json; 2 agents: daily-garden-check, inbox-junk-sweep |
| read:email | declaredinferred | shared config: ~/.claude/settings.json; 1 agent: inbox-junk-sweep |
| write:~/projects | declaredinferred | shared config: ~/projects/jobs/.claude/settings.json; 1 agent: daily-job-pipeline |
| data:salesforce:any | declared | shared config: ~/.claude/settings.json |
| exec:osascript | declared | shared config: ~/.claude/settings.local.json |
| read:~/.claude | declared | shared config: ~/.claude/settings.json |
| read:~/.config | declared | shared config: ~/.claude/settings.json |
| web:fetch | declared | shared config: ~/.claude/settings.local.json |
| web:search | declared | shared config: ~/.claude/settings.local.json |
| write:~/.claude | declared | shared config: ~/.claude/settings.json |
| net:(web hosts fetched from the shell) | inferred | 2 agents: daily-garden-check, daily-job-pipeline |
| write:~/Downloads | declaredinferred | 2 agents: morning-brief, old-rainfall-report |
| data:salesforce:read | inferred | 1 agent: escalated-case-digest |
| modify:email | declared | 1 agent: inbox-junk-sweep |
| read:calendar | declaredinferred | 1 agent: morning-brief |
| read:~/Trackers | inferred | 1 agent: weekly-fleet-review |
What this page can't see
- What the auto-mode classifier lets through. 9 agent(s) run in auto, where anything the allowlist doesn't name goes to a classifier this tool can't read. For those agents the allowlist is a floor, not a ceiling.
- Which mode 1 agent(s) with no mode in the registry actually start in.
- What agents did beyond the tool calls in their run transcripts. The just-in-time pass reads those calls; it can't see inside a script a call runs, or any run outside its window.
- Which MCP servers and connectors are attached when a scheduled run starts. Tool names in rules and instructions are read; whether the tool is there at run time is not.
- Managed settings, command-line flags, and plugin or mod permission hooks.
- Whether any control works. A hook that is registered and a rule that is written are both reported as present, and neither has been probed by this tool.
- Scripts past one hop. A script that SKILL.md runs is scanned; anything that script imports or calls is not.
- What a script does at run time. Paths and hosts built from variables don't show up in a text scan.
- Keychain contents, and whether any credential file holds a live secret.
- Operating-system permissions (macOS privacy grants, file modes beyond existence).
- Other machines. Agents scheduled anywhere else aren't in this registry.
- 1 task folder(s) on disk have no row in the registry. They're listed, not analysed: something else may still run them.
Task folders with no registry row (1)
shelf-audit
The policy this was checked against
Plain rules for agents that run on a schedule with nobody watching. Each one is grouped under the NIST AI RMF function it serves most (Govern, Map, Measure, Manage); the mapping is loose and meant for orientation, not a compliance claim. A rule the register can test says so. A rule it can't test says that instead of pretending.
| Rule | NIST AI RMF | Says | Checked? |
|---|---|---|---|
| AUP-01 Every agent is registered, with a named model and an explicit permission mode | Govern | An agent that runs on a schedule has a row in the scheduler, a model line in its instructions, and a permission mode somebody chose. Nothing runs on a default nobody picked. | findings |
| AUP-02 No agent runs with permission checks off | Govern | No scheduled agent uses bypassPermissions. Unattended is exactly when the checks matter. | findings |
| AUP-03 Spending money is never delegated | Govern | No agent buys, pays, books, or transfers. It can prepare a cart or a draft; a person places the order. | can't check nothing in permission config marks an action as a purchase. |
| AUP-04 An agent runs from its own project folder, and no credential store sits inside it | Map | The working directory is the boundary reads and edits are approved inside. Set to the home folder, that boundary is everything the account owns, credential files included. The same goes for any folder, or added directory, that holds a credential store. | findings |
| AUP-06 No secrets in instructions or allow rules | Measure | A token, key, or password never appears in a SKILL.md or a permission rule. Approving a one-off command bakes its literal text into the allowlist, so this gets checked, not assumed. | findings |
| AUP-07 The register is re-run when the fleet changes | Measure | Run it when an agent is added or its instructions change, and after any credential incident. Each finding is fixed or excepted in writing, with a reason and a name. | can't check a habit, not a setting. |
| AUP-08 Credential files are off the allowlist and on the deny list | Manage | No allow rule names or covers a credential store, and every store has a deny rule. A deny rule stops the file tools and the shell readers the harness recognises; it does not stop a script that opens the file itself, which is why AUP-04 and AUP-09 exist. | findings |
| AUP-09 No wildcard interpreter in an allowlist | Manage | A rule that allows an interpreter with a wildcard (python, bash, node, osascript) allows everything that interpreter can do. Allow the named script instead. | findings |
| AUP-10 Agents message only through the approved channels | Manage | Outbound goes through the Discord helper, the ntfy helper, or a mail draft a person sends. Sending mail directly, texting, posting to any other service, or a raw HTTP request with a body needs a named exception. | findings |
| AUP-11 Publishing is a person's decision | Manage | No agent pushes to a remote, opens or merges a pull request, or publishes a page unless it holds a named exception for that one destination. | findings |
| AUP-12 Deleting is a person's decision | Manage | No agent deletes mail, records, or files in bulk. It can list what it would remove and wait for a yes. Removing one named scratch file it made itself is fine. | findings |
| AUP-13 Destructive shell commands pass a gate | Manage | A PreToolUse hook on the shell tool is registered. The register confirms it's registered; it doesn't confirm it works, and a gate that has never been probed is an assumption. | no findings |