Skip to main content
How Claude Code reaches LLMs across machines. Routes through Bifrost so traffic hits Cecelia (free Bedrock) instead of paid accounts.

Topology

work-laptop (Mac) ─┐
debian-1 / i3      ├──► bifrost.augustin.ai/anthropic ──► Cecelia Bedrock (us-west-2)
pentium / debian-2 ─┘
MachineVK nameVK secret location
work-laptopwork-laptopmacOS 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

NameAccountAuthNotes
cecelia175342148895rotating STSFree, work-funded. Streaming requires User-Agent: claude-cli/... (set in network_config.extra_headers).
isengard-runtime666654122230long-term bearerPersonal AWS, paid. 74 models. Budget exhausted for the current month — minimize traffic.
isengard-mantle-openai666654122230long-term bearerFree, work-funded. 38 OpenAI-shape Mantle models at bedrock-mantle.us-east-1.api.aws.
isengard-mantle-anthropic666654122230long-term bearer (in extra_headers)Free, work-funded. 2 Anthropic-shape Mantle models at the /anthropic path suffix.
kiroaiclient2api tokenFree 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:
  1. bedrock-to-cecelia-redirect — any request with provider == "bedrock" (the keyless built-in) → cecelia.
  2. work-laptop-anthropic-to-cecelia — for the work-laptop VK, models matching us.anthropic.* or global.anthropic.* → cecelia, regardless of which provider/ prefix the client sent.
NameUsed by
pentiumpentium machine CC
i3debian-1 i3 desktop CC
work-laptopwork laptop CC and Zed
augustin-defaultbreak-glass / personal use
n8n-classifiern8n email classifier
mastraMastra agents
VK reshape to client-scoped names (e.g. work-laptop-claude-code, i3-kiro) is planned but not yet done.

Auth flow

CC reads the API key via apiKeyHelper 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
Zed-launched CC is a separate auth pathway. Zed sets 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 pathClient speaksNotes
/anthropic/v1/messagesAnthropic MessagesUsed by CC.
/openai/v1/chat/completionsOpenAI chatUsed by Mastra, n8n, codex.
/bedrock/model/{id}/invoke...Bedrock rawAvoid for CC — patched stream converter, brittle.
VK scope decides which provider serves the request, not the path.

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:
  1. launchd timer com.augustin.sync-cecelia-creds — every 5 min (StartInterval=300, RunAtLoad=true).
  2. sleepwatcher (brew install sleepwatcher, started via brew services) — runs ~/.wakeup on every wake-from-sleep, which calls the sync script. Required because StartInterval does not catch up missed ticks across sleep.
  3. auth.py (the a alias) — calls run_sync_cecelia_creds() after mwinit -f and the Isengard ada update.
If Bifrost returns 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 in enabledPlugins.
  • Anthropic model IDs on Bedrockcecelia and isengard-runtime need us.* or global.* cross-region inference profile IDs. Bare anthropic.* IDs reject. Mantle is the opposite: bare IDs only.
  • Tool Search through proxies — Claude Code disables Tool Search by default when ANTHROPIC_BASE_URL is non-first-party. Force it on with ENABLE_TOOL_SEARCH=true (or auto:N) in ~/.claude/settings.json env block. Otherwise CC sends every MCP tool definition on every request and burns the context window.

Files

PathWherePurpose
~/.claude/settings.jsonbothapiKeyHelper field, ANTHROPIC_BASE_URL env, hooks
~/.claude/bin/api-key-helper.shbothPer-OS VK resolver
~/.claude/bin/session-start.shbothAuto-sync hook
~/.config/zed/settings.jsonMacZed agent_servers.claude-acp.env with VK
~/Library/LaunchAgents/com.augustin.sync-cecelia-creds.plistMac5-min STS refresh (RunAtLoad=true)
~/Library/LaunchAgents/homebrew.mxcl.sleepwatcher.plistMacsleepwatcher service (brew)
~/.wakeupMacSleepwatcher hook — runs sync on wake
~/bin/sync-cecelia-creds.shMacSTS refresh script
~/apps/bifrost/.envdebian-1BIFROST_VK= for the i3 machine
~/apps/bifrost/compose.yamldebian-1Bifrost service, image tag