Observed since 20 Oct, 22:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Permission policy mediator for Claude Code, Codex, OpenCode, Gemini CLI, and Kiro.
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
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.
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.
--flag=value spelling
can vary without widening the rule.Edit(src/**) and Write(dist/**) once. Agent-specific edit,
write, notebook, and patch operations map to those capabilities.Python(readonly) parses literal python -c and heredoc source with
Python's AST, allowing inspection while surfacing recognized mutations and dynamic effects.why, custom rule reasons, validation, and opt-in JSONL traces show why
a decision happened.The complete per-agent differences are in the capability matrix.
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.
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.
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.
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.
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.
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.
MIT
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.4.0 | 28 Aug 2026 | 7 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Public sponsor counts have not been collected. These signals belong to the repository owner.
github · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-21 | 1 | 2026-10-21T12:59:06.1101601Z |
Observed since 20 Oct, 22:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:c867e16016e70ff0c19009d842a914ea46716bf77c3649adb8af021b506bc6d2