# Codex Rules: Control Commands with prefix_rule

> Learn how to set Codex command rules with prefix_rule: allow, prompt or forbid, test them with codex execpolicy check, and avoid the shell traps.

Canonical: https://bridge-terminal.com/atlas/blog/codex-rules-prefix-rule-allow-forbid-commands/
Last updated: 2026-11-12

Published 12 November 2026 · Technical · How-to · 6 min read

## The short version

- Codex rules are .rules files that decide, per command prefix, whether a command runs without asking, asks first, or is blocked.
- When several rules match one command, the most restrictive wins: forbidden beats prompt, and prompt beats allow.
- Test rules with codex execpolicy check before relying on them, and put match and not_match examples in the rule so Codex validates them on load.
- Rules match an exact prefix of the command, so option order matters; shell scripts using redirection, substitution, variables or wildcards are judged as one whole command.
- Project rules in .codex/rules only load when the project's .codex layer is trusted, and the feature is marked experimental.

If you want Codex to stop asking about commands you always approve, and to refuse commands you never want run, you write rules. Codex rules are small `.rules` files that match a command's prefix and give it a decision: allow, prompt or forbidden. This guide shows where the files go, how `prefix_rule` works, how to test a rule before trusting it, and where compound shell commands can surprise you.

Everything about Codex behaviour below comes from OpenAI's [Codex rules documentation](https://learn.chatgpt.com/docs/agent-configuration/rules). The docs mark rules as experimental and subject to change, so re-check the page before you roll anything out to a team. The old [execpolicy page in the openai/codex repository](https://github.com/openai/codex/blob/main/docs/execpolicy.md) is now only a pointer to the hosted docs.

## What are Codex rules?

Rules control which commands Codex can run outside the sandbox. They sit alongside the approval mode and sandbox you already configure: approval mode answers "how much does Codex ask in general", and rules answer "what about this specific command".

A rule has three possible decisions:

- `allow`: the command runs without prompting.
- `prompt`: Codex asks before each matching run.
- `forbidden`: Codex blocks the request.

If you do not give a decision, the default is `allow`. Keep that in mind when you copy a rule and forget the `decision` line.

## Where do the rules files go?

Create a `.rules` file in a `rules/` folder next to an active config layer. The documented example is `~/.codex/rules/default.rules`. Codex scans the `rules/` folder in every active config layer at startup, including Team Config locations and your user layer.

Two details matter in practice:

- Project-local rules in `<repo>/.codex/rules/` load only when the project's `.codex/` layer is trusted. A cloned repo you have not trusted will not silently apply its own rules.
- When you add a command to the allow list from the terminal UI, Codex writes it to `~/.codex/rules/default.rules`. That file can grow without you editing it, so read it now and then.

Restart Codex after adding a rule.

The format is Starlark, a Python-like language designed so that evaluating it has no side effects. A rules file can only describe matches.

## How do you write a prefix_rule?

`prefix_rule()` takes these fields:

- `pattern` (required): a non-empty list. Each element is either a literal string or a list of alternatives for that argument position.
- `decision`: `allow`, `prompt` or `forbidden`. Defaults to `allow`.
- `justification`: a human-readable reason that can show up in approval prompts or rejection messages. For `forbidden`, it can suggest an alternative.
- `match` and `not_match`: lists of example commands that Codex validates when it loads the rules, to catch mistakes early.

This is the example from the documentation:

```python
prefix_rule(
    pattern = ["gh", "pr", "view"],
    decision = "prompt",
    justification = "Viewing PRs is allowed with approval",
    match = [
        "gh pr view 7888",
        "gh pr view --repo openai/codex",
        "gh pr view 7888 --json title,body,comments",
    ],
    not_match = [
        # Does not match because the `pattern` must be an exact prefix.
        "gh pr --repo openai/codex view 7888",
    ],
)
```

The comment in `not_match` is the important lesson. The pattern is an exact prefix of the command's words. `gh pr --repo openai/codex view 7888` is the same operation to a human, but the words are in a different order, so the rule does not match it. Write rules for the form your team actually types, and add the awkward orderings to `not_match` so you can see the gap.

### A forbidden rule with an alternative

Here is a rule of the same shape that I wrote as an illustration, not one from the documentation. It blocks force pushes and uses alternatives at the last position of the pattern:

```python
prefix_rule(
    pattern = ["git", "push", ["--force", "-f"]],
    decision = "forbidden",
    justification = "Force pushes are blocked. Use a new commit or ask a maintainer.",
    match = [
        "git push --force",
        "git push -f",
    ],
    not_match = [
        "git push origin main",
    ],
)
```

Notice what it does not catch. `git push origin --force` has the flag after `origin`, so this prefix does not match it. A rule like this is a speed bump for the common spelling, not a guarantee. For anything you truly cannot allow, combine rules with the sandbox and with branch protection on the server side.

### Allowing the boring commands

The other half of the job is trimming prompts. A read-only command you run all day is a good candidate:

```python
prefix_rule(
    pattern = ["git", "status"],
    decision = "allow",
    match = ["git status", "git status --short"],
)
```

Allow narrow prefixes. `["git", "status"]` is a safer thing to approve than `["git"]`, which would cover every Git subcommand.

## How do you test rules before relying on them?

