apus secrets

Manage SecretRefs and keep the active runtime snapshot healthy.

Command Role
reload Gateway RPC (secrets.reload): re-resolves refs and atomically publishes the owner-aware runtime snapshot (no config writes); eligible owner failures may publish as cold or stale warnings
store Manages team-scoped secret and environment values in the local shared state SQLite database
audit Read-only scan of config/auth/generated-model stores and legacy residues for plaintext, unresolved refs, and precedence drift (exec refs skipped unless --allow-exec)
configure Interactive planner for provider setup, target mapping, and preflight (requires a TTY)
apply Executes a saved plan (--dry-run validates only and skips exec checks by default; write mode rejects exec-containing plans unless --allow-exec), then scrubs targeted plaintext residues

Recommended operator loop:

apus secrets audit --check
apus secrets configure --plan-out /tmp/apus-secrets-plan.json
apus secrets apply --from /tmp/apus-secrets-plan.json --dry-run
apus secrets apply --from /tmp/apus-secrets-plan.json
apus secrets audit --check
apus secrets reload

If your plan includes exec SecretRefs/providers, pass --allow-exec on both the dry-run and write apply commands. If the closing audit --check still reports plaintext findings, update the remaining reported target paths and rerun the audit.

Exit codes for CI/gates:

Related: Secrets Management · 1Password plugin · SecretRef Credential Surface · Security

Shared secret store

apus secrets store writes directly to the local shared state database. The store is Gateway-wide and team-scoped, and --scope team is the only accepted value. --scope me exits 2 with Identity scope is not supported yet; use --scope team.

Entries also arrive from Settings -> Secrets in the Control UI, and from the agent's secrets tool. That tool asks you to type a credential into a masked prompt. It stores the credential without the value reaching the model.

apus secrets store list
apus secrets store set <NAME>
apus secrets store get <NAME>
apus secrets store rm <NAME>...
apus secrets store import [--from <file>]

Naming and value rules:

File paths passed to --value-file or --from must identify regular files. Named pipes and device paths are rejected; use stdin for streamed input.

Set values safely

--value is accepted only when the resolved kind is env:

apus secrets store set LOG_LEVEL --kind env --value debug

For secret values, --value is refused with exit code 2 because command-line arguments can leak through shell history and process listings. It is also refused if another writer changes the entry to secret before the value is saved. Explicit --kind env still reclassifies the entry. Use one of the three safe inputs instead:

Examples:

op read 'op://Engineering/OpenAI/apiKey' | \
  apus secrets store set OPENAI_API_KEY --kind secret

apus secrets store set TLS_PRIVATE_KEY \
  --kind secret \
  --value-file ./client-key.pem

set is idempotent and updates an existing name. Add --dry-run to validate and preview the operation without writing. A successful write reminds you to run apus secrets reload before a config-referenced value can take effect.

audit reports previously stored or resolved placeholders as PLACEHOLDER_VALUE and counts them as unresolved credentials (exit 2). For a corrupt store-backed Gateway token, run apus doctor --fix, restart the Gateway, and reconnect or re-pair devices. See Gateway token recovery.

Secret egress substitution fails closed until each secret has at least one exact allowed host. Bind or replace hosts with repeatable --allow-host flags. This policy-only form does not ask for or replace an existing secret value:

apus secrets store set OPENAI_API_KEY --allow-host api.openai.com
apus secrets store set SERVICE_TOKEN \
  --allow-host api.example.com \
  --allow-host uploads.example.com
apus secrets store set SERVICE_TOKEN --clear-allowed-hosts

Hosts are normalized to lowercase ASCII/punycode. Schemes, paths, ports, and wildcards are rejected. store list shows allowed hosts because they are policy metadata, not secret material.

Read values

apus secrets store list --json
apus secrets store list --plain
apus secrets store get LOG_LEVEL

Secret values never appear in human, --json, or --plain output. store get refuses a secret entry as write-only by design and exits 2. It exits 3 when the name does not exist. Environment-kind values are readable.

Team-scoped env entries reach Gateway-hosted commands run by Apus's own exec tool, including Apus Code Mode calls into apus:core:exec and Codex gateway_exec. Explicit per-call env wins over store values. Sandbox, remote node, ACP, and Codex-native shell execution do not receive them. secret entries stay out of subprocesses by default. With secrets.egressProxy.enabled: true, Gateway-hosted exec receives only authenticated sentinels and the Gateway replaces them at HTTPS egress. See Secret egress proxy.

Store entries do not reach commands run inside an external agent harness. The Codex app-server and its sandbox exec-server, and ACP children such as Claude Code, build their own child environment and never pass through Apus's exec preparation. In eligible Codex turns, use gateway_exec to enter the Apus-managed Gateway environment path instead.

