Skip to main content

aac-cli — the aac platform CLI

The headless operator interface to the AAC control plane (Eng Spec §XII; Equifax/KPI-6 requirement: every operational task doable without a web console).

Install

pip install aac-cli

Careful with the name: pip install aac installs an UNRELATED project (an MBSE modeling tool that happens to share the acronym). The AAC platform CLI's PyPI distribution is aac-cli; the command it installs is aac — the awscli precedent (dist name ≠ command name).

Two personas, two invocation styles:

  • Installed operators (pip install aac-cli) run the bare command: aac tenant register ...
  • Repo developers run it through the workspace without installing: uv run aac ...

The examples below use the bare form; prefix uv run if you're in the repo.

The Python argparse CLI ships the Stage-2 subset of §XII's full command surface, grown since (B130 trust-anchor, B116 tenant verbs, B170 profiles — which replaced the earlier B116/B117 aac configure family). This Python CLI IS the product CLI — the formerly-planned Go rewrite was descoped (user ruling 2026-07-23; no separate Go implementation is coming):

# B170 — profiles are a first-class resource (CLI Config+Profile
# Spec). `main` is the reserved baseline; `aac configure` is GONE.
aac profile list                   # every profile incl. virtual [main]
aac profile show                   # the SELECTED profile, stored vs effective
aac profile show prod --output table
aac profile create dev --admin-url https://dev-admin.example.com \
    --data-plane-url https://dev-data.example.com
aac profile update main            # materialize/edit the baseline
aac profile delete dev             # local-only; never touches the server

# B154 PR 3 — the tenant id is SERVER-ALLOCATED (canonical
# tnt-<lowercase UUIDv4>; there is no --tenant-id and you never choose
# one). Deployment note: this CLI requires a PR-3+ control plane —
# rollout order + compatibility matrix in RELEASING.md.
# The response prints the id EXACTLY ONCE with the api_key; the
# CLI stores the credential under it AND binds the SELECTED profile to
# it (a bound profile refuses registration — use an unbound one). A
# NAMED profile must exist before it can be selected (§6.1):
aac profile create acme
aac tenant register --profile acme --display-name "ACME Corporation" \
    --contact ops@acme.example \
    --workload-spiffe-id spiffe://acme.com/treasury-agent/v1 \
    --tenant-admin-pubkey-file ./tenant-admin.public.pem \
    --bootstrap-token dev-bootstrap-token-compose-only
# Workload authorities must already be lowercase. The path is
# case-sensitive, so spiffe://acme.com/Treasury-Agent is valid and is
# preserved exactly; spiffe://ACME.com/treasury-agent is rejected.
# If the response is lost, retry the exact frozen request with no stable
# arguments. The selected profile supplies its AAC-managed recovery state:
aac tenant register --profile acme
# Registration is a gated ceremony (Eng Spec §XVII.6): the control
# plane rejects it unless X-AAC-Bootstrap-Token matches its
# AAC_CP_BOOTSTRAP_TOKEN. --bootstrap-token falls back to
# $AAC_BOOTSTRAP_TOKEN (note: the CLI-side env var has no CP_ — the
# server-side name AAC_CP_BOOTSTRAP_TOKEN is NOT read by the CLI).

# B142 — developer-tier SELF-SERVE registration (no ceremony token):
# sign in with GitHub or Google; your verified identity becomes the
# tenant's first tenant-admin. Needs a deployment with self-serve
# enabled + a shared connection for the family.
aac profile create dev        # (re)create it — deleted in the B170 example above
aac tenant register --profile dev --display-name "ACME Dev" \
    --contact dev@acme.example --idp github
aac sso login --profile dev            # thereafter: plain login

# B116 — admin-surface tenant inspection + attribute update.
# Tenant ids are the server-allocated canonical tnt-<uuid> form
# (B154 PR 5) — captured at registration / shown by `aac profile show`.
aac tenant list                                # which tenant ids exist (no 409 probe)
aac tenant describe --profile dev              # assigned domain, workloads + key METADATA
aac tenant update --tenant-id tnt-<uuid> --display-name "ACME Manufacturing Inc"

