{"id":"audit-permissions","name":"audit-permissions","summary":"このスキルは、ユーザーが「Claude権限の監査」「監査権限」「ローカルClaude設定の確認」「権限をグローバルに昇格する」「Claude設定のクリーンアップ」「権限パターンの検索」、または追加すべきプロジェクトローカルのClaude Code権限を特定したい場合に使うべきです。","body":"# Audit Claude Permissions\n\nScan project-local Claude Code settings files, aggregate permission patterns, and recommend promotions to global configuration.\n\n## Workflow Overview\n\nThis audit runs in three phases, each as a separate task. Use TaskCreate at the start to create all three tasks, then work through them sequentially with user input via AskUserQuestion.\n\n- **Phase 1: Promote to Global** — Requires user judgment. Present candidates, get decisions, apply to global config.\n- **Phase 2: Automated Redundancy Cleanup** — Script-driven. After Phase 1 promotions, run cleanup script to remove local permissions now covered by global. Present for sanity-checking, then apply.\n- **Phase 3: Judgment Calls** — Everything requiring user input: security hygiene, policy conflicts, one-off cruft, empty file deletion, moderate-risk items.\n\n## Initial Setup\n\n1. **Check for symlinked global settings:**\n\n```bash\nreadlink -f ~/.claude/settings.json\n```\n\nIf the global settings file is a symlink, note the real path. All writes to `~/.claude/settings.json` must edit the symlink target, not create a new file that replaces the symlink.\n\n2. **Load user preferences** from `~/.claude/cc-maintenance.local.md` (if it exists). See User Preferences section below. Apply any configured defaults (risk tolerance, auto-cleanup preference).\n\n3. **Read global CLAUDE.md** from `~/.claude/CLAUDE.md` to identify tool preference policies for Phase 3 policy conflict detection.\n\n4. **Run the discovery and extraction pipeline:**\n\n```bash\nscripts/discover-settings.sh | xargs scripts/extract-permissions.py\n```\n\n5. **Read the actual global settings** from `~/.claude/settings.json` — compare against the real allow list, not just the static examples in this skill.\n\n6. **Create tasks** for the three phases:\n\n```\nTaskCreate: \"Review and promote permissions to global config\"\nTaskCreate: \"Automated redundancy cleanup\"\nTaskCreate: \"Judgment calls: security, policy, and cruft\"\n```\n\n7. **Analyze the data** and categorize permissions (see Categorization Rules below).\n\n---\n\n## Phase 1: Promote to Global\n\n**Goal:** Identify permissions worth adding to global config and get user approval.\n\n### Present Findings\n\nShow a summary table of promotion candidates:\n\n```markdown\n## Promotion Candidates\n\n### Strong Recommendations (safe patterns, multiple projects)\n\n| Permission | Projects | Suggested Global Pattern |\n| ---------- | -------- | ------------------------ |\n| ...        | ...      | ...                      |\n\n### Moderate Recommendations (review carefully)\n\n| Permission | Projects | Notes |\n| ---------- | -------- | ----- |\n| ...        | ...      | ...   |\n\n### Cross-Project File Patterns\n\n[If any Read/Write/Edit permissions reference paths outside their project directory\nand appear in multiple projects, flag them here. Example: multiple projects have\n`Write(~/.config/some-tool/config.json)` - might indicate a shared config worth\nadding globally.]\n```\n\n### Get User Decision\n\nUse AskUserQuestion to let the user decide:\n\n```\nQuestion: \"Which permissions should I add to global settings?\"\nOptions:\n- \"Add all strong recommendations\"\n- \"Add strong + moderate recommendations\"\n- \"Let me pick specific ones\" (then list individually)\n- \"Skip - don't add any\"\n```\n\n### Apply Changes\n\nIf user approves additions:\n\n1. Add selected permissions to `~/.claude/settings.json` (or symlink target)\n2. Respect existing logical groupings (git, nix, gh, etc.)\n3. Sort alphabetically within groups\n4. Use space-syntax: `Bash(cmd *)` not `Bash(cmd:*)`\n5. Mark Phase 1 task as completed\n\n---\n\n## Phase 2: Automated Redundancy Cleanup\n\n**Goal:** Remove local permissions now covered by global config. This is mechanical — the script identifies exact matches; user just sanity-checks the list.\n\n### Preview Cleanup\n\nRun the cleanup script in dry-run mode:\n\n```bash\nscripts/discover-settings.sh | scripts/cleanup-redundant.py\n```\n\n### Present Findings\n\nShow what would be removed:\n\n```markdown\n## Redundant Permissions\n\n| File      | Permissions to Remove | Remaining |\n| --------- | --------------------- | --------- |\n| project-a | 5 (ls _, grep _, ...) | 12        |\n| project-b | 3 (gh api \\*, ...)    | 8         |\n| ...       | ...                   | ...       |\n\n**Total:** X permissions across Y files\n```\n\nThe script also normalizes any remaining colon-syntax (`Bash(cmd:*)`) to space-syntax (`Bash(cmd *)`) when applying.\n\n### Get User Decision\n\nIf `auto_cleanup_redundant: true` in user preferences, skip the question and apply directly (still show the summary). Otherwise:\n\n```\nQuestion: \"Should I remove these redundant permissions from local files?\"\nOptions:\n- \"Yes, clean them up\"\n- \"Show me the full list first\"\n- \"Skip cleanup\"\n```\n\n### Apply Changes\n\nIf user approves:\n\n```bash\nscripts/discover-settings.sh | scripts/cleanup-redundant.py --apply\n```\n\nMark Phase 2 task as completed.\n\n---\n\n## Phase 3: Judgment Calls\n\n**Goal:** Everything that requires real user judgment — security risks, policy conflicts, stale cruft, and cleanup opportunities. Present all categories together.\n\n### Category A: Security Hygiene\n\nFlag permissions that match these patterns:\n\n**High Risk (recommend removal):**\n\n- `Bash(curl *)`, `Bash(wget *)` — network exfiltration risk\n- `Bash(rm *)` — can delete any file\n- `Bash(source *)` — executes arbitrary scripts\n- `Bash(eval *)` — arbitrary code execution\n\n**Moderate Risk (review):**\n\n- `Bash(git reset *)`, `Bash(git checkout *)` — can discard work\n- `Bash(pkill *)`, `Bash(kill *)` — process termination\n- `Bash(python *)`, `Bash(python3 *)`, `Bash(node *)` — arbitrary code (flag if user hasn't consciously chosen this)\n\nAdjust what counts as \"moderate\" vs \"high\" based on the user's `risk_tolerance` preference if set.\n\n### Category B: Policy Conflicts\n\nRead the user's global `~/.claude/CLAUDE.md` for stated tool preferences. Flag local permissions that conflict with those policies.\n\n**How to detect:** Look for patterns like \"prefer X over Y\", \"use X instead of Y\", \"avoid Y\". Then scan all local permissions for uses of the deprecated tool. For example:\n\n> If CLAUDE.md says \"prefer tool X over built-in Y\", flag all `Y` permissions across local settings as policy conflicts.\n\nPresent these as informational — the user may have valid reasons for specific overrides.\n\n### Category C: One-Off Cruft\n\n- Hardcoded file paths (e.g., `Bash(prettier --write /full/path/to/file.md)`)\n- Incomplete shell constructs (`Bash(done)`, `Bash(for file in *.rs)`)\n- Very specific commands with no wildcards that look like debugging artifacts\n- Duplicate entries\n- Legacy colon-syntax permissions (`Bash(cmd:*)`) that weren't caught by the cleanup script (e.g., ones without a global equivalent)\n\n### Category D: Cross-Project File Access\n\n- `Read`, `Write`, or `Edit` permissions for paths outside the project\n- Flag if the same external path appears in multiple projects (potential global candidate)\n- Flag broad patterns like `Write(~/.config/*)` as security concerns\n\n### Category F: MCP Tool Permissions\n\n- Flag MCP tools with write/send/delete capabilities (message sending, data deletion, post creation) — these have side effects beyond the local environment\n- Flag server-wide wildcards (`mcp__server__*`) — convenient but auto-permits any future tools added to that server without review\n- Suggest consolidation: if all or most tools from a server are individually listed, suggest replacing with the server wildcard (with a note about the trade-off)\n\n### Category E: Empty File Deletion\n\nAfter cleanup, identify settings files where:\n\n- All permissions have been removed (empty allow list or no allow list)\n- No other settings exist (no hooks, enabledPlugins, etc.)\n\nOffer to delete these empty files entirely — they serve no purpose.\n\n### Present Findings\n\n```markdown\n## Judgment Calls\n\n### Security Hygiene\n\n#### High Risk — Recommend Removal\n\n| Permission     | Project   | Risk              |\n| -------------- | --------- | ----------------- |\n| `Bash(curl *)` | project-x | Data exfiltration |\n\n#### Moderate Risk — Review\n\n| Permission | Project | Risk |\n| ---------- | ------- | ---- |\n| ...        | ...     | ...  |\n\n### Policy Conflicts\n\n| Permission      | Projects | Policy                      |\n| --------------- | -------- | --------------------------- |\n| `WebFetch(url)` | 3        | CLAUDE.md: prefer Firecrawl |\n\n### One-Off Cruft\n\n| Permission                                         | Project   |\n| -------------------------------------------------- | --------- |\n| `Bash(prettier --write /path/to/specific/file.md)` | project-y |\n\n### External File Access\n\n| Permission                     | Projects   | Notes                           |\n| ------------------------------ | ---------- | ------------------------------- |\n| `Write(~/.config/tool/config)` | 3 projects | Shared config — consider global |\n| `Edit(/etc/hosts)`             | 1 project  | System file — review necessity  |\n\n### MCP Tool Permissions\n\n| Permission                 | Projects | Notes                                       |\n| -------------------------- | -------- | ------------------------------------------- |\n| `mcp__slack__post_message` | 2        | Side effect: sends messages externally      |\n| `mcp__puppeteer__*`        | 1        | Server wildcard — auto-permits future tools |\n\n### Empty Settings Files\n\n| File                                      | Reason                                     |\n| ----------------------------------------- | ------------------------------------------ |\n| `~/project-z/.claude/settings.local.json` | All permissions removed, no other settings |\n```\n\n### Get User Decision\n\nUse AskUserQuestion:\n\n```\nQuestion: \"How should I handle the judgment call items?\"\nOptions:\n- \"Remove all flagged items\"\n- \"Remove high risk + cruft only\"\n- \"Let me review each category\"\n- \"Skip — keep everything\"\n```\n\nIf user wants to review categories, ask about each separately.\n\n### Apply Changes\n\nEdit each affected `settings.local.json` to remove approved items. Delete empty settings files if approved.\n\nMark Phase 3 task as completed.\n\n---\n\n## Session Wrap-Up\n\nAfter all phases complete, offer to create or update `~/.claude/cc-maintenance.local.md` with session learnings. Include:\n\n- Any risk tolerance preferences expressed during the session\n- Tool preference notes mentioned during review\n- Freeform notes from user decisions (overrides, exceptions, per-project rules — anything the user said that should carry forward to future audits)\n- Session history entry (date, summary of changes)\n\n---\n\n## User Preferences\n\n**Location:** `~/.claude/cc-maintenance.local.md`\n\nRead at audit start. If missing, proceed with defaults. At session end, offer to create/update.\n\n**Format:** YAML frontmatter for structured preferences + markdown body for freeform notes.\n\n```yaml\n---\n# All preferences are optional\nrisk_tolerance: moderate # conservative | moderate | aggressive\nauto_cleanup_redundant: true\n---\n## Tool Preferences\n- Prefer Exa/Firecrawl over built-in WebSearch/WebFetch\n\n## Risk Notes\n- sqlite3 and op item get considered moderate risk\n- uv run python treated as arbitrary code execution\n\n## Notes\n- Always keep python3 permissions in the data-science project\n- Don't consolidate Firecrawl tools into a server wildcard\n\n## Session History\n### 2026-02-09\n- Promoted 13 permissions to global\n- Removed ~220 cruft permissions from Assistant project\n```\n\n**Behavior:**\n\n- `risk_tolerance` adjusts what gets flagged as moderate vs high in Phase 3\n- `auto_cleanup_redundant` skips the confirmation prompt in Phase 2 (still shows summary)\n- Tool Preferences section supplements CLAUDE.md policy detection\n- Notes section is a freeform catch-all for any user preferences that don't fit the structured sections — overrides, exceptions, per-project rules, anything the agent should remember across audits\n- Session History provides context for future audits\n\n---\n\n## Scripts\n\nAll scripts are in `scripts/` relative to this skill directory.\n\n- **`scripts/discover-settings.sh`** — Finds all `.claude/settings.local.json` files across `~` using `fd` with sensible exclusions (Library, node_modules, .git, etc.). Max depth of 5 for performance.\n- **`scripts/extract-permissions.py`** — Aggregates permissions from multiple settings files. Outputs JSON with each permission, occurrence count, and list of projects using it. Sorted by count descending.\n- **`scripts/cleanup-redundant.py`** — Removes permissions from local files that are covered by global config. Handles cross-syntax matching (colon-syntax vs space-syntax). Normalizes remaining permissions to space-syntax on write. Dry-run by default; use `--apply` to modify files.\n\n**Usage examples:**\n\n```bash\n# Extract and aggregate all permissions\nscripts/discover-settings.sh | xargs scripts/extract-permissions.py\n\n# Preview redundant permission cleanup (dry-run, default)\nscripts/discover-settings.sh | scripts/cleanup-redundant.py\n\n# Actually remove redundant permissions\nscripts/discover-settings.sh | scripts/cleanup-redundant.py --apply\n```\n\n---\n\n## Categorization Rules\n\n### Formatting Rules\n\nUse space-syntax for all permissions: `Bash(cmd *)` not `Bash(cmd:*)`.\n\n### Reasonable Global Candidates\n\nPatterns worth promoting. These operate on local project code or perform read-only operations. Compare against the **actual** global config, not just this static list — these are examples of the kinds of patterns to look for.\n\n**Git Commands (read-only):**\n`git branch *`, `git diff *`, `git log *`, `git show *`, `git status *`\n\n**File Inspection (read-only):**\n`cat *`, `head *`, `tail *`, `ls *`, `find *`, `grep *`, `du *`\n\n**Build and Check Commands:**\n`cargo build *`, `cargo test *`, `cargo check *`, `go build *`, `go test *`,\n`npm run build *`, `npm run test *`, `deno check *`, `deno lint *`, `xcodebuild *`\n\n**System Utilities:**\n`open *`, `pbcopy`, `pbpaste`, `lsof *`, `ps *`\n\n**Nix Commands:**\n`nix build *`, `nix-build *`, `nix develop *`, `nix eval *`, `nix flake *`,\n`nix path-info *`, `nix-prefetch-url *`, `nh darwin build *`\n\n**Homebrew (read-only):**\n`brew info *`, `brew search *`\n\n**GitHub CLI:**\n`gh api *`, `gh issue list *`, `gh issue view *`, `gh pr list *`, `gh pr view *`,\n`gh pr diff *`, `gh pr checks *`, `gh search *`, `gh run list *`, `gh run view *`\n\n**Wildcards:**\n`* --help *`, `* --version`\n\n### Pattern Generalization\n\nWhen promoting, generalize cautiously — only for safe patterns:\n\n| Local Pattern                 | Global Pattern          | Notes                        |\n| ----------------------------- | ----------------------- | ---------------------------- |\n| `Bash(npm run build)`         | `Bash(npm run build *)` | Safe — runs project scripts  |\n| `Bash(cargo test --release)`  | `Bash(cargo test *)`    | Safe — tests local code      |\n| `Bash(nix build .#package)`   | `Bash(nix build *)`     | Safe — sandboxed builds      |\n| `Bash(python3 script.py)`     | Keep specific or skip   | Risky — arbitrary code       |\n| `WebFetch(domain:github.com)` | Keep as-is              | Domain patterns don't change |\n\n### Formatting Rules for Global Settings\n\nWhen adding to `~/.claude/settings.json`:\n\n- Respect existing logical groupings (git, file inspection, nix, brew, gh, system utilities, build tools, wildcards, Skills, MCP tools)\n- Within each group, sort alphabetically\n- Place new permissions in the appropriate group based on command prefix\n- Use space-syntax: `Bash(cmd *)` not `Bash(cmd:*)`","author":"@malob","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/malob/nix-config/tree/master/configs/claude/plugins/cc-maintenance/skills/audit-permissions","license":"MIT","category":"review","lang":"en","tokens":3540,"stars":0,"calls30d":1,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"scripts/cleanup-redundant.py","size":5394,"sha256":"4b52f3288d5da301ad22b4feab95ef711f9950aa88546836fb1c41a0b124cce5"},{"path":"scripts/discover-settings.sh","size":635,"sha256":"9cbe5ead79f4f08b03df07495b72f31feebb7281de34589aacc5faa0de0db915"},{"path":"scripts/extract-permissions.py","size":1954,"sha256":"35a2b0aef6c7108b3ba83b410fa6bf1d7a9232aa136ae3e10131d9ab3de0775a"}],"requires":{"mcp":["server","slack","puppeteer"],"tools":["Bash(*/audit-permissions/scripts/*)","Bash(readlink *)","Read(~/.claude/settings.json)","Edit(~/.claude/settings.json)","Write(~/.claude/settings.json)","Read(**/.claude/settings.local.json)","Edit(**/.claude/settings.local.json)","Write(**/.claude/settings.local.json)","Read(~/.claude/cc-maintenance.local.md)","Edit(~/.claude/cc-maintenance.local.md)","Write(~/.claude/cc-maintenance.local.md)","Read(~/.claude/CLAUDE.md)"]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":true,"networkEndpoints":[]}}