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 pro...
Scanned 6/9/2026
Install via CLI
openskills install ada-ggf25/AI-Tools---
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:
```text
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:
```text
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.
No comments yet. Be the first to comment!