# B121/B228 — business-domain control proof and bounded claim lifecycle.
# Registration can capture up to 16 pending rows with repeatable --tenant-domain.
# The issue/verify/release/revoke commands
# require the owning tenant's tenant-admin session and default --tenant-id from
# the profile; tenant describe also uses the selected profile by default.
aac tenant register --display-name "ACME" --contact ops@acme.example \
    --tenant-domain acme.example
aac tenant issue-domain-challenge --domain acme.example
# Publish the exact record printed above, then:
aac tenant verify-domain --domain acme.example
# B182 keeps verification and binding explicit. The binding command consumes
# current exact-name evidence (and lazily revalidates when due); verify-domain
# never performs an implicit binding write.
aac tenant bind-trust-domain --trust-domain acme.example
aac tenant list-trust-domains --output table
aac tenant describe --profile dev --output table  # assigned binding status + TXT
aac tenant release-domain --domain acme.example --reason "planned transfer"
aac tenant revoke-domain --domain acme.example --reason "DNS control incident"

# If bind-trust-domain reports missing proof, its printed issue/verify/rerun
# commands pin the selected profile, effective admin URL, tenant id, and exact
# domain. They never print a session, bootstrap token, or challenge value.

# B153 — replace the tenant-admin key. Accepts and transmits the PUBLIC half
# ONLY. It never generates or writes private-key material, and it refuses a
# private key without transmitting or logging it — it does read the file you
# name, because refusing requires inspecting it.
# Replacement is IMMEDIATE and forward-only: the previous key stops
# verifying ingest JWSs at once (admin keys get NO grace window) and can
# never be reinstated.
openssl genpkey -algorithm ed25519 -out tenant-admin.pem
openssl pkey -in tenant-admin.pem -pubout -out tenant-admin.public.pem
aac tenant rotate-admin-key --tenant-admin-pubkey-file tenant-admin.public.pem
# BEFORE running it in production: stage the new PRIVATE key on the
# trust-anchor publisher host and be ready to restart it. The restart
# procedure DIFFERS by deployment path — a Docker publisher's env and key
# bind-mount are fixed at container creation, so a plain restart comes back
# on the OLD key. Follow trust_anchor_publisher/INSTALL.md, "Rotating the
# tenant-admin key". Publication stays paused until it restarts.
# --bootstrap-token (or $AAC_BOOTSTRAP_TOKEN) lets a ceremony operator
# rotate for a tenant that has no session.

# B172 — post-registration workload lifecycle. --tenant-id is optional
# here: the selected profile supplies it by default. JSON is default;
# every command also supports --output table.
aac tenant add-workload --spiffe-id spiffe://acme.com/payroll/v1 \
    --display-name "Payroll"
aac tenant list-workloads                       # ACTIVE only
aac tenant list-workloads --all                 # + DEACTIVATED history
aac tenant describe-workload --workload-id <opaque-id>
aac tenant update-workload --workload-id <opaque-id> \
    --display-name "Payroll v2"
aac tenant update-workload --workload-id <opaque-id> --clear-display-name
aac tenant deactivate-workload --workload-id <opaque-id> \
    --reason "service retired"
# Deactivation is terminal; there is no delete/reactivate command, and
# the exact SPIFFE ID remains globally reserved.

aac chain show --token-id <64-hex token or chain root> --tenant-id tnt-<uuid>
aac chain show --token-id <id> --output table
aac chain show --token-id <id> --render --render-out ./aeg.html   # headless
aac chain show --token-id <id> --render --open                    # + browser

