Topology
| Machine | VK name | VK secret location |
|---|---|---|
| work-laptop | work-laptop | macOS Keychain item bifrost-vk |
| debian-1 (i3 desktop) | i3 | ~/apps/bifrost/.env BIFROST_VK= |
| pentium (debian-2) | pentium | (location not confirmed; receiving traffic but secret distribution mechanism is unclear — investigate as part of the VK reshape) |
Providers in Bifrost
| Name | Account | Auth | Notes |
|---|---|---|---|
cecelia | 175342148895 | rotating STS | Free, work-funded. Streaming requires User-Agent: claude-cli/... (set in network_config.extra_headers). |
isengard-runtime | 666654122230 | long-term bearer | Personal AWS, paid. 74 models. Budget exhausted for the current month — minimize traffic. |
isengard-mantle-openai | 666654122230 | long-term bearer | Free, work-funded. 38 OpenAI-shape Mantle models at bedrock-mantle.us-east-1.api.aws. |
isengard-mantle-anthropic | 666654122230 | long-term bearer (in extra_headers) | Free, work-funded. 2 Anthropic-shape Mantle models at the /anthropic path suffix. |
kiro | — | aiclient2api token | Free Claude via Kiro OAuth. OAuth wedges roughly monthly; recovery requires re-auth on aiclient2api. |
bedrock | — | (no keys) | Built-in to Bifrost binary, not deletable. Has no keys; any traffic 403s. A routing rule rewrites bedrock/* to cecelia. |
VKs
Currently flat-scoped (each VK can reach all 6 providers). Two routing rules force work-laptop traffic onto cecelia regardless of VK scope:bedrock-to-cecelia-redirect— any request withprovider == "bedrock"(the keyless built-in) → cecelia.work-laptop-anthropic-to-cecelia— for the work-laptop VK, models matchingus.anthropic.*orglobal.anthropic.*→ cecelia, regardless of whichprovider/prefix the client sent.
| Name | Used by |
|---|---|
pentium | pentium machine CC |
i3 | debian-1 i3 desktop CC |
work-laptop | work laptop CC and Zed |
augustin-default | break-glass / personal use |
n8n-classifier | n8n email classifier |
mastra | Mastra agents |
work-laptop-claude-code, i3-kiro) is planned but not yet done.
Auth flow
CC reads the API key viaapiKeyHelper field in ~/.claude/settings.json. The helper at ~/.claude/bin/api-key-helper.sh resolves per-OS:
- macOS —
security find-generic-password -s bifrost-vk - Linux — reads
BIFROST_VK=from~/apps/bifrost/.env
ANTHROPIC_API_KEY directly via ~/.config/zed/settings.json agent_servers.claude-acp.env and bypasses the helper. The VK value lives inline there.
ANTHROPIC_BASE_URL is set in ~/.claude/settings.json env block (subprocess inheritance lands it in CC’s own env at HTTP-call time).
OAuth credentials (~/.claude/.credentials.json) take precedence over env-based auth. If CC unexpectedly bypasses Bifrost, claude auth logout clears them.
Path semantics
| Bifrost path | Client speaks | Notes |
|---|---|---|
/anthropic/v1/messages | Anthropic Messages | Used by CC. |
/openai/v1/chat/completions | OpenAI chat | Used by Mastra, n8n, codex. |
/bedrock/model/{id}/invoke... | Bedrock raw | Avoid for CC — patched stream converter, brittle. |
Cecelia STS refresh
ada credentials print --profile=claude-code-DO-NOT-DELETE mints temp creds for the Cecelia role
(CeceliaAmazonInternal in account 175342148895) and ~/bin/sync-cecelia-creds.sh PUTs them to
Bifrost at /api/providers/cecelia/keys/<uuid>.
STS TTL is 1 hour — the role’s MaxSessionDuration is the AWS default of 3600s.
The Isengard Admin role on account 666654122230 separately has a 6h TTL.
The script is idempotent and self-throttling: it reads existing cred age from Bifrost and skips the
refresh if the existing creds are still fresh (default: refresh when within 30 min of expiry).
This makes it safe to run on a 5-minute timer.
Three triggers refresh creds on the Mac:
- launchd timer
com.augustin.sync-cecelia-creds— every 5 min (StartInterval=300,RunAtLoad=true). - sleepwatcher (
brew install sleepwatcher, started viabrew services) — runs~/.wakeupon every wake-from-sleep, which calls the sync script. Required becauseStartIntervaldoes not catch up missed ticks across sleep. auth.py(theaalias) — callsrun_sync_cecelia_creds()aftermwinit -fand the Isengard ada update.
403 ExpiredToken, run ~/bin/sync-cecelia-creds.sh manually with FORCE_SYNC=1.
If that fails, Midway has likely expired upstream — run a first.
Sync hook
~/.claude/bin/session-start.sh runs on every CC session start. It stashes uncommitted edits, pulls origin/main, pops the stash, merges MCP config from mcp-servers.json into ~/.claude.json, then commits and pushes.
The hook propagates: settings.json, mcp-servers.json, bin/, skills/, commands/, rules/, CLAUDE.md, statusline.sh. It runs async so settings changes apply on the next session, not the one that initiated the sync.
Compliance limits
- 64-char tool names — Bedrock Converse API rejects MCP tools whose namespaced name (
mcp__server__tool) exceeds 64 chars. Filter at the MCP server with--exclude-tools=.... Plugins whose name alone exceeds 64 chars must be disabled inenabledPlugins. - Anthropic model IDs on Bedrock —
ceceliaandisengard-runtimeneedus.*orglobal.*cross-region inference profile IDs. Bareanthropic.*IDs reject. Mantle is the opposite: bare IDs only. - Tool Search through proxies — Claude Code disables Tool Search by default when
ANTHROPIC_BASE_URLis non-first-party. Force it on withENABLE_TOOL_SEARCH=true(orauto:N) in~/.claude/settings.jsonenv block. Otherwise CC sends every MCP tool definition on every request and burns the context window.
Files
| Path | Where | Purpose |
|---|---|---|
~/.claude/settings.json | both | apiKeyHelper field, ANTHROPIC_BASE_URL env, hooks |
~/.claude/bin/api-key-helper.sh | both | Per-OS VK resolver |
~/.claude/bin/session-start.sh | both | Auto-sync hook |
~/.config/zed/settings.json | Mac | Zed agent_servers.claude-acp.env with VK |
~/Library/LaunchAgents/com.augustin.sync-cecelia-creds.plist | Mac | 5-min STS refresh (RunAtLoad=true) |
~/Library/LaunchAgents/homebrew.mxcl.sleepwatcher.plist | Mac | sleepwatcher service (brew) |
~/.wakeup | Mac | Sleepwatcher hook — runs sync on wake |
~/bin/sync-cecelia-creds.sh | Mac | STS refresh script |
~/apps/bifrost/.env | debian-1 | BIFROST_VK= for the i3 machine |
~/apps/bifrost/compose.yaml | debian-1 | Bifrost service, image tag |