Arvexa OS
Get API key
Loading API Reference from OpenAPI…
Guide

Permissions, Roles & Audiences

Scopes, actor roles, account audiences, and deny-by-default

Three separate ideas, and they are not interchangeable.

Scopes are capability grants. They appear on a manifest (what the plugin asks for) and on a Developer API key (what your tooling may do). The V1 allowlist is locked:

  • api.read, api.write.limited
  • apps.read, apps.write
  • plugins.read, plugins.write
  • keys.read, keys.write
  • sandbox.run
  • marketplace.read, marketplace.write
  • catalog.read
  • config.read, config.write
  • webhooks.declare
  • observability.publish
  • workflow.action
  • events.subscribe

Some scopes are permanently refused in V1 and will never be granted: finance.settle, finance.write, trust.override, trust.write, pii.export, pii.raw, and api.write.unrestricted. Asking for one produces a specific "forbidden" diagnostic rather than "unknown scope", because the two mean different things: one will never work, the other might be a typo. An API key carries at most 32 scopes.

Roles are the actor identities a plugin may act as. Audiences are the account audiences that may see and use it. Both draw from the same set — ADMIN, OWNER, OPERATOR, DEVELOPER, BUYER, PUBLISHER, VIEWER — and each is capped at 7 entries.

The distinction matters at validation time. A hook is available to specific audiences, so declaring call.completed with no overlapping audience is rejected as HOOK_AUDIENCE_DENIED. An extension point is allowed for specific roles, so ui.admin_nav — restricted to ADMIN, OWNER, and OPERATOR — is rejected for a plugin whose roles and audiences do not include one of them.

Every hook also carries required scopes that your manifest must declare independently. call.completed requires api.read and events.subscribe; declaring the hook without both is HOOK_SCOPE_MISSING. Declaring the scope without the hook is legal but useless.

Deny-by-default is not advisory. Unknown APIs, functions, scopes, hooks, extension points, roles, and audiences all fail closed at the host, at every layer, including inside a test run. Authorization is never relaxed for a harness attempt or a sandbox run.

Developer API keys are show-once plaintext in arvexa_<prefix>_<secret> form. The host stores a hash; the plaintext is displayed once, at issue or rotate, and is never recoverable afterwards — not from the API, not from the CLI, not from arvexa whoami, which prints only the masked form. Revoked and expired keys fail immediately.

The CLI never writes a key anywhere. It has no login command, no credential file, and deliberately no --api-key flag — a value on a command line is readable by other processes through /proc and lands in shell history. Supply a key one of three ways:

  • --api-key-stdin, piped from a secret manager, so nothing touches disk
  • the ARVEXA_DEVELOPER_API_KEY environment variable, the standard CI pattern
  • an apiKeyEnv reference in arvexa.config.json, which names a variable rather than holding a value

A plaintext apiKey (or token, secret, password, authorization) in the config file is refused with an error naming the alternatives, not accepted with a warning. Every line the CLI writes to a terminal or a log is passed through redaction first, including --json output and error messages, so a key echoed back by a host cannot survive to a CI log.