尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Permio CLI: check and manage RBAC permissions, roles, grants and groups from the terminal, CI and AI agents, with config as code
翻譯準備中
正在載入完整 README。
檢視完整 README ↗Permio is hosted authorization for your app: RBAC and fine-grained permission checks on hierarchical resources, for multi-tenant SaaS.
Website · Docs · Quickstart · Dashboard
permio is the command-line interface for perms.io. Use it to
check permissions, manage permissions, roles, grants and groups, and keep a
whole project in a permio.yaml file (plan, apply, export).
It is built for scripts, CI and AI agents as well as people: every command
takes --json, exit codes are distinct and documented, and it never prompts
when stdin is not a terminal.
$ permio check user_123 /projects/42/documents/7 document.edit --explain
denied: user_123 does not have document.edit on /projects/42/documents/7
missing on /projects/42/documents/7: document.edit
$ echo $?
1
Not released yet. Once it is:
# Homebrew (macOS, Linux)
brew install perms-io/tap/permio
# npm / npx (downloads the prebuilt binary for your platform)
npx permio-cli --help
npm install -g permio-cli
# Go 1.24+
go install github.com/perms-io/permio-cli/cmd/permio@latest
Prebuilt archives for macOS, Linux and Windows (amd64 and arm64), with a
checksums.txt, are attached to each
GitHub release.
Shell completion: permio completion bash|zsh|fish|powershell --help explains
how to load it.
permio authenticates with a perms.io API key. Create one in the dashboard
at app.perms.io. A key belongs to one organisation and
one project:
check, access, list/get, plan and export);create, update, delete, grants add/remove, groups members add/remove
and apply).Keys look like perms_ followed by 38 letters and digits, and end in a
checksum, so permio rejects a mistyped or truncated key before making any
request. Legacy JWT keys are also accepted.
Settings, from highest to lowest precedence:
| Setting | Flag | Environment | Profile key | Default |
|---|---|---|---|---|
| API key | --api-key | PERMIO_API_KEY | api-key | none |
| API URL | --api-url | PERMIO_API_URL | api-url | api.perms.io:443 (production) |
| Project | --project | PERMIO_PROJECT | project | default |
| Profile | --profile | PERMIO_PROFILE | permio config use | default |
--api-url accepts host, host:port, https://host[:port], or the alias
prod. Production is the only built-in environment; to use another server,
give its address.
Profiles live in ~/.config/permio/config.yaml (or $XDG_CONFIG_HOME/permio/,
or the path in PERMIO_CONFIG). The file is written with 0600 permissions
because it holds API keys.
permio config set api-key perms_... # default profile
printf '%s' "$KEY" | permio config set api-key - # read the key from stdin
permio config set --profile staging api-url api.example.com
permio config set --profile staging api-key perms_...
permio config set --profile staging project staging
permio config use staging # make staging the current profile
permio config list # profiles (keys redacted) and effective settings
permio config unset --profile staging project
permio config path
# ~/.config/permio/config.yaml
current_profile: staging
profiles:
default:
api_key: perms_...
staging:
api_key: perms_...
api_url: api.example.com
project: staging
permio config list shows where each effective value comes from (flag, env,
profile or default), which helps when a command uses an unexpected key.
document.read./projects/42/documents/7. A
grant on a URI applies to that URI and everything below it. A _ segment in a
granted URI matches any one segment: a grant on /projects/_/public applies to
/projects/42/public/readme.group:<slug> and every member holds the grant. Groups cannot contain groups.allowed: false, exit code 1), not an
error.The full documentation is at docs.perms.io (LLM-friendly version).
Every command has --help with examples. Global flags: --api-key,
--api-url, --project, --profile, --json, --quiet/-q, --timeout
(per request, default 15s).
permio
├── check <principal> <resource> <permission...> [--explain]
│ └── batch <principal> -p <permission>... [resource... | -]
├── permissions list [--search] | get <name> | create <name...> [--description]
│ update <name> [--description] [--rename] | delete <name...>
├── roles list [--search] | get <id|name> | create <name> -p <perm>... [--description]
│ update <id|name> [--name] [--description] [-p ...] [--add-permission ...] [--remove-permission ...]
│ delete <id|name...>
├── grants list [--principal] [--resource]
│ add --principal --resource [-r <role>...] [-p <perm>...]
│ remove --principal --resource [-r <role>...] [-p <perm>...] [--all]
├── groups list [--search] | get <slug> | create <slug> [--description] [--member ...]
│ update <slug> --description | delete <slug...>
│ members list <slug> | add <slug> <principal...> | remove <slug> <principal...>
├── access list --principal --permission --under [--allows <uri>...]
│ who --resource [--permission] [--expand-groups]
├── plan [-f permio.yaml] [--prune]
├── apply [-f permio.yaml] [--prune] [--yes]
├── export [-o permio.yaml]
├── config set <key> <value> | unset <key> | use <profile> | list | path
├── version
└── completion bash|zsh|fish|powershell
permio check user_123 /documents/42 document.read # exit 0 allowed, 1 denied
permio check user_123 /documents/42 document.read document.edit # all must be held
permio check user_123 /documents/42 document.edit --explain # list what is missing
permio check user_123 /documents/42 document.read -q && echo ok # exit code only
permio check user_123 /documents/42 document.read --json
check batch answers many resources at once (one result each). Resources come
from arguments, or from stdin, one per line, when there are none or the only one
is -. It exits 0 only if every resource is allowed.
permio check batch user_123 -p document.read /documents/1 /documents/2
cat uris.txt | permio check batch user_123 -p document.read --json
permio permissions list [--search document]
permio permissions get document.read
permio permissions create document.read document.edit --description "Document access"
permio permissions update document.read --description "Read any document"
permio permissions update doc.read --rename document.read
permio permissions delete document.delete
permio roles list
permio roles get editor # by name or ID
permio roles create editor -p document.read -p document.edit --description "Can edit"
permio roles update editor --add-permission document.delete
permio roles update editor --remove-permission document.delete
permio roles update editor -p document.read # replace the whole permission list
permio roles update editor --name writer
permio roles delete writer
Remove a permission from roles before deleting the permission.
permio grants list --principal user_123 # every grant to user_123
permio grants list --resource /documents/42 # every grant made on exactly /documents/42
permio grants list --principal user_123 --resource /documents/42
permio grants list # every grant in the project
permio grants add --principal user_123 --resource /documents/42 --role editor
permio grants add --principal group:design --resource /projects/7 -r viewer -p comment.create
permio grants remove --principal user_123 --resource /documents/42 --role editor
permio grants remove --principal user_123 --resource /documents/42 --all
grants list shows grants made directly on a URI. To include inherited,
wildcard and group access, use permio access who.
permio groups create design --description "Design team" --member user_123 --member user_456
permio groups list
permio groups get design # with members
permio groups update design --description "Product design"
permio groups members list design
permio groups members add design user_789
permio groups members remove design user_456
permio groups delete design # also removes its memberships and grants
access list answers "where may this principal use this permission under this
URI?", counting direct, role, group, inherited and wildcard grants. Use it to
filter lists in your own database.
permio access list --principal user_123 --permission document.read --under /documents
permio access list --principal user_123 --permission document.read --under /documents \
--allows /documents/42 --allows /documents/43 # exit 0 only if all are covered
The JSON output has covers_all (true: everything under --under is
allowed), scopes (subtree or pattern), prefixes (subtree URIs to match as
path = p OR path LIKE p || '/%') and patterns (URIs with _ segments).
access who answers "who has access to this resource?":
permio access who --resource /documents/42
permio access who --resource /documents/42 --permission document.edit --expand-groups --json
Describe a project in permio.yaml, review the diff with plan, and make it so
with apply. export writes the project's current state in the same format.
# yaml-language-server: $schema=https://raw.githubusercontent.com/perms-io/permio-cli/main/schema/permio.schema.json
project: default
permissions:
- document.read
- { name: document.edit, description: Edit documents }
roles:
editor: { description: Can edit, permissions: [document.read, document.edit] }
groups:
design: { description: Design team, members: [user_123] }
grants:
- { principal: group:design, resource: /projects/123, roles: [editor], permissions: [] }
permio export > permio.yaml # start from the current state
permio plan -f permio.yaml # + create, ~ update, - delete; changes nothing
permio apply -f permio.yaml # shows the plan and asks for "yes"
permio apply -f permio.yaml --yes # CI
permio plan -f permio.yaml --prune # also delete what is not in the file
permio apply -f permio.yaml --prune --yes
Rules:
project is optional and defaults to the configured project. If it is set and
--project/PERMIO_PROJECT names a different project, the command fails.permio resolves them to IDs.permissions, a group's members (when given) and a grant's
roles and permissions are each the full set: entries not listed are
removed, even without --prune. Leave out members to leave a group's
members alone. Give a grant empty lists to revoke everything on that pair.description (or a bare permission name) leaves the description
as it is.--prune, apply only creates and updates. With --prune it also
deletes permissions, roles, groups, and grants on (principal, resource) pairs
that are not in the file.apply asks for confirmation. When stdin is not a terminal, with --json, or
with -f -, it does not prompt and requires --yes.apply stops at the first failure. The changes before it stay applied, and
running apply again continues from there. Applying the same file twice makes
no further changes, and plan of an exported file shows no changes.Editor autocompletion: the JSON Schema is
schema/permio.schema.json. Exported files start
with a yaml-language-server comment that points to it, which the YAML
extensions for VS Code, JetBrains IDEs and Neovim pick up. See
examples/permio.yaml for a complete example.
| Exit code | Meaning |
|---|---|
0 | Success. For check, check batch and access list --allows: allowed. |
1 | Denied (check, check batch, access list --allows). |
2 | Usage error, invalid input, or an API error (not found, unavailable, timeout...). |
3 | Authentication error: no API key, a malformed key, or a key the API rejected. |
4 | Permission denied for the key: e.g. a check-only key trying to write, or a key used with another project. |
JSON. With --json, results go to stdout as a single JSON document whose
shape is stable (fields may be added, never renamed or removed). Lists are
always arrays, never null. Examples:
// permio check user_123 /documents/42 document.read document.edit --json
{ "allowed": false, "principal": "user_123", "resource": "/documents/42",
"permissions": ["document.read", "document.edit"],
"missing": [{ "resource": "/documents/42", "permissions": ["document.edit"] }] }
// permio roles get editor --json
{ "id": "...", "name": "editor", "description": "Can edit", "permissions": ["document.edit", "document.read"] }
// permio grants list --principal user_123 --json
{ "grants": [{ "principal": "user_123", "resource": "/documents/42",
"roles": [{ "id": "...", "name": "editor" }], "permissions": [] }] }
// permio plan -f permio.yaml --json
{ "project": "default", "prune": false,
"changes": [{ "action": "create", "kind": "role", "name": "editor", "add_permissions": ["document.edit", "document.read"] }],
"summary": { "create": 1, "update": 0, "delete": 0 } }
List commands wrap their items: {"permissions": [...]}, {"roles": [...]},
{"groups": [...]}, {"grants": [...]}. apply --json prints
{"project", "plan", "applied", "summary"}, also when it stops on a failure.
Errors go to stderr. With --json they are JSON too:
{ "error": { "kind": "permission_denied", "message": "permission denied for the API key",
"grpc_code": "PermissionDenied", "exit_code": 4,
"missing": [{ "resource": "/organisation/.../project/default", "permissions": ["permission.create"] }] } }
kind is one of usage, config, auth, permission_denied,
invalid_argument, not_found, already_exists, unavailable, timeout,
error.
Quiet. --quiet suppresses status messages. check prints nothing at all
(use the exit code); list commands print one identifier per line (grants list:
principal and resource, tab-separated).
Retries. Read-only calls are retried twice with backoff on Unavailable
and timeouts. Writes are never retried.
Agents can use permio directly from a shell; no extra server is needed.
--json and read stdout; errors are JSON on stderr. Branch on the exit
code: 0 allowed/success, 1 denied, 2 usage or API error, 3
authentication, 4 the key may not do this.PERMIO_API_KEY (and PERMIO_PROJECT), not on the
command line.permio --help and permio <command> --help describe every command with
examples, so an agent can discover the CLI without these docs.plan before apply. apply never prompts without a terminal; it requires
--yes.npx permio-cli ... works the same
way.export PERMIO_API_KEY=perms_... PERMIO_PROJECT=default
permio check user_123 /documents/42 document.read --json; echo "exit=$?"
permio export --json
permio plan -f permio.yaml --json
permio login (v2). Organisation-level objects (projects, API keys, team
members) need a dashboard user, not an API key. A browser-based
permio login flow will add commands for them. v1 manages project-level
objects with API keys only.go vet ./...
go test -race ./...
The tests run every command end to end against an in-memory fake of the
PermissionsService (pkg/fakeserver) over bufconn. Live tests against a real
API run when PERMIO_TEST_API_KEY and PERMIO_TEST_API_URL are set
(PERMIO_TEST_PROJECT defaults to default); they only read unless
PERMIO_TEST_WRITE=1 is also set, in which case they create uniquely named
objects and delete them again.
Layout:
| Path | Contents |
|---|---|
cmd/permio | main |
internal/cli | Cobra commands and output |
internal/settings | config file, profiles and precedence |
pkg/permio | gRPC client: auth, retries, typed errors, pagination helpers |
pkg/configsync | permio.yaml parsing, export, plan and apply (reusable by other tools) |
pkg/apikey | local API key format validation |
pkg/fakeserver | in-memory PermissionsService for tests |
schema/ | JSON Schema for permio.yaml |
npm/ | npm wrapper package (permio-cli) |
The pkg/ packages are pre-1.0 and may change.
Releases are built by GoReleaser (.goreleaser.yaml) from v* tags via
.github/workflows/release.yml.
Apache License 2.0. See LICENSE.