# B130 — YOUR tenant's trust-anchor state (what .well-known never
# shows: REVOKED keys, expired-grace history, lifecycle timestamps,
# tenant-admin key status, the ingest ledger). Bearer-authenticated;
# tenant scoping is implicit in the credential.
aac trust-anchor list --tenant-id tnt-<uuid>        # both roles, all states
aac trust-anchor list --role tenant-admin           # ingest-signing keys only
aac trust-anchor describe --kid key-1               # lifecycle + public PEM
aac trust-anchor ingest-history --artifact-class root-keys --limit 20
# Session-only emergency/environment-retirement operation. Terminal, may
# revoke the last root, and cannot be authorized by bootstrap token/API key:
aac trust-anchor revoke --tenant-id tnt-<uuid> --kid key-1 \
    --reason "root signing key suspected compromised"

# B144 — before the first tenant IdP, Tenant Ops generates an Ed25519
# offline recovery keypair. The private PEM stays offline and mode 0600;
# only the non-secret enrollment JSON crosses to AAC Ops/control plane.
aac sso generate-idp-recovery-key \
    --private-key-file offline-idp-recovery-private.pem \
    --enrollment-file idp-recovery-enrollment.json
aac sso enroll-idp-recovery-key \
    --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --file idp-recovery-enrollment.json \
    --bootstrap-token "$AAC_BOOTSTRAP_TOKEN"

# B140 — register a tenant↔IdP connection (Eng Spec §XVII.4; the sso
# noun). The connection config rides as a JSON file (nested claims
# mapping — see --help for an Entra example). Initial recovery-key
# enrollment above happens before first-IdP registration. First-IdP
# registration is the ops ceremony; later IdPs ride a cached session:
# (--tenant-id takes the canonical tnt-<uuid> id captured at your
# tenant's registration — B154 PR 5: a dotted value fails locally.)
aac sso register-idp --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --file connection.json \
    --bootstrap-token "$AAC_BOOTSTRAP_TOKEN"

# B151 — discover the opaque connection id and current revision without a
# session. The public response contains only safe issuer metadata, a stable
# idp_connections.id, and the numeric ETag needed for correction:
aac sso list-idp --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000

# B151 — correct the COMPLETE connection document. Pin the revision you
# reviewed; the CLI sends it with the cached tenant-admin session and never
# substitutes a newer revision. Repeating after a lost response is safe:
aac sso replace-idp --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --connection-id <id-from-list-idp> \
    --revision <revision-from-list-idp> \
    --file corrected-connection.json

# B144 — if the IdP is unavailable, the same B151 replacement is authorized
# by a three-command two-party ceremony. Tenant Ops signs the exact corrected
# file and receives a request id plus REPAIR-INTENT fingerprint. AAC Ops
# compares both through the incident channel, approves that exact intent, and
# manually notifies Tenant Ops. Tenant Ops then runs replace-idp with the same
# request/file/revision/key. The CLI internally redeems a ten-minute,
# single-use capability, holds it only in memory, and never prints or stores it.
# It grants no login, data-plane access, or general administration.
aac sso request-idp-repair \
    --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --connection-id <id-from-list-idp> \
    --revision <revision-from-list-idp> \
    --file corrected-connection.json \
    --recovery-key-file offline-idp-recovery-private.pem
aac sso approve-idp-repair \
    --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --connection-id <id-from-list-idp> \
    --repair-request-id <tenant-provided-request-id> \
    --repair-intent-fingerprint sha256:<tenant-provided-intent-hash> \
    --bootstrap-token "$AAC_BOOTSTRAP_TOKEN"
aac sso replace-idp \
    --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --connection-id <id-from-list-idp> \
    --revision <same-request-revision> \
    --file corrected-connection.json \
    --repair-request-id <approved-request-id> \
    --recovery-key-file offline-idp-recovery-private.pem

# These fingerprints are different: recovery_key_fingerprint identifies the
# enrolled Ed25519 PUBLIC key; repair_intent_fingerprint identifies one exact
# tenant/connection/revision/document/key intent. Neither replaces the other.

# Recovery-key lifecycle is normal-session administration. Generate a fresh
# pair before rotation; old material cannot return. Revocation is terminal.
aac sso list-idp-recovery-keys --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000
aac sso rotate-idp-recovery-key \
    --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --file new-idp-recovery-enrollment.json \
    --replaces-recovery-key-id <current-active-key-id>
