In v1.1.0, we made Codex policy asks fail closed. The hook could tell Codex to
allow or deny a tool call, but it could not open Codex’s approval UI. Turning an
ask into an allow would quietly skip the human. So AgentJail denied it.
Safe? Yes. Fun when a normal command matched an ask rule? Not really.
Codex already has a native approval prompt for shell commands. v1.3.0 connects that prompt to every effective AgentJail Bash ask, including asks from project and custom policy. The command runs only after you approve it in Codex.
TL;DR
- Every effective Bash ask can open Codex’s native prompt. The source can be core policy, a library pack, AWS policy, resolver policy, project policy, or a custom rule you wrote.
- The original command stays bound to one approval. Codex receives a fixed broker command carrying an opaque, single-use challenge.
- The broker fails closed. Decline, replay, expiry, daemon restart, version skew, or an identity check that cannot be verified means the original command does not run.
- Non-Bash asks still deny. v1.3.0 does not pretend Codex can prompt for hook types its native shell approval flow cannot represent.
- Git remote-update checks now parse arguments. Commands using
git -Cand branch-aware force forms are classified from executable arguments instead of raw phrase matching.
From policy ask to native prompt
The flow looks like this:
Bash tool call
-> AgentJail policy returns ask
-> hook substitutes a fixed broker command + opaque challenge
-> Codex opens its native shell approval prompt
-> approval redeems the challenge once
-> broker executes the original command
There are three details here that matter:
- Codex does not receive the original command inside the challenge. The prompt shows a bounded, redacted copy for the human, while the broker keeps the executable command on the AgentJail side.
- The hook follows the effective Bash action. It does not keep a magic list of built-in rules that happen to support approvals. If your own rule asks, the same path applies.
- Approval is not a reusable permission slip. It authorizes one typed operation in one active session at one tool-call boundary.
That last part took most of the work. Opening a prompt is easy. Making sure an old approval cannot run a different command is the security feature.
One challenge, one command
The broker binds redemption to the typed operation, Codex session, tool-call epoch, working directory, same-UID peer, and fresh process ancestry. It also has a short lifetime and can be used once.
Suppose an approved broker command gets copied from a terminal transcript and replayed later. The epoch and freshness checks reject it. If the daemon restarts, its in-memory challenges disappear. If a different process or working directory tries to redeem it, identity checks reject it.
The boring failure paths matter too:
- You decline the Codex prompt.
- Codex is running with
approval_policy=never. - AgentJail is launched with
--ignore-rules. - The challenge expires or has already been used.
- The hook and broker disagree on the protocol version.
- AgentJail cannot verify the session, peer UID, or process ancestry.
Every one of those paths ends without running the original command. There is no “approval failed, so let us try the command directly” fallback. That would make the whole prompt decorative.
Why this is Bash-only
Codex’s native permission flow can approve a shell command. That gives AgentJail a concrete operation to substitute and redeem.
A file read, patch, or MCP call does not have the same transport through the
PreToolUse hook. If policy returns ask for one of those calls, AgentJail still
sends a denial. The audit record keeps policy_action=ask and records the
effective denial separately, so you can see what policy wanted and what the
protocol could safely do.
It is a smaller claim, but it is the honest one.
Git checks now read Git
This release also removes more string guessing from remote-update policy.
A command can put global options before the subcommand:
git -C /path/to/repo push origin main
git -C /path/to/repo push --force-with-lease origin feature
AgentJail now classifies those operations from parsed executable arguments. It
understands git -C, the actual remote-update subcommand, and branch-aware force
forms. A commit message containing the word “push” is still just a commit
message. A real push remains a remote update.
Upgrade
Upgrade through the same channel you installed from:
brew upgrade agentjail
# or
agentjail update
The native approval path is wired for Codex 0.146. After upgrading, run:
codex --version
agentjail doctor
Then keep using Codex normally. When policy asks about a Bash command, the decision now appears where it should have been all along: in Codex’s own approval prompt, before the command runs.