Secret framework onboarding

First-run setup of the secret framework on a new machine or in a new repository. This document walks from "nothing configured" to "devboy doctor --secrets is green and the manifest passes CI".

When to use: after npm install -g @devboy-tools/cli and the basic devboy onboard (see Quick start). If your project already has .devboy/secrets.toml and you want an interactive wizard, run setup-secrets via the AI agent — it automates the same steps.

Russian translation: ru/onboarding.md.

Readiness checklist

  • devboy --version answers (CLI installed).
  • OS keychain available (macOS Keychain / Windows Credential Manager / Linux Secret Service).
  • Permissions to create ~/.devboy/secrets/ and <project>/.devboy/.
  • You know which secrets the project needs (one is enough to start — the manifest grows as you go).

Step 1. Install and verify the CLI

If devboy is already on PATH, skip this step.

npm install -g @devboy-tools/cli
devboy --version

Alternative via cargo:

cargo install devboy-cli

Confirm the secrets subsystem is available:

devboy secrets --help

You should see subcommands list, describe, validate, migrate, agent, ui, rotate, catalog. If any are missing, upgrade the CLI to 0.26 or later (the minimum version that ships the secret framework).

Companion binaries

The npm package and the GitHub Release tarball ship two companion binaries alongside devboy:

  • devboy-secrets-agent — long-running daemon that owns the unlocked local-vault. Spawned on demand by devboy secrets agent start; not required unless you use the local-vault source.
  • devboy-secrets-ui — native GUI window (eframe / egui) for the inventory + provision dialog. Spawned by devboy secrets ui --gui as a subprocess; not required for TUI / CI-only usage.

Both are placed next to devboy in the same bin/ directory, so the CLI's discovery walk (env override → sibling of current_exe()PATH) finds them out of the box. If you build from source via cargo install --path crates/devboy-cli, run the same cargo install against crates/devboy-secrets-agent / crates/devboy-secrets-ui-bin to get the companions. The DEVBOY_AGENT_BIN and DEVBOY_UI_BIN env vars override discovery for tests / dev workflows.

The split keeps the CLI itself lean (~19 MiB) — CI runs hitting secrets list / secrets validate / the MCP server never link the eframe rendering stack.

Step 2. Wire up the first source

By default the CLI works against the OS keychain with no configuration. That's enough for one developer on one machine. When the team adds 1Password, Vault, or env-store, you extend the router config. Start with keychain.

