Fine-grained, tiered permissions for AI agent CLI access.
agent-perms is an ergonomic guardrail — not a security sandbox. It makes agent automation predictable by adding deterministic, semantic classification to commands that agent platforms can only match as opaque strings. It won't stop a determined attacker or a malicious agent, but it gives well-intentioned agents (and the humans supervising them) clear, auditable intent signals so safe work runs automatically and risky work prompts.
Use this to see the value before reading full docs:
# Install
go install github.com/rgharris/agent-perms/cmd/agent-perms@main
# 1) Ask for a tier
agent-perms explain gh api --method DELETE /repos/OWNER/REPO
# Later in this README your agent permissions will be configured to block
# all commands matching `agent-perms exec admin *`
# so while this command would work, your agent cannot execute it
# `agent-perms exec admin remote -- gh api --method DELETE /repos/OWNER/REPO`
# 2) Try the wrong claim (blocked with required tier + suggestion)
agent-perms exec read remote -- gh api --method DELETE /repos/OWNER/REPO
# 3) Run a safe command with correct claim (passes through)
agent-perms explain gh api repos/pulumi/esc/pulls/595/comments
# Your agent permissions will be configured to allow `agent-perms exec read *`
agent-perms exec read remote -- gh api repos/pulumi/esc/pulls/595/commentsPrimary user: a team lead or platform-minded engineer running AI agents across repos who wants deterministic, auditable command intent policy without maintaining large allowlists.
Best fit:
- Teams using Claude Code and/or Codex that want one shared policy language (
read/write/admin+local/remote) - Teams that care about reviewability and reproducible behavior more than maximum autonomous speed
Not the main target:
- Users running in fully bypassed/yolo modes who intentionally skip policy gates
Supported CLIs: esc (Pulumi ESC), gh (GitHub CLI), git, go, kubectl, pulumi
Tier model: Commands are classified across two dimensions:
| Local | Remote | |
|---|---|---|
| Read | Inspect local state (git log, go vet) |
Query remote APIs (gh pr list, git fetch) |
| Read-sensitive | — | Expose secrets (gh auth token, pulumi env open) |
| Write | Mutate local state (git commit, go fmt) |
Mutate remote state (git push, gh pr create) |
| Admin | Destructive local ops (git reset --hard, go clean -cache) |
Destructive remote ops (git push --force, gh repo delete) |
Tiers use exact matching — write does not cover read, and read does not cover read-sensitive. Each tier is independent.
At a glance:
- Deterministic classification in Go using CLI + subcommand + flags (for example,
git pushvsgit push --force) - Two-layer enforcement: agents are instructed to use
agent-perms, and direct CLI access is denied by outer rules - Exact tier matching: if an agent claims the wrong tier, the command is denied with the required tier
- One-time setup for Claude Code and Codex (
agent-perms <platform> init)
AI coding agents let you allowlist shell commands so they run without prompting. Those allowlists are hard to maintain and encourage permissive wildcards like gh *, even though agents frequently use gh api for routine reads (PR comments, reviews, metadata) and the same command can also mutate or delete data based on flags. They also cannot distinguish git reset --soft from git reset --hard, or a safe gh api GET from a destructive DELETE.
agent-perms adds a semantic layer between your agent and your CLIs. You define which tiers run automatically, and the agent declares its intent upfront. One rule replaces dozens of individual command allowlists.
# Classified as "read remote" — auto-approved
agent-perms exec read remote -- gh pr list
# Classified as "read-sensitive remote" — prompts (exposes secrets)
agent-perms exec read-sensitive remote -- pulumi env open myorg/prod
# Classified as "admin remote" — prompts you
agent-perms exec admin remote -- gh api --method DELETE /repos/OWNER/REPO
# Claimed tier must match exactly — wrong tier is denied:
# ERROR: denied. 'gh api --method DELETE /repos/OWNER/REPO' requires 'admin remote', claimed 'read remote'.
agent-perms exec read remote -- gh api --method DELETE /repos/OWNER/REPOAgents do not discover agent-perms on their own. The init commands for each platform inject instructions that tell the agent to wrap CLI commands with agent-perms exec:
- Claude Code:
agent-perms claude initadds aSessionStarthook that runsagent-perms claude md, injecting usage instructions (theagent-perms execsyntax and examples for each CLI) at session start. - Codex CLI:
agent-perms codex initwrites anAGENTS.mdfile (loaded automatically by Codex) with the same instructions.
In both cases, the agent sees instructions like "run CLI commands through agent-perms exec <action> <scope> -- <cli> <subcommand>" and follows them. Permission rules then ensure the agent cannot bypass agent-perms by calling CLIs directly; those commands are denied.
Agent allowlists match command strings; they have no visibility into flags. This makes common cases impossible to handle safely:
| Command | Problem |
|---|---|
git reset --hard |
Can't distinguish --soft (safe) from --hard (destroys uncommitted work) |
git push --force |
Can't distinguish a normal push from one that rewrites remote history |
gh api /repos/.../pulls/.../comments |
Common read path for PR context, but command-string allowlists cannot separate it from write/delete API calls |
gh api --method DELETE /repos/… |
Same gh api subcommand, but method/path can permanently delete data |
git config --get vs git config --global |
Same subcommand, opposite risk: one reads a value, the other mutates global config |
agent-perms classifies commands with full flag awareness, so git reset and git reset --hard land in different tiers. Your agent's allowlist rules stay simple; the semantic work happens inside agent-perms.
Agent platforms are converging on coarse-grained safety mechanisms — sandboxes, pattern matching, hooks — but none has semantic command classification. The gap isn't "too many prompts vs. not enough prompts." It's that no platform can distinguish git reset --soft from git reset --hard, or a gh api GET from a gh api --method DELETE, using built-in rules alone.
Claude Code: Glob patterns like Bash(git reset *) match both safe and destructive variants. Claude Code's own docs acknowledge this: "Bash permission patterns that try to constrain command arguments are fragile." One agent-perms exec rule replaces dozens of pattern entries while adding flag-level classification that globs cannot express. agent-perms also works as the classification engine behind PreToolUse hooks.
Codex CLI: Starlark prefix_rule() entries match command prefixes but have no concept of what a command does. agent-perms adds semantic intent on top of sandbox and exec policy defaults — biggest value for teams needing auditable, deterministic command policies across CLIs.
Both platforms: Teams using both Claude Code and Codex get one semantic policy that works on both. The same read/write/admin tiers apply regardless of which agent runs the command.
go install github.com/rgharris/agent-perms/cmd/agent-perms@mainMake sure $(go env GOPATH)/bin is on your PATH.
Current install is Go-first by design (works well for teams already on Go tooling). Additional install options (for example, package manager releases) are planned.
One command generates a settings.json with permissions, deny rules, and a SessionStart hook:
$ agent-perms claude initYou'll be prompted to choose a profile. If you already have a ~/.claude/settings.json, rules are merged automatically. See Claude Code setup for details.
One command generates exec policy rules and AGENTS.md:
$ agent-perms codex initYou'll be prompted to choose a profile and confirm writing. This creates ~/.codex/rules/agent-perms.rules and ~/.codex/AGENTS.md. See Codex CLI setup for details.
Note: Codex support is experimental. The core classification and exec enforcement work, but Codex's permission model differs significantly from Claude Code's and has not been tested as extensively. If you hit issues, please open an issue.
Use agent-perms explain to see how a command is classified:
$ agent-perms explain gh secret set TOKEN
cli: gh
command: secret set
base_tier: admin remote (gh secret set)
result: admin remote
$ agent-perms explain git push --force
cli: git
command: push
base_tier: write remote (git push)
flags: --force → admin remote
result: admin remoteBoth Claude Code and Codex use the same three profiles:
| Profile | Description |
|---|---|
read |
Read access for all CLIs (non-sensitive); writes prompt; admin denied |
write-local |
Read + local writes (git commit, go fmt, etc.); remote writes prompt; sensitive prompts; admin denied |
full-write |
Read + write for all CLIs (including remote); sensitive prompts; admin denied |
write-local is the recommended default profile for day-to-day development.
$ agent-perms claude initIf ~/.claude/settings.json exists, rules are merged into it automatically. The generated settings include:
- Permissions: allow/deny rules that auto-approve the right tiers and block direct CLI access
- SessionStart hook: runs
agent-perms claude mdto inject usage instructions into every session
To merge into a specific file:
$ agent-perms claude init --merge=~/.claude/settings.json$ agent-perms claude validateClaude Code's glob match (Bash(agent-perms exec read remote -- gh *)) is the outer gate. If Claude tries to skip agent-perms and run gh api --method DELETE ... directly, the deny rule blocks it. agent-perms exec is the inner gate, enforcing tier semantics independently.
See examples/claude-settings.md for granular profiles, per-CLI rules, and mixing broad and fine-grained patterns.
$ agent-perms codex initThis creates:
~/.codex/rules/agent-perms.rules— Starlarkprefix_rule()entries~/.codex/AGENTS.md— usage instructions for all supported CLIs
The workspace-write sandbox blocks network by default. Many commands need it (gh, git push, pulumi up). Add to ~/.codex/config.toml:
[sandbox_workspace_write]
network_access = true$ agent-perms codex validateCodex applies the most restrictive decision when multiple rules match (forbidden > prompt > allow). The generated rules:
- Allow agent-perms exec commands at the profile's tier level
- Forbid direct CLI access (
gh,git,go,pulumiwithout agent-perms) - Forbid admin operations in all profiles
The exec policy is the outer gate; agent-perms exec is the inner gate.
See examples/codex-settings.md for profile details, sandbox mode interaction, and rule precedence.
agent-perms is a guardrail, not a sandbox. It relies on agents following instructions and on outer platform rules denying direct CLI access. It does not defend against:
- Shell wrappers and indirection — an agent can call
/usr/bin/gitby full path, invokeenv git ..., or usecommand git ...to bypass deny rules that match onlygit. - Environment variable injection — setting
GIT_SSH_COMMAND,GH_TOKEN, or similar vars before a command can change what the command does in ways the classifier cannot see. - Git hooks and aliases —
.git/configaliases or hook scripts can execute arbitrary code triggered by otherwise-safe commands. - Unsupported CLIs — only
esc,gh,git,go,kubectl, andpulumiare classified. Other CLIs pass through unclassified and must be handled by platform-level rules.
The outer platform layer (Claude Code deny rules, Codex exec policy forbidden entries) is the primary enforcement boundary. agent-perms adds semantic classification that the platform cannot express on its own.
Treat agent-perms as semantic policy and workflow control, not as your final security boundary.
- Keep platform sandboxing enabled (
workspace-write/read-only) whenever possible - Keep direct CLI deny/forbidden rules enabled so agents must route through
agent-perms exec - Keep
--on-unknown=denyas default outside short evaluation sessions - Use
readorwrite-localprofiles by default; escalate intentionally for risky operations - If you must run Codex with
--sandbox danger-full-access(for example, current macOS network caveat), treatagent-permsas your primary command-intent gate for that session and keep admin tiers blocked or prompted
This project is a practical near-term tool and proof-of-concept for semantic CLI classification in agent workflows.
- Goal: make current platforms safer and more predictable today
- Non-goal: compete head-to-head with major AI platform vendors on full security/runtime stacks
- If platforms ship strong native subcommand+flag classification, this project can narrow to reference taxonomy, policy examples, and migration support