sync-codex-permissions — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited sync-codex-permissions (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
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.
| Claude Code source array | Codex decision |
|---|---|
permissions.allow | "allow" |
permissions.deny | "deny" |
Bash(...) entries such as Read(...), WebFetch(...), and MCP/tool permissions:report as intentionally skipped.
Bash(*), Bash(bash *), Bash(python3 *), or similarly broad shells: classifyfor manual review; do not auto-port.
|, &&, ||, ;, redirection, commandsubstitution, or globs: classify for manual review because Codex prefix rules match command segments rather than full shell programs.
explicitly approves a project-specific rule.
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.
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.
For every Claude Code permission entry:
Bash(...) entries into Codex prefix_rule candidates;pattern and decision;new, already synced, or not portable.If no new portable rule remains, report Already in sync - nothing to add. and stop.
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 requiredGroup 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.
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.
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.
.claude/settings.local.json. Never read globalClaude Code settings as a fallback.
.claude/settings.local.json, .claude/, or global Claude Code configwhile syncing.
.codex/rules/default.rules; never write to ${CODEX_HOME:-~/.codex}.Bash(...) permissions, broad shell commands, shell programs withcontrol operators, or absolute paths outside the current project.
pattern anddecision.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.