permissions
Recommend safe Bash permissions for Elixir mix commands in settings.json. Use when permission prompts slow workflow, "fix permissions", "reduce prompts", "auto-allow mix".
Install
npx skills add https://github.com/oliver-kriska/claude-elixir-phoenix/tree/main/plugins/elixir-phoenix/skills/permissions
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install oliver-kriska-claude-elixir-phoenix@llmmart
git clone https://github.com/oliver-kriska/claude-elixir-phoenix.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole oliver-kriska/claude-elixir-phoenix collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Permission Analyzer
Scan recent session transcripts to find Bash commands you keep approving,
cross-reference with current settings.json, and recommend adding the missing ones.
Primary goal: Discover MISSING permissions from actual usage. Secondary goal: Clean up redundant/garbage entries.
Usage
/phx:permissions [--days=14] [--dry-run] — Scans session JSONL files, finds uncovered Bash commands, classifies risk, and recommends settings.json changes. Use --dry-run to preview without writing.
Arguments
$ARGUMENTS — --days=N (default: 14), --dry-run (preview only).
Iron Laws
- NEVER auto-allow RED —
rm,sudo,kill,curl|sh,mix ecto.reset,git push --force,chmod 777 - Evidence-based only — Only recommend commands actually approved in sessions
- Show before writing — Present full diff, get explicit confirmation
- Preserve existing — Merge, never overwrite
Risk Classification
| Level | Examples | Action |
|---|---|---|
| GREEN | ls, cat, grep, tail, which, mkdir, cd, mix test/compile/credo/format, git status/log/diff |
Auto-recommend |
| YELLOW | git add/commit/push, mix ecto.migrate, mix deps.get, npm install, docker build/run, source, mise exec |
Recommend with note |
| RED | rm -rf, sudo, kill, curl|sh,mix ecto.reset/drop,git push --force,git reset --hard |
Never recommend |
Workflow
Step 1: Extract Bash Commands from Session JSONL Files
Run the extraction script from ${CLAUDE_SKILL_DIR}/references/extraction-script.md.
This scans all project JSONL files from the last N days, checks each Bash command
against current settings.json patterns, and reports uncovered commands with counts.
Run this before any settings cleanup — missing permissions are the primary goal.
Step 2: Classify and Recommend
For each uncovered command from Step 1 output:
- Classify as GREEN / YELLOW / RED per table above
- Generate permission pattern: normalize to
Bash(base_command *)format (use SPACE before*, NOT colon —:*is deprecated)mkdir -p(94x) →Bash(mkdir *)mise exec(39x) →Bash(mise *)tail -5(20x) →Bash(tail *)
- Check for redundancy: skip if a broader existing pattern covers it
- Also scan for garbage in current settings:
Bash(done),Bash(fi),Bash(__NEW_LINE_*), partial heredocs, entries covered by broader patterns - Fix deprecated
:*patterns — replace anyBash(name:*)withBash(name *)(space before*). The:*suffix is deprecated and may not match reliably
Present a combined table:
## Permission Recommendations (last N days)
### ADD — Missing permissions (from session scan)
| Pattern to Add | Times Used | Risk | Example |
|...
### REMOVE — Redundant/garbage entries
| Entry | Reason |
|...
### RED — Require manual approval (not adding)
| Command | Count | Risk |
|...
Step 3: Interactive Triage (unless --dry-run)
Walk through findings interactively using AskUserQuestion. Present items
in batches by risk level, starting with GREEN (safest):
Batch 1 — GREEN items (read-only, tests, safe tools):
Use AskUserQuestion with options:
- "Add all GREEN" — approve entire batch
- "Pick individually" — show each one for yes/no
- "Skip GREEN" — move to YELLOW
Batch 2 — YELLOW items (write ops, need caution):
Always show individually — one AskUserQuestion per item with options:
- "Add" — include in settings
- "Skip" — keep requiring manual approval
- "Customize" — let user edit the pattern before adding
Batch 3 — REMOVE candidates (garbage/redundant):
Use AskUserQuestion with options:
- "Remove all" — clean up entire batch
- "Pick individually" — show each for yes/no
- "Keep all" — skip cleanup
Track approved items in a list. After triage, show final summary of what will be added/removed and ask for confirmation.
Step 4: Apply
Merge approved additions into ~/.claude/settings.json under permissions.allow.
Remove approved garbage entries. Report final counts.
Workflow-artifact permissions (always check)
The plugin's workflow writes to .claude/plans/, .claude/solutions/, and
.claude/reviews/. If these aren't covered, /phx:compound and review agents
get write-blocked mid-workflow. Recommend (GREEN):
Write(.claude/plans/**), Write(.claude/solutions/**), Write(.claude/reviews/**).
References
${CLAUDE_SKILL_DIR}/references/risk-classification.md— Full classification rules${CLAUDE_SKILL_DIR}/references/settings-format.md— Permission pattern format
Related
Long mix output flooding context? /phx:mix-compression installs rtk filters
that compress mix test/credo/dialyzer/compile output before it reaches the
transcript (5-15% token savings on mix-heavy sessions).
Files (claude-elixir-phoenix)
-
references
-
extraction-script.md 3.3 KB
# Session JSONL Extraction Script Run this Python script to extract all uncovered Bash commands from recent sessions: ```python python3 -c " import json, os, glob, fnmatch, re from datetime import datetime from collections import Counter DAYS = ${DAYS:-14} # 1. Read current allowed patterns from all settings files allowed = [] for path in [os.path.expanduser('~/.claude/settings.json'), '.claude/settings.json', '.claude/settings.local.json']: try: with open(path) as f: allowed.extend(json.load(f).get('permissions',{}).get('allow',[])) except: pass # 2. Build matchers from permission patterns # Handles both formats: # Bash(git *) — current (space before wildcard) # Bash(git:*) — deprecated (colon before wildcard) # Bash(git status) — exact match # Bash — matches ALL bash commands def make_glob(perm): if perm == 'Bash' or perm == 'Bash(*)': return '*' # matches everything m = re.match(r'Bash\((.+)\)', perm) if not m: return None pat = m.group(1) # Normalize deprecated :* to space * if pat.endswith(':*'): pat = pat[:-2] + ' *' return pat pats = [make_glob(p) for p in allowed if p.startswith('Bash')] pats = [p for p in pats if p] def is_covered(cmd): return any(fnmatch.fnmatch(cmd, p) for p in pats) # 3. Scan ALL project JSONL files from last N days all_files = glob.glob(os.path.expanduser('~/.claude/projects/*/*.jsonl')) cutoff = datetime.now().timestamp() - DAYS*86400 recent = [f for f in all_files if os.path.getmtime(f) > cutoff] uncovered = Counter() examples = {} deprecated = [] for fp in recent: try: with open(fp) as f: for line in f: entry = json.loads(line) if entry.get('type') != 'assistant': continue for block in (entry.get('message',{}).get('content',[]) or []): if not isinstance(block, dict): continue if block.get('type') == 'tool_use' and block.get('name') == 'Bash': cmd = block.get('input',{}).get('command','').strip().split(chr(10))[0][:300] if cmd and not is_covered(cmd): parts = cmd.split() base = ' '.join(parts[:2]) if len(parts)>=2 else parts[0] uncovered[base] += 1 if base not in examples: examples[base] = cmd[:120] except: pass # 4. Check for deprecated :* patterns in current settings for p in allowed: if p.startswith('Bash(') and ':*)' in p: deprecated.append(p) # 5. Output results print(f'Sessions scanned: {len(recent)} (last {DAYS} days)') print(f'Uncovered command patterns: {len(uncovered)}') print(f'Total avoidable prompts: {sum(uncovered.values())}') if deprecated: print(f'Deprecated :* patterns to fix: {len(deprecated)}') print() for cmd, count in uncovered.most_common(30): ex = examples.get(cmd,'') print(f'{count:4d}x {cmd}') if ex != cmd: print(f' e.g.: {ex[:100]}') if deprecated: print(f'\n=== DEPRECATED :* patterns (replace : with space) ===') for p in deprecated[:10]: print(f' {p} -> {p.replace(chr(58)+chr(42)+chr(41), chr(32)+chr(42)+chr(41))}') if len(deprecated) > 10: print(f' ... and {len(deprecated)-10} more') " ``` -
risk-classification.md 5.7 KB
# Risk Classification Rules Comprehensive command classification for the permission analyzer. ## Classification Algorithm 1. Extract the **base command** (first token or first two tokens for compound commands) 2. Check against RED list first (deny-list takes priority) 3. Check against GREEN list 4. Default to YELLOW if not in either list ## GREEN — Read-Only and Standard Dev Tools Commands that cannot cause data loss or security issues. ### Always Safe | Pattern | Rationale | |---------|-----------| | `ls *` | Read-only directory listing | | `cat *` | Read-only file content | | `head *`, `tail *` | Read-only file content | | `wc *` | Read-only counting | | `find *` | Read-only file search (CC 2.1.113+: `find -exec` / `find -delete` are excluded — these still prompt) | | `grep *`, `rg *` | Read-only content search | | `which *`, `where *` | Read-only path lookup | | `echo *` | Output only | | `date`, `whoami`, `pwd` | Info only | | `file *` | Read-only type detection | | `diff *` | Read-only comparison | ### Elixir/Phoenix Safe | Pattern | Rationale | |---------|-----------| | `mix compile *` | Build step, reversible | | `mix test *` | Read-only test execution | | `mix format --check-formatted *` | Read-only check | | `mix credo *` | Read-only analysis | | `mix hex.info *` | Read-only package info | | `mix hex.audit` | Read-only security check | | `mix deps.audit` | Read-only dependency check | | `mix xref *` | Read-only cross-reference | | `mix dialyzer *` | Read-only type check | | `mix phx.routes *` | Read-only route listing | | `elixir -e *` | Evaluation (treat as GREEN for simple expressions) | | `iex -S mix` | Interactive shell | ### Git Read-Only | Pattern | Rationale | |---------|-----------| | `git status *` | Read-only | | `git log *` | Read-only | | `git diff *` | Read-only | | `git show *` | Read-only | | `git branch` (no -D/-d) | Read-only listing | | `git remote -v` | Read-only | | `git stash list` | Read-only | ### Node/Frontend Safe | Pattern | Rationale | |---------|-----------| | `node -e *` | Evaluation | | `npx prettier --check *` | Read-only | | `npm ls *` | Read-only | | `npm outdated` | Read-only | ## YELLOW — Write Operations (Recommend with Caution) Commands that modify local state but are generally recoverable. ### Git Write Operations | Pattern | Note | |---------|------| | `git add *` | Stages files (reversible with reset) | | `git commit *` | Creates commit (reversible with reset) | | `git push` (no --force) | Publishes commits | | `git checkout *` | Switches branches, can discard changes | | `git switch *` | Switches branches | | `git stash *` | Saves/restores work | | `git merge *` | Merges branches | | `git rebase *` (no --force) | Rewrites history locally | | `git branch -d *` | Deletes merged branch | ### Elixir Write Operations | Pattern | Note | |---------|------| | `mix format *` (without --check) | Modifies files (reversible via git) | | `mix deps.get` | Downloads dependencies | | `mix deps.compile *` | Compiles dependencies | | `mix ecto.migrate` | Runs migrations (has rollback) | | `mix ecto.rollback` | Rolls back migration | | `mix ecto.gen.migration *` | Creates migration file | | `mix phx.gen.* *` | Generates code files | | `mix ecto.setup` | Creates + migrates + seeds | ### File Operations | Pattern | Note | |---------|------| | `mkdir *` | Creates directories | | `touch *` | Creates empty files | | `cp *` | Copies files | | `mv *` | Moves files (reversible if in git) | ### Package Managers | Pattern | Note | |---------|------| | `npm install *` | Installs packages | | `npm run *` | Runs scripts | | `yarn *` | Package operations | | `hex.pm` commands | Package operations | ## RED — Never Auto-Allow Commands that can cause irreversible damage, security risks, or affect systems beyond the local project. ### Destructive Operations | Pattern | Risk | |---------|------| | `rm *` | File deletion (irreversible outside git) | | `rm -rf *` | Recursive deletion | | `rmdir *` | Directory deletion | | `mix ecto.reset` | Drops + recreates database | | `mix ecto.drop` | Drops database | | `git push --force *` | Overwrites remote history | | `git push -f *` | Overwrites remote history | | `git reset --hard *` | Discards uncommitted changes | | `git clean -f *` | Deletes untracked files | | `git branch -D *` | Force-deletes branch | ### Privilege Escalation | Pattern | Risk | |---------|------| | `sudo *` | Elevated privileges | | `su *` | User switching | | `chmod 777 *` | World-writable permissions | | `chown *` | Ownership changes | ### Network / External | Pattern | Risk | |---------|------| | `curl * \| sh` | Remote code execution | | `wget * \| sh` | Remote code execution | | `curl * \| bash` | Remote code execution | | `ssh *` | Remote access | | `scp *` | Remote file transfer | ### Process Control | Pattern | Risk | |---------|------| | `kill *` | Process termination | | `killall *` | Mass process termination | | `pkill *` | Pattern-based process kill | ### Container / Infrastructure | Pattern | Risk | |---------|------| | `docker rm *` | Container deletion | | `docker rmi *` | Image deletion | | `docker system prune *` | Mass cleanup | ## Edge Cases ### Compound Commands For piped or chained commands (`cmd1 | cmd2`, `cmd1 && cmd2`): - Classify EACH component separately - Final classification = highest risk component - `mix test | head` → GREEN (both GREEN) - `mix deps.get && rm -rf _build` → RED (rm is RED) ### Commands with Redirects - `echo "text" > file.txt` → YELLOW (file write) - `cat file > /dev/null` → GREEN (null write is safe) ### Environment Variables - `MIX_ENV=test mix test` → Same as `mix test` (GREEN) - `MIX_ENV=prod mix phx.server` → RED (production operations) - `DATABASE_URL=... mix ecto.*` → YELLOW (external DB connection) -
settings-format.md 4.1 KB
# Claude Code Settings Permission Format How to correctly write permissions to Claude Code settings files. Source: [code.claude.com/docs/en/permissions](https://code.claude.com/docs/en/permissions) ## Settings File Hierarchy Claude Code reads settings from multiple locations. More specific scopes take precedence; `deny` at any level blocks even if another level allows: | Scope | File | Shared? | |-------|------|---------| | User (global) | `~/.claude/settings.json` | No | | Project (team) | `.claude/settings.json` | Yes (git) | | Local (personal) | `.claude/settings.local.json` | No (gitignored) | ## Permission Format ```json { "permissions": { "allow": [ "Bash(npm run build)", "Bash(npm run test *)", "Bash(git *)" ], "deny": [ "Bash(rm -rf *)", "Bash(sudo *)" ] } } ``` Rules are evaluated: **deny → ask → allow**. First match wins. ## Pattern Syntax Permission rules follow `Tool` or `Tool(specifier)` format. ### Match all uses | Rule | Effect | |------|--------| | `Bash` | Matches ALL Bash commands | | `Bash(*)` | Same — matches all | ### Wildcard patterns with `*` `*` is a glob wildcard. The **space before `*` matters**: | Pattern | Matches | Does NOT match | |---------|---------|----------------| | `Bash(ls *)` | `ls -la`, `ls /tmp` | `lsof` (word boundary) | | `Bash(ls*)` | `ls -la`, `lsof` | (no boundary) | | `Bash(git *)` | `git diff`, `git add` | `gitk` | | `Bash(mix test *)` | `mix test test/foo.exs` | `mix testing` | | `Bash(* --version)` | `node --version` | — | | `Bash(npm run build)` | exact match only | `npm run build:dev` | ### Deprecated `:*` syntax > "The legacy `:*` suffix syntax is equivalent to `*` but is deprecated." > — [Claude Code docs](https://code.claude.com/docs/en/permissions) **Do NOT use** `Bash(git:*)` — use `Bash(git *)` instead. The `:*` format may not match reliably and will be removed in a future version. ### Compound commands Claude Code is aware of shell operators (`&&`, `|`, `;`). A prefix match rule like `Bash(safe-cmd *)` won't give permission to run `safe-cmd && other-cmd`. When "Yes, don't ask again" is clicked on a compound command, Claude Code saves a **separate rule for each subcommand** (up to 5 rules). ## Recommended Permission Sets ### Minimal (Read-Only Developer) ```json { "permissions": { "allow": [ "Bash(ls *)", "Bash(cat *)", "Bash(grep *)", "Bash(mix compile *)", "Bash(mix test *)", "Bash(git status)", "Bash(git log *)", "Bash(git diff *)" ] } } ``` ### Standard Elixir Developer ```json { "permissions": { "allow": [ "Bash(ls *)", "Bash(cat *)", "Bash(grep *)", "Bash(head *)", "Bash(tail *)", "Bash(wc *)", "Bash(find *)", "Bash(which *)", "Bash(mkdir *)", "Bash(mix compile *)", "Bash(mix test *)", "Bash(mix format *)", "Bash(mix credo *)", "Bash(mix deps.get *)", "Bash(mix ecto.migrate *)", "Bash(mix ecto.gen.migration *)", "Bash(mix phx.routes *)", "Bash(mix xref *)", "Bash(mix hex.info *)", "Bash(git *)" ] } } ``` ### Full-Trust Developer ```json { "permissions": { "allow": [ "Bash(mix *)", "Bash(git *)", "Bash(npm *)", "Bash(ls *)", "Bash(cat *)", "Bash(grep *)", "Bash(find *)", "Bash(mkdir *)", "Bash(cp *)" ], "deny": [ "Bash(mix ecto.reset *)", "Bash(mix ecto.drop *)", "Bash(git push --force *)", "Bash(git push -f *)", "Bash(git reset --hard *)", "Bash(rm -rf *)", "Bash(sudo *)" ] } } ``` ## Merging Strategy When the permission analyzer writes to settings: 1. **Read** current contents of the target settings file 2. **Parse** existing `permissions.allow` array 3. **Append** new entries (skip duplicates) 4. **Fix deprecated** `:*` patterns → `*` 5. **Write** merged result back ## Project vs Global Placement | Command Type | Recommended Location | |-------------|---------------------| | Universal tools (`ls`, `grep`, `cat`) | `~/.claude/settings.json` (global) | | Elixir-specific (`mix test`, `mix compile`) | `.claude/settings.json` (project) | | Personal preferences | `.claude/settings.local.json` (local) |
-
-
SKILL.md 5.1 KB
--- name: permissions description: Recommend safe Bash permissions for Elixir mix commands in settings.json. Use when permission prompts slow workflow, "fix permissions", "reduce prompts", "auto-allow mix". argument-hint: "[--days=14] [--dry-run]" effort: low --- # Permission Analyzer Scan recent session transcripts to find Bash commands you keep approving, cross-reference with current `settings.json`, and recommend adding the missing ones. **Primary goal**: Discover MISSING permissions from actual usage. **Secondary goal**: Clean up redundant/garbage entries. ## Usage `/phx:permissions [--days=14] [--dry-run]` — Scans session JSONL files, finds uncovered Bash commands, classifies risk, and recommends `settings.json` changes. Use `--dry-run` to preview without writing. ## Arguments `$ARGUMENTS` — `--days=N` (default: 14), `--dry-run` (preview only). ## Iron Laws 1. **NEVER auto-allow RED** — `rm`, `sudo`, `kill`, `curl|sh`, `mix ecto.reset`, `git push --force`, `chmod 777` 2. **Evidence-based only** — Only recommend commands actually approved in sessions 3. **Show before writing** — Present full diff, get explicit confirmation 4. **Preserve existing** — Merge, never overwrite ## Risk Classification | Level | Examples | Action | |-------|----------|--------| | GREEN | `ls`, `cat`, `grep`, `tail`, `which`, `mkdir`, `cd`, `mix test/compile/credo/format`, `git status/log/diff` | Auto-recommend | | YELLOW | `git add/commit/push`, `mix ecto.migrate`, `mix deps.get`, `npm install`, `docker build/run`, `source`, `mise exec` | Recommend with note | | RED | `rm -rf`, `sudo`, `kill`, `curl|sh`,`mix ecto.reset/drop`,`git push --force`,`git reset --hard` | Never recommend | ## Workflow ### Step 1: Extract Bash Commands from Session JSONL Files Run the extraction script from `${CLAUDE_SKILL_DIR}/references/extraction-script.md`. This scans all project JSONL files from the last N days, checks each Bash command against current `settings.json` patterns, and reports uncovered commands with counts. Run this before any settings cleanup — missing permissions are the primary goal. ### Step 2: Classify and Recommend For each uncovered command from Step 1 output: 1. **Classify** as GREEN / YELLOW / RED per table above 2. **Generate permission pattern**: normalize to `Bash(base_command *)` format (use SPACE before `*`, NOT colon — `:*` is deprecated) - `mkdir -p` (94x) → `Bash(mkdir *)` - `mise exec` (39x) → `Bash(mise *)` - `tail -5` (20x) → `Bash(tail *)` 3. **Check for redundancy**: skip if a broader existing pattern covers it 4. **Also scan for garbage** in current settings: `Bash(done)`, `Bash(fi)`, `Bash(__NEW_LINE_*)`, partial heredocs, entries covered by broader patterns 5. **Fix deprecated `:*` patterns** — replace any `Bash(name:*)` with `Bash(name *)` (space before `*`). The `:*` suffix is deprecated and may not match reliably Present a combined table: ``` ## Permission Recommendations (last N days) ### ADD — Missing permissions (from session scan) | Pattern to Add | Times Used | Risk | Example | |... ### REMOVE — Redundant/garbage entries | Entry | Reason | |... ### RED — Require manual approval (not adding) | Command | Count | Risk | |... ``` ### Step 3: Interactive Triage (unless `--dry-run`) Walk through findings interactively using `AskUserQuestion`. Present items in batches by risk level, starting with GREEN (safest): **Batch 1 — GREEN items** (read-only, tests, safe tools): Use `AskUserQuestion` with options: - "Add all GREEN" — approve entire batch - "Pick individually" — show each one for yes/no - "Skip GREEN" — move to YELLOW **Batch 2 — YELLOW items** (write ops, need caution): Always show individually — one `AskUserQuestion` per item with options: - "Add" — include in settings - "Skip" — keep requiring manual approval - "Customize" — let user edit the pattern before adding **Batch 3 — REMOVE candidates** (garbage/redundant): Use `AskUserQuestion` with options: - "Remove all" — clean up entire batch - "Pick individually" — show each for yes/no - "Keep all" — skip cleanup Track approved items in a list. After triage, show final summary of what will be added/removed and ask for confirmation. ### Step 4: Apply Merge approved additions into `~/.claude/settings.json` under `permissions.allow`. Remove approved garbage entries. Report final counts. ### Workflow-artifact permissions (always check) The plugin's workflow writes to `.claude/plans/`, `.claude/solutions/`, and `.claude/reviews/`. If these aren't covered, `/phx:compound` and review agents get write-blocked mid-workflow. Recommend (GREEN): `Write(.claude/plans/**)`, `Write(.claude/solutions/**)`, `Write(.claude/reviews/**)`. ## References - `${CLAUDE_SKILL_DIR}/references/risk-classification.md` — Full classification rules - `${CLAUDE_SKILL_DIR}/references/settings-format.md` — Permission pattern format ## Related Long mix output flooding context? `/phx:mix-compression` installs rtk filters that compress `mix test/credo/dialyzer/compile` output before it reaches the transcript (5-15% token savings on mix-heavy sessions).
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.