aac sso revoke-idp-recovery-key \
    --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
    --recovery-key-id <current-active-key-id> \
    --reason "offline media lost"

# B142 — register a SHARED developer-tier connection (platform
# operator ceremony ONLY; owned by no tenant). GitHub registers with
# jwks_static {"keys": []} + explicit endpoints (GitHub is not an OIDC
# provider); Google registers via discovery + public_client_secret:
aac sso register-idp --shared --file shared-github.json \
    --bootstrap-token "$AAC_BOOTSTRAP_TOKEN"

# B141 — sign in via your tenant's IdP (aws sso login semantics).
# Device flow by default (the browser can be on ANY machine — headless
# friendly); Google-family connections use loopback PKCE (Google's
# device grant is scope-restricted). Success caches a short-lived AAC
# session token AND writes the config profile in one motion; every
# admin verb (tenant list/describe/update, self-serve register-idp)
# then rides the session automatically.
aac sso login --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000
aac sso login --issuer https://login.microsoftonline.com/<tid>/v2.0  # >1 IdP
aac sso login --flow pkce --no-browser        # print the URL, don't launch

# Sessions are REFRESH-LESS by design (Eng Spec §XVII.2): on expiry
# any admin verb tells you to re-run `aac sso login` — there is no
# refresh token to steal, and no silent re-authentication.

# B155/B239 — local session/profile inspection; no server call or JWT parsing.
# whoami exits 0 = unexpired cache, 3 = expired/none (§14).
aac sso whoami --profile dev --output table   # cached session + saved assigned domain
aac sso logout --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000

Naming: console script = aac (the §XVI-reserved name); import package = aac_cli (the SDK owns the aac import package); distribution = aac-cli (decided at first release, B119: bare aac on PyPI belongs to an unrelated active project and is not claimable).

Configuration

Profiles live in ~/.aac/config (UTF-8 INI with DIRECT sections — [main], [dev], [prod], never [profile dev]; override the directory with AAC_CLI_HOME). aac profile create/update are the writers; the file stays hand-editable INI, but note a rewrite does not preserve comments (aws-cli behaves the same):

[main]
admin_url = http://127.0.0.1:8000
data_plane_url = http://127.0.0.1:9000
tenant_id = tnt-550e8400-e29b-41d4-a716-446655440000

[dev]
admin_url = https://dev-admin.example.com
data_plane_url = https://dev-data.example.com

main is the reserved baseline profile. It always exists — virtually (built-in localhost defaults) until aac profile update main materializes it — and cannot be created or deleted. Profile SELECTION for operational commands is --profile <name> > AAC_PROFILE > main; a selected profile that doesn't exist is an error, never a silent fallback. Prototype-era [default] sections migrate to [main] automatically on first touch (both-exist-and- differ fails closed with manual remediation).

tenant_id is system-managed. Profile commands display it but never prompt for or accept it — only authenticated workflows (aac tenant register, aac sso login) write it. Canonical tnt-<uuid> validation is MANDATORY (B154 PR 5): a profile holding a prototype-era dotted value (acme.com) now fails every command, exit 3, with remediation printed (delete the stale tenant_id line, then re-register or aac sso login to bind a canonical id).

Setting precedence within the selected profile: flag > env (AAC_ADMIN_URL / AAC_DATA_PLANE_URL / AAC_TENANT_ID; also AAC_BOOTSTRAP_TOKEN for tenant register --bootstrap-token) > profile > localhost defaults. aac profile show prints stored AND effective values with each one's source (flag / env:AAC_* / profile:<name> / default / unset).

Guardrails (deliberate bounded complexity): at most 50 profiles including main, 50 keys per section, 30-character keys, and 512-character values — exceeding any is a deterministic exit-3 invalid-config error. Unknown keys are preserved by writes and reported (by name) by aac profile show.

