Proposal: Explicit Execpolicy Amendment Persistence Choice between Project-Local or Global

Open 💬 0 comments Opened Jun 19, 2026 by McDonald-Andrew

Summary

I would like to propose TUI approvals for execpolicy amendments that let users explicitly choose whether a rule is scoped to the current project/repo or globally across projects.

Today, Codex's TUI offers to remember approved command prefixes only at the global level. This, however, can make the trust decision broader than the user intended.

_This proposal is meant to connect several existing issues rather than duplicate them. Please also see below [Issues this Prototype Proposal Addresses](#issues-this-prototype-proposal-addresses)_

_[A demo video is also available at bottom of this issue](#demo-video)_

Prototyped Proposed Behavior:

  • When a user accepts an execpolicy amendment during command approval, Codex should distinguish between:
  • Saving the execpolicy amendment for the current project/repo (e.g. <repo>/.codex/rules/default.rules)
  • Saving the execpolicy amendment globally for the user (persists across projects/repos)
  • Scoping execpolicy amendments to the current local project should be the safer and default path
  • Scoping execpolicy amendments globally should remain available, but require an explicit choice
  • If project scope cannot be resolved safely, Codex should warn and skip persistence rather than falling back to global execpolicy amendments.
  • If the current project is trusted but no .codex/ folder exists yet, choosing the project-local option initializes .codex/rules/default.rules.
  • The TUI makes the scope obvious (e.g. "_Approve prefix in this repo_", "_Approve prefix globally_")

This is intended to avoid accidentally granting equivalent command trust across all repositories.

Prototyped Safety Properties

The important safety properties are:

  1. No Implicit Global Persistence.

A project-local approval should not become a global user rule unless the user explicitly chose the global option.

  1. Warn and Skip Persistence for Unresolved Project Scope.

If Codex cannot resolve the trusted project-local .codex layer, it should warn and not persist the amendment. It should not silently fall back to the global rules file.

  1. Keyboard Shortcut should Prefer Safer Scope.

The keyboard shortcut for "_Approve this prefix..._" (currently the _p_ key) should map only to the project-local option. A global approval should require an explicit selection.

  1. Protocol should Carry the Scope.

The approval decision should carry an explicit scope through the protocol/app-server/TUI/session/core path so the write target is never inferred later from legacy behavior.

I am opening this as an issue first per the contribution guidance, and only mentioning the prototype branch in case maintainers want to invite a PR.

Current Documented Workaround with Codex

According to the Codex Rules documentation, Codex already supports project-local rules, but the TUI allow list path persists execpolicy amendments to the user's home level .codex/rules/default.rules (global).

In order to have rules scoped to the project/repo, you must perform the following:

  1. Manually create or edit <repo>/.codex/rules/default.rules.
  2. Manually write the correct prefix_rule(...) yourself.
  3. Restart Codex.
  4. Ensure the project's .codex/ layer is trusted.

Steps 1-3 must be repeated each time a new project-local rule is needed, as Codex generally cannot freely edit the project-local .codex folder within the lower risk :read-only or :workspace sandbox modes without an explicit permission override.

But at that point, the governance gap becomes moot, since Codex now has write-access to the local project's .codex/rules.

The TUI approval flow is independent of LLM file edit behavior and is specifically controlled by an explicit user approval decision.

The missing behavior here is not that "_project-local rules don't exist_" (they do exist), the missing behavior is an explicit TUI option to persist execpolicy amendments to the project-local rules instead of globally.

Why It Matters

A command prefix that is safe and expected inside one project/repo is not necessarily safe in another.

For example:

  • ./scripts/deploy.sh
  • ./scripts/cleanup.sh
  • npm run release
  • npm run publish
  • make deploy
  • make reset
  • terraform apply
  • kubectl apply -f

In one repo, one of these commands may be harmless. In another repo, the same prefix could deploy infrastructure, publish packages, mutate databases, alter resources, rotate credentials, delete generated assets, or run cleanup logic with bad consequences.

These are exactly the kinds of commands users may want Codex to remember during a focused workflow. But if the execpolicy amendment is written globally, a project-specific approval can become a permission across all repositories. That is a much larger trust decision than one may intend when clicking an "_always_" or "_approve prefix_" option during a single workflow.

An execpolicy amendment scoped to the local project would let Codex remember the practical approval while keeping the permission boundary aligned with only the project where the approval was made.

Prototyped Implementation

The prototype implementation introduces an explicit scope for approved execpolicy amendments:

pub enum ExecPolicyAmendmentScope {
    UserDefault,
    ProjectDefault,
}

That scope can then resolve into a concrete persistence target at the session/core boundary:

pub enum ExecPolicyAmendmentTarget {
    UserDefault,
    ProjectDefault(PathBuf),
}

For ProjectDefault, the target would resolve to <repo>/.codex/rules/default.rules.

For UserDefault, the behavior would preserve the existing global user-default write path.

The approval handler would resolve the target before persistence.

If resolution fails for project scope, Codex would emit a warning and skip persistence rather than falling back globally.

Issues this Prototype Proposal Addresses

This is not intended to claim that this prototype fixes every issue below. Rather, these issues point toward the same governance need: explicit user-controlled trust scopes between constant approvals and global authorization.

Related Issues

| Issue | Relevance |
| ------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| #16167 | Identifies global exec approval-rule persistence as a safety footgun and argues that repo-local persistence should be the safer default.
| #21018 | Proposes user-selectable approval scopes in command prompts, which overlaps with making approval persistence scope explicit to the user.
| #27157 | Highlights the need to review and manage saved command-approval rules, including rules that may currently be persisted globally.
| #3085 | Requests commands that do not need repeated permission. This proposal adds the missing project-local vs global governance layer for command allow-list behavior. |
| #17623 | Asks for reusable authorization scope to be clear, including exact command, prefix, working directory, argv shape, sandbox escape, and "in this repo" options. |
| #12716 | Requests an allow list instead of danger-full-access plus deny list, especially for regulated environments. |
| #3960 | Requests command permission modes such as always block, always ask, always allow, whitelist, and blacklist behavior. |
| #24596 | Reports that "don't ask again" generated the wrong prefix for piped commands. Project-local approval persistence reduces impact of an approved prefix if broader or different than expected. |
| #26108 | Notes that adding safe commands to default.rules allows them outside the sandbox and bypasses the filesystem confinement. |
| #16695 | Asks for a command prefix to be allowed only for one automation, not globally for all threads. |
| #11176 | Asks for a middle ground between "always allow" and "prompt every time," with consistent UI/config/protocol behavior. |
| #17028 | Requests trusted repo/project behavior with repo-scoped or user-scoped config. |
| #6490 | Asks for commands run in a directory to be written into config and reused later, as a more controllable alternative to full access. |

Supporting Related Issues

| Issue | Relevance |
| ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| #12190 | Need for broader command-policy and governance hooks. |
| #2847 | Requests repo-local and global sensitive-file exclusions. Supports the principle that project-local and user-global policy should be separable. |
| #20917 | Asks to separate where a command runs from whether it is allowed. |
| #11580 | Supports scoped trust instead of repeated approvals through whitelisted folders. |
| #14601 | Strong project-vs-global state analogy: objects to project-specific trusted metadata being written into global ~/.codex/config.toml. |
| #3821 | User could not find allowlist documentation and was trying to allow commands such as msbuild. |
| #9164 | User manually configured both repo-local and user rules, including <repo-root>/.codex/rules and ~/.codex/rules. |
| #20210 | Strong project-vs-global state analogy: project-local config loads, but project-local _skill_ filters do not override globally installed _skills_. |
| #7959 | Strong project-local .codex support: Ask for repo-level .codex/ customization and names .codex/rules/ as contextual/scoped rules. |
| #8778 | Generated-prefix issue: "_don't ask again_" produced a too-narrow prefix. Generated command behavior is safer when scoped explicitly to local project by default. |
| #14338 | Exception governance issue: user wants current-worktree Git metadata writable while staying in sandboxed workspace-write. |
| #24742 | Requests user-provided Seatbelt sandbox rules because current workarounds are command escalation or danger-full-access. |
| #11583 | Workspace boundary issue: user reports Codex editing outside intended folder without permission requests. |
| #22023 | Env-var include allowlists supporting narrow explicit policy instead of global trust. |
| #14399 | Requests fine-grained permissions, including command classes, severity, folder/repo limits, and blocked Git commands. |

Prototype Available if Useful

Per the contributing.md guidance, I am opening this as an issue first rather than submitting an unsolicited PR.

I have a focused prototype branch available in my fork if the Codex team thinks this approach aligns with the intended direction and would like to invite a PR: https://github.com/McDonald-Andrew/codex/pull/1

I am not asking maintainers to review an unsolicited upstream PR. I am sharing my branch only as implementation evidence.

Commit Summary:

  • Threads explicit execpolicy amendment scope through approval protocol, app-server conversion, TUI decision handling, session handling, and persistence
  • Adds project-local and user-global persistence approval targets
  • Preserves original global approval behavior as an available option
  • Writes project-scoped amendments to <repo>/.codex/rules/default.rules
  • Initializes project-local .codex/rules/ when trusted repo has no existing .codex/ folder yet
  • Warns and skips persistence when project scope cannot be resolved
  • Distinguishes TUI labels for "_in this repo_" vs "_globally_"
  • Routes prefix approval keyboard shortcut only to project-local persistence
  • Includes tests for project-scoped writes and global-shortcut safety
  • Has been rebased cleanly onto a fork current with openai/codex main and manually tested

I am happy to adapt the branch to the maintainers' preferred naming, UI wording, protocol shape, or persistence behavior if maintainers agree this is a direction worth pursuing and want to invite a PR.

Demo Video

I recorded a short demo showing the project-local execpolicy amendment flow end-to-end, including the UI choice between saving an amendment for the current repo versus globally.

https://drive.google.com/file/d/178XVKe2Hd2YU-AkxHWN91cyWZuubOB7z/view?usp=sharing

_The video is hosted externally since the recording is 181 MB and exceeds GitHub's native issue attachment limit_.

View original on GitHub ↗