Create ~/.devboy/secrets/sources.toml (if you don't have one yet):

mkdir -p ~/.devboy/secrets
# ~/.devboy/secrets/sources.toml
schema_version = 1

[[source]]
name = "default-keychain"
type = "keychain"
# No credentials needed — the keychain manages access itself.

# When no `[[route]]` matches by prefix, the router falls back
# to the default source. `fallback` engages when the default
# answers `NotInstalled` (CI without an OS keychain).
[default]
source = "default-keychain"

Verify the router sees the source:

devboy doctor --checks context-secrets --format json

You should get an entry like {"name": "default-keychain", "type": "keychain", "available": true}.

If you plan to use 1Password / Vault: add a separate [[source]] block of type 1password or vault, plus a [[route]] with the matching prefix. Details: docs/guide/secrets/local-vault.md.

Using an existing KeePass database

If you already keep your tokens in a KeePass .kdbx file, point devboy at it via env var (no router config needed for read-only use):

export DEVBOY_KDBX_FILE=~/Documents/secrets.kdbx
# Optional companion keyfile (two-factor unlock):
# export DEVBOY_KDBX_KEYFILE=~/Documents/secrets.keyx

devboy secrets ui --gui

The UI window opens with an "Unlock KeePass database" modal asking for the passphrase. After unlock the inventory populates with one row per KeePass entry. Path mapping: Personal / Cloud / "AWS Access Key"kdbx/personal/cloud/aws-access-key. The decrypted snapshot lives inside the UI process only — the devboy-secrets-agent daemon never opens the file. Read-only MVP; writing back lands as a follow-up.

For a non-GUI smoke (CI / headless dev box):

devboy secrets kdbx peek --file ~/Documents/secrets.kdbx
# Prompts for passphrase in-terminal (no echo); prints the inventory
# table — path / Title / UserName / URL / `password?` yes-no. Values
# are never printed.

Step 3. Project manifest

The manifest declares which secrets the project expects. Without it the framework has no idea what to look for and doctor cannot complain about missing values.

Create <project>/.devboy/secrets.toml:

# <project>/.devboy/secrets.toml
required = [
  "team/<provider>/api-key",
  "team/<provider>/deploy-token",
]

optional = [
  "personal/<provider>/feature-flag-token",
]

[overrides."team/<provider>/api-key"]
description = "Used by the CI pipeline when publishing artefacts."
rotate_every_days = 90
# Force agents to confirm every USE of this token, not just its
# provision. See "Step 4b. Approve-on-use policy" below.
approve_on_use = "per-call"

[secret."sandbox/<provider>/local-token"]
description = "Local smoke tests only; never committed."
retrieval_url = "https://example.invalid/<provider>/tokens"
pattern_id = "generic-bearer"
rotation_method = "manual"

Structure (see ADR-020):

  • required — list of paths in ADR-020 form (<scope>/<provider>/<purpose>); the project does not work without their values.
  • optional — paths that improve UX (mailers, feature flags) but don't block the build.
  • [overrides."<path>"] — per-path metadata patches over the global index (~/.devboy/secrets/index.toml).
  • [secret."<path>"] — full declaration for a path that exists only in this project (sandbox scenarios, local playgrounds).

Use placeholders, not real names: examples use <provider> / <purpose> placeholders. In a real manifest write concrete segments (team/jira/api-key), but never publish client names, internal team codes, or server IDs to GitHub — that's an infra leak. For those, use the team/-scope with a generic provider name.

Step 4. Validate the manifest

Re-run format validation after every manifest edit:

devboy secrets validate

What it checks (see ADR-021 §6):

  • Every path is valid ADR-020 (3+ segments, kebab-case).
  • requiredoptional is empty.
  • rotate_every_days, expires_at, pattern_id are well-typed.
  • With the liveness flag (--liveness), the framework also checks that for every required path there's a router source that can return a value.

Wire the command into a pre-commit hook or CI pipeline:

# .github/workflows/secrets.yml
- run: devboy secrets validate --strict

--strict promotes warnings about non-conformant paths (P10.1) to errors.

Step 4b. Approve-on-use policy (optional)

Most paths resolve silently — the proxy alias resolver swaps @secret:<path> for the value with no agent prompt. For high-stakes credentials (production database password, signing key, billing API token), the manifest can require the user to confirm each use even after the value has been provisioned. This is separate from rotation gating: rotation already requires a destructive-confirm dialog; approve-on-use covers reads.

Three policies live on the approve_on_use field of an IndexEntry or OverrideEntry:

PolicyBehaviourRight for
never (default)Resolve silently — no dialog.Most paths.
sessionPrompt on first resolve in the process; cache the approval for the rest of the session.Stage credentials you don't want to log every five minutes but still want logged once.
per-callPrompt on every resolve; cache is bypassed.Production credentials, signing keys, anything destructive.

Examples:

# ~/.devboy/secrets/index.toml — global default for a path
[secret."team/prod-db/password"]
description = "Production DB password — approve every use."
rotation_method = "manual"
approve_on_use = "per-call"

# <project>/.devboy/secrets.toml — project-level tightening
[overrides."team/<provider>/api-key"]
approve_on_use = "session"

Override precedence per [ADR-020] §4: [overrides."<path>"].approve_on_use wins over the global index entry. The project can therefore tighten (move from never to per-call) without rewriting the global index. Loosening (per-callnever) works the same way and is the contract — the project owner has the authority to relax their own copy.

What the dialog looks like is in agent-protocol.md. The cache that holds session approvals is devboy-core::secret_approval::SessionApprovalCache, scoped per-process; closing the agent session clears it.

Step 5. Inspect what the framework sees

devboy secrets list

The output is a table with columns path, status, expires_at, provider. Metadata only — no values.

Per-path details:

devboy secrets describe team/<provider>/api-key

Shows description, retrieval_url, rotation_method, last_rotated_at, pattern_id, and every overrides patch applied on top of the global index.

JSON mode for scripts:

devboy secrets list --json | jq '.[] | select(.status == "missing")'

Step 6. Provision values

Values land in the keychain through secrets ui (TUI/GUI with a provision dialog) or via the AI agent (secrets_request_provision MCP tool). Pick the mode that fits:

  • Interactive (recommended):

    devboy secrets ui --tui

    Opens a TUI with the inventory view. Arrow keys navigate, Enter opens the provision dialog for the selected path, q quits. In a GUI environment the CLI auto-detects $DISPLAY / $WAYLAND_DISPLAY and launches the egui window instead.

  • Via the AI agent: ask the agent to "provision missing secrets" — it runs the setup-secrets skill (see docs/guide/secrets/agent-protocol.md).

  • Scripted (only for repeatable secrets on one machine):

    devboy secrets rotate team/<provider>/api-key --from-stdin --yes <<<"<value>"

    Stamps the rotation time and validates the format. For initial provisioning the equivalent is to bring the daemon up and write through the provision flow; see docs/guide/secrets/local-vault.md.

After values are in, secrets list shows status = provisioned for paths whose value actually landed in the keychain.

Step 7. Final check

devboy doctor --secrets

A green run means:

  • Every required path is provisioned.
  • Every source in sources.toml is available.
  • No non-conformant paths in the keychain (legacy entries migrated — see devboy secrets migrate).
  • Daemon is running (only if you actually use secrets ui or the MCP tools).

If anything is red, doctor prints the exact code and suggests a fix command. Next stops: the repair skill or the Doctor section.

What's next

  • local-vault.md — set up your own local store (zeroize-on-drop file with XChaCha20-Poly1305).
  • token-catalog.md — author per-provider procedure files (kimi.json, openai.json, …) the GUI binds to.
  • catalog-url-sources.md — serve the catalog over the network with sha-pinning + audit log.
  • agent-protocol.md — how the AI agent works with secrets through MCP without ever seeing the values.
  • setup-skill.md — the AI-driven equivalent of this page: eight-step flow, setup-state.toml shape, resume contract.
  • source-plugin-protocol.md — add your own source via the subprocess plugin protocol.
  • ADR-020 / ADR-021 / ADR-023 — the formal specs of the manifest, the router, and the UX layer.