Sync claude permissions
Skill ada-ggf25/AI-Tools/global/claude/skills/sync-claude-permissions
A cross-device synced catalog for Claude and Codex skills, agents, and workflows.
npx -y skills add ada-ggf25/AI-Tools --skill sync-claude-permissionsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Translates current-project Codex permission rules (.codex/rules/default.rules prefix_rule blocks only, not personal ~/.codex rules) into Claude Code permission entries (.claude/settings.local.json), computes the gap against already-present rules, and presents portable rules for per-rule approval grouped by category before writing. Global and project-agnostic. Trigger when the user says "sync claude permissions", "sync-claude-permissions", "port project codex rules to claude", "translate project codex permissions", "replicate project codex allow rules", or "bring project codex permissions into claude".
SKILL.md
7.1 KB, as published. Nobody here has run it
Sync Project Codex Permissions To Claude Code
Global, project-agnostic skill. Reads only the current project's
.codex/rules/default.rules, translates prefix_rule(...) entries to Claude Code
Bash(...) permission syntax, diffs against .claude/settings.local.json, and writes
only the user-approved new entries. Every proposed rule requires explicit per-rule
approval before any write.
This skill intentionally syncs project-local rules only. Do not read or fall back to
${CODEX_HOME:-~/.codex}/rules/default.rules: personal/global Codex rules may affect the
active Codex session, but they are outside this project-local sync workflow.
Complements setup-permissions (which predicts rules from the stack) by operating on
already-written project-local Codex rules rather than generating from scratch. Treat
.codex/rules/default.rules as the source for this operation even when its rules were
originally adapted from Claude Code settings.
Translation reference
Pattern → Claude rule
Reconstruct the longest unambiguous prefix from the pattern array:
Codex pattern | Claude rule(s) |
|---|---|
["git", "status"] | Bash(git status:*) |
["git", ["status", "diff", "log"]] | Bash(git status:*), Bash(git diff:*), Bash(git log:*) |
["git", "-C", "/repo", ["status", "log"]] | Bash(git -C /repo status:*), Bash(git -C /repo log:*) |
["npm", "run", "test"] | Bash(npm run test:*) |
["./install.sh"] | Bash(./install.sh:*) |
When a pattern contains nested lists (one-of alternatives), expand each alternative into one Claude rule. If expansion would produce more than 8 rules from a single source entry, collapse to the common prefix and warn the user that the translation is broader.
Decision mapping
Codex decision | Claude target |
|---|---|
"allow" | permissions.allow |
"deny" | permissions.deny |
"prompt" | NOT ported — Claude Code's default for uncovered commands is already to prompt; no rule needed |
Not portable
decision = "prompt"→ list in "Deliberately NOT ported"; never add to allow or deny.- Absolute-path patterns (e.g.
["cp", "/home/user/...", "..."]) → flag as "manually review — contains absolute paths"; never auto-port.
Output notation
Always use Bash(prefix:*) colon notation (e.g. Bash(git status:*), never
Bash(git status *)).
Procedure
1. Read source
Read .codex/rules/default.rules relative to the current working directory. If the file
does not exist, report it and stop - do not create it and do not fall back to
${CODEX_HOME:-~/.codex}/rules/default.rules.
Parse all prefix_rule(...) blocks. A block spans from prefix_rule( to its matching
). Within each block extract:
pattern— the inline TOML array (may span multiple lines); parse it as a whole unit.decision—"allow","deny", or"prompt".justification— informational string; surface it in the approval prompt.
2. Read target
Read .claude/settings.local.json if it exists; if not, treat permissions.allow and
permissions.deny as empty (the file will be created in step 5). Also peek at
.claude/settings.json for already-present entries to avoid duplicates across both files,
but write exclusively to .claude/settings.local.json.
Parse permissions.allow and permissions.deny arrays.
3. Compute gap
For each prefix_rule block:
- Apply the translation rules above to get one or more candidate Claude rule strings.
- Check if each candidate is already present in the target's allow/deny list.
- Classify it as one of:
- New — candidate not in target; will be proposed.
- Already synced — candidate already present; skip silently.
- Not portable —
decision = "prompt", absolute-path pattern, or expansion > 8 entries (collapse case).
If every rule is either already synced or not portable, report "Already in sync — nothing to add." and stop.
4. Show the gap summary
Before asking for approval, display:
Rules to add (N new)
allow:
- Bash(git status:*) ← allows git status; does NOT allow git push or git reset
...
deny:
- Bash(rm:*)
Already synced (M rules, skipped)
- Bash(./install.sh:*)
...
Deliberately NOT ported
- [git reset / checkout / push] decision = "prompt" — already Claude Code default behavior
- [cp /home/user/...] absolute paths — flag for manual review
5. Propose per-rule approval
Use AskUserQuestion with multiSelect: true, grouping proposed rules by category
(git / build-test / package-manager / project-scripts / other). For each rule show:
- The proposed rule string (e.g.
Bash(git status:*)) - A one-line note from
justification: "allows X; does NOT allow Y"
Also display the "Deliberately NOT ported" section as informational (not a question), so the user sees what was withheld and why.
If there is only one category, a single multiSelect question is fine.
6. Write approved rules
For each approved rule:
- Append to
permissions.alloworpermissions.denyin.claude/settings.local.json. - If the file does not exist, create it with the structure:
{ "permissions": { "allow": [], "deny": [] } } - If the file exists but lacks the
permissionskey, add it. - Deduplicate: never write a rule already present.
- Preserve all existing entries and formatting as closely as possible.
Echo back exactly what was written and to which file.
Guardrails
- Source is project-local and read-only. Read only the current project's
.codex/rules/default.rules; never read personal${CODEX_HOME:-~/.codex}/rules/default.rulesas a fallback, and never modify the project-local source file. - Propose first, write after approval. Never auto-write any rule.
decision = "prompt"is always NOT ported. Surface it in "Deliberately NOT ported" with the note "already Claude Code default behavior (prompt); no rule needed." Never add it to allow or deny.- Absolute-path patterns are never auto-ported. Flag them for manual review; let the user decide whether a portable equivalent makes sense.
- Write only to
.claude/settings.local.json. Never touch.claude/settings.json, global~/.claude/settings.json, or any Codex file. - Narrow notation only. Every
Bash(...)rule must useprefix:*colon notation. - Merge, never clobber. Preserve existing entries; deduplicate; never overwrite the file from scratch.
- Stop gracefully if the source file is missing or the gap is empty.