Config as code
Export, review, and import your workspace governance as a versioned JSON document.
Your workspace's governance (policies, card and inbound policies, custom detectors, response rules, notification channels, webhook endpoints) round-trips through one versioned JSON document. Review changes in git, promote a staging workspace's rules to production, or keep a disaster-recovery copy next to your infrastructure code.
CLI
npm install -g @axiorank/cli
export AXIORANK_API_KEY=axr_live_...
axiorank config export --file axiorank.config.json
axiorank config diff --file axiorank.config.json
axiorank config import --file axiorank.config.jsondiff shows the plan (creates, updates, deletes) without changing anything;
import prints the same plan and then applies it. --prune additionally
deletes workspace entries that are absent from the file; without it imports
never delete. diff --exit-code exits 1 when anything would change, which is
the building block for CI gates.
GitOps
The config file is the source of truth in git; the workspace follows it.
Export once and commit the file, gate pull requests with
axiorank config diff --exit-code, and apply on merge with
axiorank config import. The full CI recipe (including a Terraform shim for
teams that must run terraform apply) lives on the
GitOps page.
Backtest before you apply
A drift gate tells you the file and the workspace differ; a backtest tells you what the difference would have done. It replays the file's policies over your workspace's recent traffic (the newest 5000 calls in the window) and counts decision flips: calls that were allowed but the file would deny, calls that were held but the file would allow, and so on.
axiorank config backtest --file axiorank.config.json --days 7 --max-flips 0The command prints the flip total, a per-transition breakdown (for example
allow->deny: 3), and up to 20 sample calls. It exits 1 when the flips exceed
--max-flips, so adding it next to the drift gate in your PR job blocks a
governance change that would alter more real decisions than you budgeted for.
Unlike the dashboard's single-rule backtest, the file is treated as the full
desired state: its policies replace the current set wholesale, exactly as an
import would leave them. v1 backtests the policies section only; the other
sections (card and inbound policies, detectors, response rules) are ignored.
Promote between workspaces
The CLI is workspace-scoped by its API key, so promoting staging governance to production needs no extra feature, just two keys:
AXIORANK_API_KEY=$STAGING_KEY axiorank config export --file axiorank.config.json
AXIORANK_API_KEY=$PROD_KEY axiorank config diff --file axiorank.config.json --exit-code
AXIORANK_API_KEY=$PROD_KEY axiorank config import --file axiorank.config.jsonAPI
The CLI is a thin client over three endpoints:
GET /api/workspace/configreturns{ config, excluded }.POST /api/workspace/configwith{ dryRun, prune, config }.dryRundefaults to true and returns the per-section diff;dryRun: falseapplies it.POST /api/workspace/config/backtestwith{ config, days }(days defaults to 7, max 30) returns{ rows, flips, sample }without changing anything.
Authenticate with a dashboard session (admin) or an API key: policies:read
exports, diffs, and backtests, policies:write imports.
Semantics
- Entries are keyed by name within each section; names must be unique.
Rename an entry and an import sees a create (plus, with prune, a delete).
The one exception is
webhookEndpoints, which have no name: their URL is the key, so changing an endpoint's URL reads as a create plus a delete. - Imports land on the Config Changes page like any dashboard edit, so the audit trail is identical either way.
- A re-imported export is a no-op: the diff is computed against fresh state on every call.
- The document carries
version: 2. Version-1 files (which predate thenotificationChannelsandwebhookEndpointssections) still import: a section that is absent from the file is treated as not managed and left untouched, even with--prune. Delete a section's key to hand it back to the dashboard; an empty array[]means "manage it, and there should be none".
Write-only secrets
Channel secrets never leave the server. An export omits the webhook channel
signing secret and the PagerDuty routingKey; URLs and email addresses are
not secrets and round-trip normally. On import:
- An absent secret field means "keep whatever is stored". It never shows up as a diff, so the exported file is drift-free as is.
- A present secret field is applied as written (and always counts as an update). Inject it from your CI secret store rather than committing it.
- Creating a
webhookchannel without asecretworks: the server mints one, exactly like the dashboard. The import response never carries it, so give the receiver a knownsecretin the document, or create that channel from the dashboard (which shows the minted secret once). - Creating a
pagerdutychannel requiresroutingKeyin the document: the server cannot mint one. - Webhook endpoint signing secrets are entirely server-managed: minted on
create, never exported, never importable. After creating an endpoint via
import, rotate its secret from the dashboard (or
POST /api/webhook-endpoints/[id]/rotate) to obtain the value your receiver verifies with.
What the document excludes
Channel and endpoint signing secrets (write-only, see above), per-agent egress allowlists, and per-surface inbound policies stay outside the document. The export response lists the exclusions so a round-trip is never silently lossy.
Next steps
- Policies: what the entries mean.
- GitOps: the full CI recipe and the Terraform shim.
- GitHub Action: gate pull requests on the same governance.
Voice agents (Realtime API)
Govern the tool calls and output of an OpenAI Realtime voice agent with the same policy, risk scoring, and audit trail as any other agent.
GitOps
Run your workspace governance like infrastructure, with the config file in git, a drift gate on pull requests, and an import on merge.