Remove values

apus secrets store rm OLD_TOKEN
apus secrets store rm OLD_TOKEN LEGACY_PASSWORD --yes
apus secrets store rm OLD_TOKEN --dry-run

Removal is idempotent, so a missing name succeeds quietly. Without --yes, the CLI asks for confirmation. Removed rows are soft-deleted and purged after 30 days.

Import dotenv files

Import dotenv-format assignments from a regular file or stdin:

apus secrets store import --from .env
apus secrets store import --from .env --dry-run
apus secrets store import --from .env --yes
op read 'op://Engineering/service-account/dotenv' | apus secrets store import --yes

The importer supports quoted values and multiline quoted values such as PEM keys. Use --yes to skip confirmation and --dry-run to inspect the import without writing. Like store set, import preserves an existing entry's kind and uses the name-based rule only for new names. Pass --kind secret|env to explicitly reclassify all imported entries.

The store CLI commands do not accept --url or --token and do not route through the Gateway. The Control UI uses the admin-scoped secrets.store.* RPC methods instead. Those methods refresh the runtime automatically when a changed name is referenced by active config.

Reload runtime snapshot

apus secrets reload
apus secrets reload --json
apus secrets reload --url ws://127.0.0.1:18789 --token <token>

Uses gateway RPC method secrets.reload. Healthy owners refresh independently. Eligible failed owners become stale only when their ref identities, provider definitions, and complete non-secret owner contract are unchanged. New or changed failures become cold. This degraded activation succeeds and reports warningCount. Strict or unmapped failures return an error and preserve the previously active snapshot.

Options: --url <url>, --token <token>, --timeout <ms>, --json.

Audit

Scans Apus state for:

The .env scan covers the effective state directory and the directory containing the active config. When both paths name the same file, it is scanned once.

Sensitive provider header detection is name-heuristic based: it flags headers whose name matches common auth/credential fragments (authorization, x-api-key, token, secret, password, credential).

Doctor and secrets audit share the plaintext classification for apus.json. Known non-secret provider API-key markers such as ollama-local, SecretRefs, and non-sensitive provider headers do not produce plaintext warnings. Real plaintext keys still do.

apus secrets audit
apus secrets audit --check
apus secrets audit --json
apus secrets audit --allow-exec

Report shape:

Configure (interactive helper)

Build provider and SecretRef changes interactively, run preflight, and optionally apply:

apus secrets configure
apus secrets configure --plan-out /tmp/apus-secrets-plan.json
apus secrets configure --apply --yes
apus secrets configure --providers-only
apus secrets configure --skip-provider-setup
apus secrets configure --agent ops
apus secrets configure --json

Flow: provider setup first (add/edit/remove secrets.providers aliases), then credential mapping (select fields, assign {source, provider, id} refs), then preflight and optional apply.

For env and store refs, no provider entry is required when provider matches that source's effective default: secrets.defaults.env or secrets.defaults.store, falling back to default when unset. Other aliases and all file/exec refs require a matching secrets.providers entry.

Flags:

--providers-only and --skip-provider-setup cannot be combined.

Notes:

Exec provider safety

Package managers often expose symlinked command paths. Resolve the real binary path (for example with realpath "$(command -v vault)") and configure that absolute, non-symlink path. Use trustedDirs to restrict executables to approved directories. Run apus config validate on the Gateway host to check manual exec command paths without executing providers. On Windows, provider paths fail closed when ACL verification is unavailable, with no provider-level bypass.

Apply a saved plan

apus secrets apply --from /tmp/apus-secrets-plan.json
apus secrets apply --from /tmp/apus-secrets-plan.json --allow-exec
apus secrets apply --from /tmp/apus-secrets-plan.json --dry-run
apus secrets apply --from /tmp/apus-secrets-plan.json --dry-run --allow-exec
apus secrets apply --from /tmp/apus-secrets-plan.json --json

--dry-run validates preflight without writing files. Exec SecretRef checks are skipped by default in dry-run. Write mode rejects plans containing exec SecretRefs/providers unless --allow-exec. Use --allow-exec to opt in to exec provider checks/execution in either mode.

--from must point to a regular file no larger than 16 MiB (16,777,216 bytes). The byte limit applies to the complete serialized file, including whitespace.

What apply may update:

Plan contract details (allowed target paths, validation rules, failure semantics): Secrets Apply Plan Contract.

Why no rollback backups

secrets apply intentionally does not write rollback backups containing old plaintext values. Safety comes from strict preflight plus atomic-ish apply, with best-effort in-memory restore on failure.

Related