~/.aac/state/tenant-registrations/<profile>.json is AAC-managed registration recovery state (one record per profile; dir 0700, file 0600). Do not edit, rename, copy between profiles, or delete these files while a registration is unresolved — deleting one cannot cancel a request that may already have committed. A profile with such a record cannot be deleted. aac tenant register creates the record before authentication or HTTP and holds a nonblocking per-profile process lock across the entire attempt. A transport interruption retains the same request id and frozen stable intent; a bare retry resumes it with fresh ceremony/evidence credentials. Supplying identical stable arguments is also accepted, while a difference fails locally before network access. The CLI deletes pending state only after success is safely persisted or the server returns the exact paired Idempotency-Key + AAC-Registration-Status: not_created guarantee.

B183 applies the same canonical workload-ID boundary before either a durable registration-state write or an add-workload network request: a non-lowercase SPIFFE authority is rejected, never normalized. An accepted path retains its exact case in the frozen stable intent, fingerprint input, state file, and every retry comparison.

A completed server recovery returns tenant identity but cannot replay the one-time API key. The CLI binds the profile and transitions the state to completed_credential_reissue_required, directing the operator to the separate B173 reissue capability; B171 does not implement reissue.

Replace or recover a tenant API key (B173)

After establishing an own-tenant tenant-admin session, run:

aac tenant reissue-api-key \
  --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
  --profile production

This is immediate replacement, not B98/B189 graceful rotation: the server revokes every ACTIVE tenant API key and returns one fresh aac_ak_* value once. The CLI makes one HTTP request per invocation and atomically replaces the mode-0600 credential file only after validating the complete success response. A transport interruption leaves the local file untouched and tells the administrator to run the command again; the next explicit invocation is a fresh attempt that revokes any unknown prior result. There is no automatic retry or secret-response journal. A successful B173 replacement also removes any superseded non-secret B189 local rotation record. It does not silently delete the separate staged key file; that value is now revoked and must be removed through the approved secure-file procedure.

After success the CLI prints copy/paste-ready aac trust-anchor list and curl commands for API-key-only verification against GET /v1/trust-anchors. The curl recipe streams the stored credential through stdin configuration rather than writing plaintext into shell history or an OS process argument.

Operator-assisted onboarding recovery is exceptional and requires both the explicitly opened bootstrap ceremony and the matching completed registration locator. Load AAC_BOOTSTRAP_TOKEN through the approved secret-handling process, then run:

aac tenant reissue-api-key \
  --tenant-id tnt-550e8400-e29b-41d4-a716-446655440000 \
  --registration-request-id treq-550e8400-e29b-41d4-a716-446655440000 \
  --profile onboarding

The server admits this only before a tenant login path exists. The treq-* value is a locator, never a credential. Tenant API keys are separate from tenant-admin Ed25519 keys and B144 offline IdP-recovery material. See SOP-010 — Recover or replace a tenant API key in the AAC design vault's sops/ directory for the tenant-administrator and AAC Ops procedures.

Rotate a tenant API key without downtime (B189)

Planned rotation uses a nested command family and an own-tenant tenant-admin AAC session:

aac tenant api-key list --profile production
aac tenant api-key issue --profile production

issue saves a non-secret akr-* issuance identity before sending one HTTP request. It writes the returned plaintext only to a new mode-0600 staged file (default ~/.aac/credentials/<tenant-id>.next), refuses existing files and symlinks, requires any custom parent directory to exist, preserves that directory's permissions, and never replaces the current profile credential. Its success output contains metadata and a curl recipe that reads the staged file without putting plaintext in shell history or process arguments.

Move every client to the staged key through the approved secret store, verify client traffic, then list again and select the old key by its exact non-secret key_id:

aac tenant api-key retire \
  --key-id ak_0123456789abcdef \
  --yes \
  --profile production

Retirement requires two ACTIVE keys and is terminal. The CLI fetches the authoritative set immediately before the request, names the exact key that will remain, and never guesses by age or position. It does not silently promote the staged file into the current credential location. Do that only through the approved local secret-handling procedure after the selected old key retires.

