| name | sync-codex-permissions |
| description | Translates current-project Claude Code permission rules (.claude/settings.local.json permissions.allow and permissions.deny Bash entries only) into Codex prefix_rule blocks in .codex/rules/default.rules, computes the gap against existing project-local Codex rules, and presents portable rules for per-rule approval before writing. Global and project-agnostic. Trigger when the user says "sync codex permissions", "sync-codex-permissions", "port project claude permissions to codex", "translate project claude permissions", "replicate project claude allow rules", or "bring project claude permissions into codex". |
Sync Project Claude Code Permissions To Codex
Use $sync-codex-permissions to mirror already-approved current-project Claude Code
command permissions into Codex's project-local rules file. The source is always the
current project's .claude/settings.local.json; the target is always
.codex/rules/default.rules.
This skill intentionally syncs project-local rules only. Do not read or fall back to
global Claude Code settings or ${CODEX_HOME:-~/.codex}/rules/default.rules: personal or
global permissions may affect active sessions, but they are outside this project-local
sync workflow.
This skill is the inverse of sync-claude-permissions. sync-claude-permissions
translates .codex/rules/default.rules into .claude/settings.local.json; this skill
translates .claude/settings.local.json into .codex/rules/default.rules.
Translation Reference
Claude Code Rule To Codex Pattern
Translate only Claude Code Bash(...) permission entries. Build the narrowest Codex
pattern array that matches the same command prefix:
| Claude Code rule | Codex prefix_rule pattern |
|---|
Bash(git status:*) | ["git", "status"] |
Bash(git status *) | ["git", "status"] |
Bash(git -C /repo status:*) | ["git", "-C", "/repo", "status"] |
Bash(npm run test:*) | ["npm", "run", "test"] |
Bash(./install.sh:*) | ["./install.sh"] |
Accept both Bash(prefix:*) and older Bash(prefix *) forms as source syntax. Strip the
wildcard suffix and split the remaining shell words with shell-aware parsing, not by
plain whitespace. Preserve quoted arguments as one pattern element.
Decision Mapping
| Claude Code source array | Codex decision |
|---|
permissions.allow | "allow" |
permissions.deny | "deny" |
Not Portable
- Non-
Bash(...) entries such as Read(...), WebFetch(...), and MCP/tool permissions:
report as intentionally skipped.
- Bare
Bash(*), Bash(bash *), Bash(python3 *), or similarly broad shells: classify
for manual review; do not auto-port.
- Entries with shell control operators such as
|, &&, ||, ;, redirection, command
substitution, or globs: classify for manual review because Codex prefix rules match
command segments rather than full shell programs.
- Absolute paths outside the current project: classify for manual review unless the user
explicitly approves a project-specific rule.
Procedure
1. Read The Claude Code Source
Read .claude/settings.local.json from the current working directory. If it does not
exist, report that there are no project-local Claude Code permissions to translate and
stop. Do not read global Claude Code settings as a fallback.
Parse permissions.allow and permissions.deny arrays. Ignore missing arrays by
treating them as empty. Preserve each rule's source array (allow or deny) for the
Codex decision mapping.
2. Read The Codex Target
Read .codex/rules/default.rules when it exists. If it is missing, plan to create it
only if the user approves at least one translated rule.
Parse existing prefix_rule(...) blocks from .codex/rules/default.rules, including
multiline blocks. Extract pattern and decision as structured data so duplicates can
be detected before proposing additions.
3. Compute The Gap
For every Claude Code permission entry:
- translate portable
Bash(...) entries into Codex prefix_rule candidates;
- compare candidates against existing Codex rules by both
pattern and decision;
- classify each result as
new, already synced, or not portable.
If no new portable rule remains, report Already in sync - nothing to add. and stop.
4. Present The Review
Before asking for approval, show a compact summary:
Rules to add (N new)
allow:
- prefix_rule(pattern = ["git", "status"], decision = "allow")
from Bash(git status:*) - allows git status; does NOT allow git push or git reset
deny:
- prefix_rule(pattern = ["rm"], decision = "deny")
Already synced (M rules, skipped)
- ["./install.sh"] allow
Deliberately NOT ported
- Read(//home/user/project/**) non-Bash Claude permission
- Bash(python3 *) broad shell command, manual review required
Group proposed rules by practical category such as git, build-test, package-manager,
project-scripts, and other. Include the source Claude Code rule in each one-line note and
call out what the permission does not cover when that boundary is important.
5. Ask For Per-Rule Approval
Ask the user which individual rules to write. Approval must be explicit per rule, even
when all proposed rules are low risk. The "Deliberately NOT ported" section is
informational only; do not include those entries as selectable write candidates.
If the user approves nothing, make no changes and report that no Codex permission entries
were written.
6. Write Approved Rules
Append each approved rule to .codex/rules/default.rules as a prefix_rule(...) block:
prefix_rule(
pattern = ["git", "status"],
decision = "allow",
justification = "Translated from project-local Claude Code permission Bash(git status:*).",
)
If .codex/rules/default.rules does not exist, create it with a short header noting that
the file contains project-local Codex command approval rules. If .codex/ or
.codex/rules/ is missing, create only the needed directories after the user approves at
least one rule.
Deduplicate before every write. Preserve existing rules and append new blocks at the end.
Finish by listing the exact rules written and the target file path.
Guardrails
- Read only the current project's
.claude/settings.local.json. Never read global
Claude Code settings as a fallback.
- Never modify
.claude/settings.local.json, .claude/, or global Claude Code config
while syncing.
- Write only after explicit per-rule approval.
- Write only to
.codex/rules/default.rules; never write to ${CODEX_HOME:-~/.codex}.
- Never auto-port non-
Bash(...) permissions, broad shell commands, shell programs with
control operators, or absolute paths outside the current project.
- Merge with existing rules, preserve unrelated content, and deduplicate by
pattern and
decision.
- Stop cleanly when the source file is missing or when the computed gap is empty.