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 cancel

TypeScript 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:

  • set and propose replace 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. --activate is the explicit opt-out that publishes from the terminal.
  • cancel discards 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 --json

Output:

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 templates

Output:

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 from armoriq policy templates.

Flags:

  • --reason <text> - audit reason recorded with the proposal. Defaults to Template "<name>" applied via armoriq CLI.
  • --activate - publish immediately instead of stopping at proposed.
  • --yes - skip the --activate confirmation 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 --activate

Output (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 to Policy from <file> proposed via armoriq CLI.
  • --activate, --yes - as for set.
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 cancel

Output:

✔ 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

MessageCause
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.

  • armoriq keys - manage the credentials this command authenticates with
  • armoriq orgs - confirm which org you are scoped to first
  • ArmorClaude - the plugin that enforces the policy this command publishes

On this page