If an issue response is ambiguous, rerun the same command. The saved identity is reused: a non-committed attempt may return the new plaintext, while a committed attempt reports that plaintext is unavailable and identifies the unknown new row through api-key list. Retire that unknown row, leaving the known old credential ACTIVE, then issue again. No automatic retry or plaintext journal exists. A profile with unresolved rotation state cannot be deleted. See SOP-011 — Rotate a tenant API key without downtime in the design vault.

~/.aac/idp-repair-requests/<tenant_id>/<connection_id>.json is B144's separate AAC-managed IdP repair record (directory 0700, file 0600). It is written before request-idp-repair transmits anything and contains the exact connection document, document digest, request id, recovery-key fingerprint, and public signature. It contains neither the offline private key nor the short-lived AAC repair capability. An identical retry reuses the request id; a different live intent is refused locally. Preserve this file with the incident until replacement is complete, and do not edit, rename, copy between tenants, or delete it to “cancel” a request that may already exist server-side.

AAC_CLI_HOME — isolated homes

AAC_CLI_HOME relocates the whole ~/.aac tree (config + credentials). Two everyday uses:

# 1. Throwaway smoke/test home — nothing touches your real config:
AAC_CLI_HOME=/tmp/aac-smoke aac tenant register --display-name "Smoke" ...

# 2. Multi-account operators — hard-wall separation beyond profiles
#    (separate credential files, not just separate config sections):
alias aac-prod='AAC_CLI_HOME=$HOME/.aac-prod aac'
alias aac-staging='AAC_CLI_HOME=$HOME/.aac-staging aac'

Profiles share one credentials directory; AAC_CLI_HOME gives each context its own.

Credentials — TWO kinds coexist in ~/.aac/credentials/ (documented coexistence, Eng Spec §XVII.9):

  • {tenant_id} — the bare aac_ak_... string at mode 0600, written by aac tenant register (the key is printed EXACTLY ONCE — only its peppered hash exists server-side) and presented as Authorization: Bearer by the DATA-PLANE verbs (chain show, trust-anchor *). Same bare-string format the joined compose smoke writes into sidecar key dirs — this file never grows structure.
  • {tenant_id}.session — JSON, mode 0600, written by aac sso login: the short-lived AAC session token + its client-computed expiry. The ADMIN-surface verbs ride it automatically. A session within 30s of expiry fails fast locally with the re-login message instead of dialing out; the server's own session 401s carry the same remediation (the server stays authoritative). aac sso logout removes the file; aac sso whoami reports its tenant + expiry and, when available, the matching profile's saved AAC-assigned domain. Both commands operate locally; whoami does not verify current server-side binding status.

Your tenant_id

tenant_id is your org's FEDERATION IDENTIFIER — the stable handle every other tenant verifies your signatures under: it appears in X-AAC-Originator-Tenant-Id headers, /.well-known/aac-root-keys/ {tenant_id} paths, SIEM stream directories, and supplier whitelists. You do NOT choose it (B154 PR 5, Tenant Identifier Policy): the control plane allocates the canonical tnt-<lowercase UUIDv4> (exactly 40 characters, e.g. tnt-550e8400-e29b-41d4-a716-446655440000) at registration, the CLI captures it into the selected profile, and it is immutable, public, and never reused — like an AWS account ID. --parent-tenant-id takes the parent org's canonical tnt- id — the server resolves handles to internal row ids; no database identifier ever crosses the API (B118 D3/D4). B121 domain ownership verification is a separate, additive control tracked in tenant_domains: _aac-challenge.<domain>. TXT aac-verify=<token>, issued/verified through the tenant-admin commands above. A verified business domain is evidence only. B182's separate bind-trust-domain request admits a domain's first SPIFFE binding only from B228-current evidence for the exact same name; parent-domain proof does not cover subdomains. SPIFFE-valid values outside the DNS proof grammar remain ceremony-only, and existing binding history remains B181.