Use `codex execpolicy check` to see how your rules apply to a command:

```bash
codex execpolicy check --pretty \
  --rules ~/.codex/rules/default.rules \
  -- gh pr view 7888 --json title,body,comments
```

Pass `--rules` more than once to combine files, which is how you can test a project rules file together with your personal one.

A practical routine:

1. Write the rule with `match` and `not_match` examples, so Codex checks them when it loads the file.
2. Run `codex execpolicy check` on three or four real commands, including one you expect not to match.
3. Restart Codex and try the command in a real session.
4. Commit project rules only after a teammate has run the same check on their machine.

## What happens when two rules match?

The most restrictive decision applies: `forbidden` beats `prompt`, and `prompt` beats `allow`. So you can allow a broad prefix and then add a stricter rule for a dangerous variant, and the stricter one wins. Admins can also enforce restrictive `prefix_rule` entries through `requirements.toml`, which gives a team a way to set limits that personal rules do not override.

## Shell wrappers and compound commands

Agents rarely run bare commands. They often run `bash -lc "..."`. Codex treats `bash -c`, `bash -lc` and the `zsh` and `sh` equivalents specially, and the behaviour decides whether your rules protect you.

- If the script is a simple chain of plain words joined by `&&`, `||`, `;` or `|`, Codex splits it and evaluates each command separately. For example, `git add . && rm -rf /` is evaluated as `git add .` and `rm -rf /`, so allowing `git add` does not allow the whole line.
- If the script uses redirection, substitution, environment variables, wildcards or control flow, Codex does not split it. It treats the whole invocation as one command and applies rules to that.

The second case is where allow rules get less useful. A line such as `git status > out.txt` is one command to Codex, so check what your `["git", "status"]` rule does with it using `codex execpolicy check` rather than assuming. Test your real habitual command lines, not only the tidy ones.

## Smart approvals and the allow list

With Smart approvals, which are on by default per the docs, Codex may suggest a `prefix_rule` when it escalates a command. That is convenient and also the easiest way to approve something too broad by reflex. Read the proposed pattern. If it is shorter than you expected, narrow it before you accept.

## Common mistakes

- Forgetting that `decision` defaults to `allow`.
- Writing a pattern that is too short, so it covers more than intended.
- Assuming option order does not matter. It does, because the match is an exact prefix.
- Expecting project rules to apply in a repo whose `.codex/` layer you have not trusted.
- Relying on rules for security by themselves. They are experimental, and a prefix match is only one layer.
- Assuming Work Cloud setups read local files. The docs say local `.rules` files don't apply there; Work Cloud containers follow existing Work Cloud policies, and admins set supported command rules in the `rules` TOML field in Agent Security.

## Conclusion

Codex rules turn "approve this again" into a decision you make once, in a file you can review and test. Start with a few narrow `allow` rules for commands you run constantly, add `forbidden` rules with a justification for the commands that should never run, and always run `codex execpolicy check` on real command lines before trusting the result. Treat the whole feature as experimental, and keep the sandbox and server-side protections as your backstop.

## Questions people ask

### What is a Codex prefix_rule?

It is a rule in a .rules file that matches the first words of a command and gives it a decision: allow, prompt or forbidden. The pattern must be an exact prefix of the command, so words in a different order do not match.

### How do I test a Codex rule?

Run codex execpolicy check --pretty with --rules pointing at your rules file, then -- and the command. You can pass --rules several times to combine files. You can also add match and not_match examples to the rule, which Codex validates on load.

### What happens if two Codex rules match the same command?

The most restrictive decision applies. Forbidden beats prompt, and prompt beats allow.

### Where do Codex rules files live?

In a rules folder next to an active config layer, for example ~/.codex/rules/default.rules. Project rules in <repo>/.codex/rules/ load only when the project's .codex layer is trusted. Restart Codex after adding a rule.

### Are Codex rules safe enough to be my only protection?

No. The documentation marks rules as experimental and they match command prefixes, so variants can slip through. Use them with the sandbox and with protections on the server side.

## About Atlas: Fixed lines for the team, set by the operator

Atlas runs on Claude Code rather than Codex, so Codex rules files do not apply to it. A similar idea appears in how it works: production go-lives, spending, deleting data, sending anything outside and dropping scope always wait for you, even with Run unattended on. See the Atlas home page at /atlas/. — https://bridge-terminal.com/atlas/

## Sources

- [Codex rules (OpenAI docs)](https://learn.chatgpt.com/docs/agent-configuration/rules)
- [openai/codex execpolicy doc pointer](https://github.com/openai/codex/blob/main/docs/execpolicy.md)

_Researched and drafted with Claude, then checked against the sources above. Atlas is an independent product, not affiliated with Anthropic or OpenAI._

## Related

- [Claude Code Permissions: Allow, Deny Rules and Modes](https://bridge-terminal.com/atlas/blog/claude-code-permissions-allow-deny-rules/)
- [Claude Code Sandbox: Limit Files and Network for Bash](https://bridge-terminal.com/atlas/blog/claude-code-sandbox-bash-files-network/)
- [Prompt Injection Explained: A Plain Guide for Founders](https://bridge-terminal.com/atlas/blog/prompt-injection-plain-guide-ai-coding-agents/)
