Secret management¶
How secrets are named, bound, resolved, and kept out of packs, corpus, state, and documentation.
Core principle¶
Secret names and provider bindings are configuration. Secret values are never stored in Conductor, corpus, packs, state, indexes, profile docs, or generated output.
A missing secret is an explicit failure — Conductor never falls back to a default, environment variable, or hard-coded value.
Architecture¶
Organization profile Secret provider (Bitwarden)
┌──────────────────────┐ ┌──────────────────────────┐
│ Secret names: │ │ Secret values: │
│ NOTION_API_KEY │──bind──→ │ nt_api_xyz... │
│ GITHUB_TOKEN │──bind──→ │ ghp_abc... │
│ BWS_ACCESS_TOKEN │──bind──→ │ bws_def... │
│ CONDUCTOR_AUTH │──bind──→ │ conductor_token_... │
└──────────────────────┘ └──────────────────────────┘
│ │
│ name │ value (ephemeral)
▼ ▼
┌─────────────────────────────────────────────────┐
│ Secret resolution │
│ name → provider query → ephemeral value │
│ Value never stored; delivered to caller only │
└─────────────────────────────────────────────────┘
│
│ ephemeral value (in-memory only)
▼
┌─────────────────────────────────────────────────┐
│ Caller (agent, adapter, compiler) │
│ Uses value for one operation; never persists │
└─────────────────────────────────────────────────┘
Secret names¶
Secret names are declared in the organization profile and adapter configuration:
| Secret name | Purpose | Required by |
|---|---|---|
CONDUCTOR_MCP_AUTH_TOKEN |
Authenticate agent to Conductor MCP | All requesting agents |
CONDUCTOR_GATE_C_APPROVED |
Enable live Notion/GitHub reads | Estate preparation tools |
CONDUCTOR_READ_ALLOW_LIVE |
Permit live adapter reads | Read adapters |
CONDUCTOR_NOTION_READ_TOKEN |
Notion API access token | Notion read adapter |
CONDUCTOR_GITHUB_READ_TOKEN |
GitHub API access token | GitHub read adapter |
BWS_ACCESS_TOKEN |
Bitwarden Secrets Manager access | Secret resolution component |
BWS_ORG_ID |
Bitwarden organization ID | Secret resolution component |
BWS_PROJECT_ID |
Bitwarden project ID | Secret resolution component |
VPS_HOST |
Deploy host address | Deploy operations |
VPS_SSH_KEY |
Deploy SSH private key | Deploy operations |
TAILSCALE_AUTHKEY |
Tailscale authentication | Deploy operations (self-hosted) |
NOTION_WORKSPACE_ID |
Notion workspace identifier | Notion adapter |
NOTION_DATABASE_IDS |
Notion database identifiers | Notion adapter |
GITHUB_ORG_ALLOWLIST |
Permitted GitHub organizations | GitHub adapter |
GITHUB_REPO_ALLOWLIST |
Permitted GitHub repositories | GitHub adapter |
Provider bindings¶
The organization profile maps secret names to provider-specific lookup keys:
secrets:
- name: CONDUCTOR_MCP_AUTH_TOKEN
provider: bitwarden
provider_key: conductor-mcp-auth-token
required: true
- name: CONDUCTOR_NOTION_READ_TOKEN
provider: bitwarden
provider_key: notion-read-token
required: true
Rules:
- Provider is always bitwarden (Bitwarden Secrets Manager) for Conductor
- provider_key is the lookup key in Bitwarden, not the value
- required: true means the secret must resolve or the operation fails
- required: false means the secret is optional (operation proceeds without it)
Resolution path¶
1. Agent requests secret-dependent operation
2. Conductor identifies required secret names from config
3. Secret resolution component queries Bitwarden for each name
4. Bitwarden returns ephemeral value (in-memory, never logged)
5. Value is delivered to the requesting component
6. Component uses value for one operation
7. Value is discarded after use
Resolution is synchronous and per-request. Values are never cached across authorization boundaries. Each consult_plan or adapter read resolves secrets fresh.
Never-in-pack rule¶
Secret values must never appear in:
| Surface | Enforcement |
|---|---|
| Authorized packs | Compiler strips secret references before emission |
| Corpus units | Proposal validation rejects secret values |
| Notion state | Adapter never writes secrets |
| GitHub repositories | Pre-commit hooks and CI checks reject secrets |
| Generated documentation | Generator excludes secret sections |
| Organization profile | Only names and bindings, never values |
| Experience records | Feedback validation strips secrets |
| Chat memory or logs | Agent instruction: never echo secrets |
Missing-secret behavior¶
| Scenario | Behavior |
|---|---|
| Required secret name has no binding | Operation fails; error: secret.<name>.unbound |
| Provider unreachable | Operation fails; error: provider.unavailable |
| Provider returns no value for key | Operation fails; error: secret.<name>.missing |
| Optional secret missing | Operation proceeds without it; warning emitted |
| Secret value appears in plan or evidence | Authorization refused; finding: secret.leaked |
Software-specific secrets¶
For Software deployments, per-repository secrets follow additional rules:
# corpus/lines/software/units/sw.std.secrets.md
Key points:
- Canonical store: Bitwarden Secrets Manager (EU), project workspaces
- Unlock with the Python secret-gate CLI (not legacy secret-gate.ps1); Windows requires pwsh 7.2+
- Use cached session when present
- Prefer generic reusable key names (VPS_SSH_KEY, not my-app-vps-ssh-key)
- Before creating a secret, bws secret list and reuse if suitable
- New secrets: create placeholder → Hector updates value in vault UI
Per-repo CI secrets (Lab/Portfolio Free-plan orgs):
- VPS_HOST — Tailscale IP of deploy host
- VPS_SSH_KEY — Deploy SSH private key
- TAILSCALE_AUTHKEY — Tailscale auth for Actions
- Set after promotion via add-repo-secrets.ps1
Prohibited: - Hard-coding tokens in scripts or docs - Echoing secret values into chat/logs when avoidable - Committing secrets, API keys, or private keys to git
Adding a new secret binding¶
- Identify the secret's purpose and which component needs it
- Add the secret name to the organization profile's secrets list
- Create the secret value in Bitwarden with the matching provider key
- Update any adapter or component configuration to reference the name
- Never document the value — only the name and purpose
Related documents¶
- Privacy model:
reference/security/privacy-model.md - Organization profile:
about/organization-profile.md - Read access contract:
evidence/read-access-contract.md - Connection guide (token retrieval):
guides/connecting.md - Software secrets standard:
corpus/lines/software/units/sw.std.secrets.md - Secrets standard:
corpus/standards/secrets.yml - Authority model (secret rows in ownership table):
reference/authority/authority-model.md