Semantics worth knowing

  • aac chain show accepts ANY hop's token id or the chain root id (--root-token-id is an accepted alias); visibility is participant-tenant over the symmetric composite closure (Week 12) — non-participants get the same 404 as unknown tokens.
  • Timelines are §V.2.1 METADATA-TIER: predicates and business narratives stay in your tenant SIEM stream; the table output's footer says so (§6.1 federated join is the full-fidelity story).
  • Exit codes (CLI Config+Profile Spec §14, ratified 2026-08-04 — supersedes the originator-cli-era convention): 0 success / 1 remote outcome (server rejected/denied, or the server-side resource doesn't exist) / 2 invalid command-line usage / 3 invalid local configuration or state (missing profile/credential, malformed INI, bad registration state) / 4 transport failure (unreachable or timed out — the retryable class).
  • B159 rate limiting: a numeric server Retry-After is rendered beside the stable 429/503 error. The CLI never automatically replays a mutation; wait for the displayed interval and rerun deliberately.

Tests

uv run pytest cli/aac/tests/ — pytest-httpx mocks; no control plane needed. Against a live stack: bring up the joined topology (./bin/run-wedge-a-control-plane-compose.sh --keep-up) and point the flags at localhost.

Assigned tenant domains (B239)

Registration automatically saves the server-assigned hosted_trust_domain in the selected profile. The CLI displays the full name, explains its purpose in SPIFFE identities/certificates/trust configuration, and prints the command for finding it again. No manual copy is required. With JSON output, this guidance goes to stderr and stdout remains one JSON document; table output includes it inline. Completed-registration recovery provides the same saved-name guidance without changing credential-reissue requirements.

aac profile show dev --output table                         # saved locally, offline
aac tenant describe --profile dev --output table            # assigned name + current binding status
aac tenant list-trust-domains --profile dev --output table   # current ACTIVE bindings
aac tenant list-trust-domains --profile dev --all --output table  # includes revoked history
aac sso whoami --profile dev --output table                  # cached session + matching saved name

tenant describe accepts an optional --tenant-id; the usual flag → environment → selected profile precedence applies. Its response comes from AAC. Binding table output labels AAC-assigned/custom origin, ACTIVE/REVOKED status and inherited scope. Registration, describe, profile show and binding-list JSON fields retain their existing shapes. whoami adds optional hosted_trust_domain and hosted_trust_domain_source: "profile:<name>" fields when that profile's saved tenant matches the inspected session. These fields describe locally saved metadata, not current binding eligibility. Tenant overrides never display another tenant's saved domain; session exit codes and offline operation are unchanged. Profile show says "not saved in this profile" when metadata is absent, without asserting that AAC has no allocation.

Existing tenant admins use aac tenant assign-hosted-domain --profile dev; explicit eligible restoration uses aac tenant reactivate-hosted-domain --profile dev. Neither command registers another tenant or asks for a DNS name. See the hosted-domain guide for custom-domain progression, recovery compatibility and lifecycle limits.

Release files for aac-cli 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aac-cli 0.1.3
File Size Uploaded
aac_cli-0.1.3.tar.gz 185.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aac-cli 0.1.3
File Interpreter ABI Platform
aac_cli-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 299.1 kB

Release files / aac_cli-0.1.3.tar.gz

Download URL aac_cli-0.1.3.tar.gz
Size 185.0 kB
Tags Source
SHA-256 checksum
How to use checksums
80daad083d7d653b73c00dd3a6c2e63bc640533f693c78128c1da3b66306f983
BLAKE2b-256 checksum
How to use checksums
fb7185c6389815bf4752cb0abf54c2d45773311e291e984f8c105bdca176e654
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 12, 2026.

Transparency log

Release files / aac_cli-0.1.3-py3-none-any.whl

Download URL aac_cli-0.1.3-py3-none-any.whl
Size 114.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2407b2d5835d757b7566b6b736fea5963dbe32f21ef164ff89bca3084a0ed98f
BLAKE2b-256 checksum
How to use checksums
1fff6bc22c9eb9b77b4c65d66f9db29620cd45355363309650d7ac487dc5ca70
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 12, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page