agentperm
Stop approving the same safe command because a flag moved or it entered a pipe.
agentperm gives Claude Code, Codex CLI, OpenCode, Gemini CLI, and Kiro one local permission policy. It parses shell programs, evaluates every command, and applies the strictest result. You review intent once instead of maintaining five fragile string allowlists.
https://github.com/user-attachments/assets/9abcd24d-147c-4323-a1c3-970544e0d86a
One command, fully understood
This policy allows read-only AWS inspection, jq, and git status:
{
"version": 1,
"permissions": {
"allow": [
"Shell(aws values(--region, --profile) ec2 describe-* only(--region, --profile))",
"Shell(jq !-*)",
"Shell(git values(-C) status only(-C, --short))"
]
}
}
Now an agent can run this without a prompt:
bash -lc 'aws --profile dev ec2 describe-instances --region ap-southeast-2 | jq ".Reservations[]" && git -C . status --short'
agentperm unwraps bash -lc, splits the pipe and &&, and checks aws, jq, and git
independently. Move --profile or --region before or after the AWS subcommand, or use
--region=value: the same reviewed rule still matches.
The rule does not become broad just because it is flexible. Add --endpoint-url, change
describe-* to a mutating operation, or insert an unknown pipeline stage and the compound prompts.
A deny anywhere denies the whole operation.
That structural evaluation is the difference: agentperm understands pipelines, command and process substitutions, redirects, executable paths, quoting, supported wrappers, flag clusters, and declared flag values. It matches normalized commands—not one opaque shell string.
Try it
Requires Python 3.12+ on macOS or Linux.
uv tool install agentperm # or: pipx install agentperm
agentperm install --dry-run && agentperm install
agentperm init
install --dry-run shows every hook file before anything changes. init builds
~/.agent-permissions.jsonc from conservative starter templates. Check a decision without running
an agent:
$ agentperm why "git status | head -5"
allow — allow by rule 'Shell(git {status,log,diff,show,blame,shortlog,describe,reflog} values(-C))'
git status → allow (...)
head -5 → allow (...)
Then use your agent normally. Existing native settings stay in place and continue to participate in the host's permission flow. See Getting started for installation modes, starter policies, and the first safe customization.
What one policy can express
- Shell structure: each command in pipes, chains, substitutions, control flow, and supported wrappers is evaluated independently.
- Useful permutations: declare value-taking flags once; their order and
--flag=valuespelling can vary without widening the rule. - Precise constraints: alternate command paths, require or forbid flags, reject extra operands, and allow only reviewed flags.
- Semantic file controls: write
Edit(src/**)andWrite(dist/**)once. Agent-specific edit, write, notebook, and patch operations map to those capabilities. - Scoped tools: match tools by name, prefix, URL domain, or normalized path, including cwd, traversal, and existing symlinks.
- Read-only inline Python:
Python(readonly)parses literalpython -cand heredoc source with Python's AST, allowing inspection while surfacing recognized mutations and dynamic effects. - Layered policy: combine a global policy with directory policies. Global Deny is an immutable floor; for Ask and Allow, the nearest matching policy wins, so a project can whitelist a global prompt without weakening a deny.
- Explainable decisions:
why, custom rule reasons, validation, and opt-in JSONL traces show why a decision happened. - Portable setup: install directly or through Rulesync, and import supported native policies.
The complete per-agent differences are in the capability matrix.
Rules in 60 seconds
Rules live in permissions.allow, permissions.ask, or permissions.deny:
{
"version": 1,
"permissions": {
"allow": [
"Shell(git {status,log,diff} !-*)",
"Shell(aws values(--region) s3 ls only(--region))",
"Read(src/**)",
"Python(readonly)"
],
"ask": [
"Shell(git push)"
],
"deny": [
{"Edit(generated/**)": {"reason": "Generated file; update its source instead."}},
{"Write(generated/**)": {"reason": "Generated file; update its source instead."}},
"Shell(git push --force)",
"Shell(sudo)"
]
}
}
Useful Shell forms:
| Form | Meaning |
|---|---|
{status,log,diff} |
one of these command-path tokens |
describe-* |
glob within one token |
values(--region) |
--region consumes the following token |
only(--region, --profile) |
reject every other flag |
!--force |
reject this flag |
!-* |
reject every flag |
!... |
reject trailing operands |
Run agentperm validate after editing. The policy reference covers the
whole file format; the Shell pattern DSL is the exact grammar and matching
specification.
How decisions compose
agentperm returns allow, ask, deny, or no-opinion. After policy-layer precedence selects a
verdict for each operation, the strictest result within a compound request wins:
deny > ask > allow > no-opinion
An otherwise allowed pipeline with one unknown command becomes Ask. A multi-file patch with one
denied destination becomes Deny. no-opinion lets the host continue its native flow.
Policies load from ~/.agent-permissions.jsonc and then from every directory between the filesystem
root and the command's working directory. Deny matches across every layer. For Ask and Allow, the
nearest policy with a matching rule wins; within one file, Ask precedes Allow. A cloned repository
can therefore bring its own allows, so review checked-in policy files like .envrc or
.vscode/tasks.json.
Security boundary
agentperm is a permission intent layer, not a sandbox. It does not contain processes, prove what an allowed program will do, or see execution paths a host does not send through hooks. Host bypass mode can bypass agentperm entirely. Use OS isolation when containment matters and read SECURITY.md before treating policies as a security control.
- It adds decisions to native permission flows; it does not replace host settings.
- It does not configure or isolate MCP servers.
- Directory policies are not trust-gated: a cloned repository can add allows and override global Ask rules, though it cannot weaken any Deny.
- Shell and Python analysis classify reviewed intent; they do not prove program behavior.
Traces are also diagnostic—not a production audit system. They are off by default, may contain raw commands and secrets, and have no built-in redaction, rotation, retention, or tamper protection. See CLI: diagnostic traces.
There is no SQL syntax analyzer today. SQL clients can be constrained with Shell rules, but
agentperm does not distinguish SELECT from mutating SQL inside a query string.
Zellij pane bypass
The bundled Zellij plugin adds a per-pane “skip prompts” toggle. It turns Ask and NoOpinion into Allow for that pane while preserving Deny, making it narrower than a host-wide “dangerously skip permissions” mode.
Documentation
- Getting started — install, initialize, and verify a policy.
- Capability matrix — exact coverage and behavior by agent.
- Policy reference — schema, semantic tools, hierarchy, and redirects.
- Shell pattern DSL — complete matching grammar and limitations.
- CLI reference — commands, hook installation, traces, and exit behavior.
- Troubleshooting — symptom-led diagnosis and fixes.
- Architecture and adapter notes — contributor internals.
- Changelog and contributing guide — releases and development.
agentperm uninstall removes only hooks written by agentperm; policy files remain yours. Then remove
the package with uv tool uninstall agentperm or pipx uninstall agentperm.
License
MIT
Metadata
Release files for agentperm 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| agentperm-0.4.0.tar.gz | 114.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agentperm-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 193.1 kB
Release files / agentperm-0.4.0.tar.gz
| Download URL | agentperm-0.4.0.tar.gz |
|---|---|
| Size | 114.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
730d13f21e4fa4f85aa3bcd78461b73692e5c71d5287eb6c0dddf90afcb7bf4e
|
|
BLAKE2b-256 checksum How to use checksums |
f6575c4adf6d5f9c1b7222a22c92bde1ca86dcba95ed5af2a472a984fea4edd6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / agentperm-0.4.0-py3-none-any.whl
| Download URL | agentperm-0.4.0-py3-none-any.whl |
|---|---|
| Size | 78.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eb7bf438966207f108e3330147c08026a6cd38ba004ba9344e651e2d1120a718
|
|
BLAKE2b-256 checksum How to use checksums |
84df99349e96f081503e2fcad346de57eb0083bea8baefa804083c67f92c72a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for agentperm 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.