- sources: named credential origins under
auth_origins - resolvers: runtime helper commands under
runtime_auth_resolvers - bindings: delivery rules that tell a host adapter how to consume credentials
| Layer | Main question | Runs where | Common local-process shape |
|---|---|---|---|
sources | ”What credential origin exists?” | Orchestrator before spawn, or agent runtime depending on scope | Often omitted entirely |
resolvers | ”What helper command should the adapter call later?” | Inside the agent environment at runtime | bedrock-auth-helper |
bindings | ”How does this adapter expect to receive auth?” | Adapter projection / spawn wiring | claude_api_key_helper or bearer_env |
At a Glance
Where config lives
fracta.yaml has two auth layers:
| Location | Purpose | Typical contents |
|---|---|---|
auth.credentials.profiles.<name> | Reusable credential profile | auth_origins, runtime_auth_resolvers, env, assertions, default_binding |
agents.agent_runtimes.<name> | Runtime entry that selects a profile | adapter, auth_profile, optional auth_binding override |
- Define a reusable profile under
auth.credentials.profiles. - Point a runtime at it with
auth_profile. - Override
auth_bindingon the runtime only when the same profile needs a different delivery shape for a different adapter.
How to read the names
Auth config mixes three different kinds of names:| Kind | What it is | Examples | Who interprets it |
|---|---|---|---|
| Schema keywords | Fixed field names and enum values from Fracta’s config schema | auth_profile, auth_origins, default_binding, secret_env, bearer_env, secret_ref | Fracta |
| Local labels | User-defined identifiers that other fields in the same config refer to | opencode_bedrock, seeded_token, bedrock_helper | Fracta, by matching references |
| External names | Names that must match real env vars, K8s Secrets, Secret keys, or runtime-specific variables | AWS_BEARER_TOKEN_BEDROCK, AWS_REGION, fracta-auth, bearer-token | Kubernetes, the runtime, or both |
| Field | Refers to |
|---|---|
auth_profile | A profile name under auth.credentials.profiles.<name> |
auth_origin | A source name under auth_origins.<name> |
runtime_auth_resolver | A resolver name under runtime_auth_resolvers.<name> |
- If changing the name requires changing a matching reference elsewhere in
fracta.yaml, it is probably a local label. - If changing the name requires changing a real Secret, env var, or runtime expectation outside
fracta.yaml, it is probably an external name. - If the name comes from the config schema itself, it is a schema keyword and should not be renamed.
Binding types
Bindings answer: “how do credentials reach the runtime?”| Binding Type | How it works | Typical use case | Notes |
|---|---|---|---|
claude_api_key_helper | Writes Claude’s apiKeyHelper setting plus env into user-settings.json | Claude + Bedrock bearer tokens with refresh/TTL | Claude-specific projection |
bearer_env | Injects a token directly as an env var | OpenAI API keys, Anthropic direct keys, Bedrock bearer env vars | Supports source-based, resolver-based, or env passthrough shapes |
token_file | Mounts credential data as a file | K8s file-mounted secrets | Uses a materialized source with a configured path |
Credential source types
Sources answer: “where does the credential come from?”| Source Type | What it does | Common scope | Typical use case |
|---|---|---|---|
http_header_token | Makes an HTTP request and extracts a token from a response header | agent_runtime | Bedrock/corporate proxy token fetch |
command_output | Runs a local command and uses stdout as the credential | host_edge or any | bedrock-auth-helper for host-side or local-process token fetch. Use scope: any for local-process mode so the token materializes at spawn time in all topologies. The command field must be a YAML array (e.g. ["bedrock-auth-helper"]), not a string. |
secret_env | References a pre-existing K8s Secret key as an env var | any | Static API keys in Kubernetes |
Quick examples
Claude with refreshable Bedrock auth:Architecture
Three Layers
Sources
Sources describe credential origins. In YAML, they live underauth_origins. Each source has a scope that determines when it is available:
| Scope | Meaning | Example |
|---|---|---|
agent_runtime | Only available to the agent/runtime helper after spawn | corporate proxy HEAD request |
host_edge | Prepared on the host before spawning | bedrock-auth-helper in host-orchestrated K8s |
any | Available in any topology | Pre-existing K8s Secret |
| Type | Description | Important fields |
|---|---|---|
http_header_token | Extract token from an HTTP response header | request, extract, scope |
command_output | Run a command and use stdout as the credential | command, scope, optional delivery, optional path |
secret_env | Reference a pre-existing K8s Secret | env_name, secret_ref, scope |
Resolvers
A resolver is a runtime helper command. The primary example isfetch-bedrock-token:
- Try corporate proxy HEAD request (source:
proxy) - If that fails, read mounted fallback file (source:
host_fallback)
sources block at all. Example: Claude can call bedrock-auth-helper directly as its apiKeyHelper.
order is deprecated. If a helper command needs fallback logic, the command should own it internally rather than duplicating it in config.
Bindings
Bindings describe how a host adapter consumes credentials:| Binding Type | Adapter Action | Required fields |
|---|---|---|
claude_api_key_helper | Write apiKeyHelper to ~/.claude/settings.json (Claude) | runtime_auth_resolver |
bearer_env | Inject token as environment variable | env_name, plus optionally auth_origin or runtime_auth_resolver |
token_file | Mount token as a file | auth_origin |
bearer_env has three valid shapes:
source + env_name: inject a materialized source into an env varresolver + env_name: inject the first materialized source that the helper usesenv_nameonly: plain env passthrough, where the value already exists in host/profile env
Execution Flow
Source Phase Annotation
When the planner builds a credential plan, each source is annotated with an execution phase based on its scope and the current topology:| Scope / Topology | host_edge | in_cluster |
|---|---|---|
host_edge | prepare_now | unavailable |
agent_runtime | runtime_only | runtime_only |
any | prepare_now | prepare_now |
Cross-Boundary Staging
When the orchestrator runs in-cluster (Topology B), host-edge credentials must be staged across the CP API boundary:Staging Rules
| Scenario | Result |
|---|---|
Remote + dispatch=queued + staging needed | Stage via CP API, attach refs |
Remote + dispatch=direct + staging needed | Error: requires queued |
Remote + mode=stream + staging needed | Error: stream incompatible |
| Remote + dispatch omitted + staging needed | Error: requires explicit queued |
| Remote + no staging needed | Pass through |
| Local + direct | Orchestrator handles in-process |
| Local + queued + required host_edge | Error: use direct or remote mode |
Config Reference
Minimal local-process profile (Claude on host)
Env passthrough profile (OpenAI/Codex-style)
source or resolver. It simply states that the adapter expects OPENAI_API_KEY to already be present in the merged env.
Full credential profile (K8s host-orchestrator)
In-cluster profile (no host_fallback — pods self-auth via the credentials proxy)
Host binding override (non-Claude adapter)
order Deprecation
resolvers.<name>.order is deprecated.
Use this rule going forward:
- If the helper is an opaque command, fallback order belongs inside the command.
- New configs should omit
order. - Existing configs may keep
ordertemporarily for backward compatibility.
Assertions
Assertions are declarative config-driven validation rules. They run against the final merged environment (host env + profile env + binding-derived env) before credentials are materialized. No Claude/Bedrock-specific logic is hardcoded in Go.| Assertion | Meaning |
|---|---|
require_env: [KEY] | Fail if KEY is not in the merged env |
forbid_env: [KEY] | Fail if KEY IS in the merged env |
require_source: [name] | Fail if the named source is not available for the topology |
warn_if_missing_env: [KEY] | Warn (non-fatal) if KEY is missing |
Diagnostics
fracta auth diagnose
- Credential origins with scope and execution phase
- Runtime helper command, TTL, and deprecated source order when present
- Binding type and target
- Assertion results (pass/fail)
- Final merged environment variables
Pod helper debug mode
SetFRACTA_CREDENTIALS_DEBUG=1 in the credential profile env to enable verbose stderr logging in fetch-bedrock-token:
Structured log events
All credential operations emit structured logs viafractalog.Component("credentials"):
| Event | When |
|---|---|
credentials.plan.build | Plan construction starts |
credentials.plan.source | Each source annotated with phase |
credentials.plan.complete | Plan ready with phase counts |
credentials.source.prepare | Host-edge source being materialized |
credentials.source.success / .fail | Source preparation result |
credentials.assertion.pass / .fail | Assertion evaluation |
credentials.stage.success / .fail | Cross-boundary staging |
credentials.rehydrate.success / .fail | Worker rehydration |
credentials.binding.project | Adapter projection |
credentials.spawn.materialized | Final spawn handoff |
Config File Locations
Afterfracta init --scaffold <mode>, the per-mode config files live under your project root:
| File | Mode | Description |
|---|---|---|
fracta.yaml (project root) | All modes | Operator-edited config; runtime.backend distinguishes modes |
deployment/configs/controlplane.yaml | Docker Compose | Server-side controlplane config (mounted into the controlplane container) |
deployment/configs/gateway.yaml | Docker Compose | Server-side gateway config |
deployment/k8s/manifests/fracta-controlplane.yaml | Kubernetes | Controlplane ConfigMap + Deployment |
deployment/k8s/manifests/fracta-gateway.yaml | Kubernetes | Gateway ConfigMap + Deployment |
Known Limitations
— Fixed:auth_profilenested underkubernetesauth_profileandauth_bindingnow live atagents.agent_runtimes.<name>.*directly, not underagents.agent_runtimes.<name>.kubernetes.*.K8sCredentialStageris not yet implemented — staging usesInMemoryCredentialStager(same-process) orRemoteCredentialStager(CP API HTTP). A K8s Secret-backed stager would be needed for multi-process production deployments without a CP API.- No end-to-end integration test covering the full remote staging → CP API → worker rehydration path.

