armoriq policy
Read and change your org's armor.policy.v1 profile from the terminal - show, templates, set, propose, cancel
armoriq policy
Read and change the org's active policy profile from the terminal. Before this
existed, policy could only be authored from the dashboard or from inside a
Claude Code session (/armor).
armoriq policy show [--json]
armoriq policy templates
armoriq policy set <template> [--reason <text>] [--activate] [--yes]
armoriq policy propose --file <path> [--reason <text>] [--activate] [--yes]
armoriq policy cancelTypeScript CLI only. armoriq policy ships in @armoriq/sdk (0.6.7) and
has no equivalent in the Python armoriq-sdk CLI, which answers
invalid choice: 'policy'. See the command support
matrix.
The change model
Your org has exactly one working draft, shared with the dashboard's policy editor. Every write goes through the same three stages:
setandproposereplace the draft, then immediately stage it as a proposal and print the diff against the active policy.- Moving proposed → active is human-only by default: you confirm it on the
dashboard.
--activateis the explicit opt-out that publishes from the terminal. canceldiscards the staged proposal. The active policy is untouched.
Because the draft is per-org and shared, set and propose overwrite whatever
a teammate (or the dashboard editor) currently has in progress. There is no
merge.
armoriq policy show
Prints the org's confirmed, active policy. Read-only.
Flags:
--json- dump the raw response (version, policy document,publishedAt) instead of the formatted summary.
armoriq policy show
armoriq policy show --jsonOutput:
Active policy (version 4, published 2026-07-28T11:04:22Z):
name balanced
description Read allowed. Bash/Write/Edit require approval.
default confirm
statements 3
allow Read, Grep, Glob
confirm Bash, Write, Edit
deny WebFetch where url contains "internal."When the org has never confirmed a policy:
No confirmed policy for this org yet.
The ArmorClaude plugin keeps enforcing its local policy until one is
confirmed here. Stage one with `armoriq policy set <template>`.That second message matters: no confirmed policy does not mean no enforcement. The ArmorClaude plugin falls back to its own local policy.
armoriq policy templates
Lists the built-in templates. Local, no network call.
armoriq policy templatesOutput:
Policy templates:
all-allow Everything permitted, intent planning still enforced
strict-read-only Only Read/Grep/Glob allowed. Bash/Write/Edit denied.
balanced Read allowed. Bash/Write/Edit require approval.
lockdown All tools require approval. Nothing auto-allowed.
architect Explore wide, write inside workspace, never destroy
quality-guardian Read and test freely, gate CI and secrets, cautious default
velocity-machine Fast and low friction, hard stops on destroy, exfil and publish
night-owl Solo off-hours, confirm writes and bash, deny by default
Apply one with `armoriq policy set <template>`.The server is the authority on template names - this list is a local copy for display and a fast typo check. If you pass a name the CLI does not know, it warns and asks the server anyway:
! "balenced" is not a template this CLI knows about, asking the server anyway.armoriq policy set
Applies a named template as the draft, then stages it.
Arguments:
<template>(required, positional) - a name fromarmoriq policy templates.
Flags:
--reason <text>- audit reason recorded with the proposal. Defaults toTemplate "<name>" applied via armoriq CLI.--activate- publish immediately instead of stopping at proposed.--yes- skip the--activateconfirmation prompt. Required off a TTY.
# Stage it; confirm on the dashboard
armoriq policy set balanced --reason "Q3 hardening"
# Publish straight from the terminal
armoriq policy set lockdown --activateOutput (default - stage only):
✔ Draft set from template "balanced" (replaces the org's working draft).
Changes vs the active policy:
- default: allow
+ default: confirm
+ deny WebFetch where url contains "internal."
✔ Proposed (hash 9c2f4ae1b30d).
Confirm it on the dashboard to make it active: activation is human-only.
Discard it with `armoriq policy cancel`.Output with --activate, interactively:
! --activate publishes this policy immediately, skipping dashboard confirmation.
Every agent session in this org picks it up on its next policy pull.
Publish it as the active policy now? [y/N] y
✔ Activated (version 5).
Plugin sessions pick this up on their next policy pull.Answer anything other than y/yes and it prints Not activated. - the
proposal stays staged, which is the safe default.
armoriq policy propose
Same as set, but the draft comes from your own armor.policy.v1 JSON document
instead of a template.
Flags:
--file <path>(required) - the JSON file. May also be given positionally.--reason <text>- defaults toPolicy from <file> proposed via armoriq CLI.--activate,--yes- as forset.
armoriq policy propose --file policies/production.json --reason "add egress deny"Output:
✔ Draft saved from policies/production.json (replaces the org's working draft).
Changes vs the active policy:
+ deny Bash where command matches "curl .* \| sh"
✔ Proposed (hash 4b81de20c9f7).
Confirm it on the dashboard to make it active: activation is human-only.
Discard it with `armoriq policy cancel`.The file is validated locally before anything is sent - it must exist, be a regular file, contain valid JSON, and parse to an object (not an array):
✘ policies/production.json is not valid JSON: Unexpected token } in JSON at position 412
✘ Not a readable file: policies/
✘ policies/production.json must contain an armor.policy.v1 object.armoriq policy cancel
Discards the staged proposal. No flags, no arguments.
armoriq policy cancelOutput:
✔ Staged proposal discarded. The active policy is unchanged.Using it in CI
--activate without --yes is refused up front in a non-interactive shell,
before any write happens:
✘ Refusing to activate without confirmation in a non-interactive shell.
Re-run with --yes, or drop --activate and confirm on the dashboard.
Nothing was changed.The check runs ahead of the first request deliberately, so a pipeline that gets this error has genuinely changed nothing - the draft is not replaced and no proposal is staged.
Two sane CI shapes:
# Safe: stage on merge, a human confirms on the dashboard
- run: armoriq policy propose --file policies/production.json --reason "$GITHUB_SHA"
env:
ARMORIQ_API_KEY: ${{ secrets.ARMORIQ_API_KEY }}
# Fully automated: publishes to every agent session in the org
- run: armoriq policy propose --file policies/production.json --activate --yes
env:
ARMORIQ_API_KEY: ${{ secrets.ARMORIQ_API_KEY }}Errors you may hit
| Message | Cause |
|---|---|
API key rejected (401). Try `armoriq login` again. | The key is invalid or revoked. |
This API key is not allowed to manage policy for its org (403). | The key is valid but lacks policy rights. Re-running login mints an equivalent key and will not help - the org role has to change. |
No org on the saved credentials, so a policy write could land on the wrong org. | Credentials have no orgId. Run armoriq login --force or armoriq switch-org <name>. |
Could not reach the ArmorIQ backend at <url> | DNS, refused connection, or the 15s timeout. |
The org guard exists because the draft and propose routes resolve the org from the request body and otherwise fall back to "the caller's first org membership". For anyone in more than one org that could silently target a different org than the key's - so the CLI refuses instead of guessing.
Related
armoriq keys- manage the credentials this command authenticates witharmoriq orgs- confirm which org you are scoped to first- ArmorClaude - the plugin that enforces the policy this command publishes