Token and credential paths
Every credential Speedwave stores lives under one data directory, ~/.speedwave/ by default. Set the SPEEDWAVE_DATA_DIR environment variable to move it elsewhere: every path below then resolves under your chosen location, and since Speedwave reads the variable once per process, changing it takes a restart. See environment variables for the full list Speedwave reads at startup, and how credentials are handled for the security rules that keep one service from reading another’s files.
Layout
Section titled “Layout”Directory~/.speedwave/
Directorytokens/
Directory<project> /
Directory<service> / per-service worker credentials
- … credential files
Directoryllm/
- <provider_id> _api_key LLM provider API key
Directoryclaude-home/
Directory<project> /
Directory.claude/
- .credentials.json Anthropic OAuth (owned by Claude Code)
Directoryoauth/
Directory<project> /
- <service> .json plugin OAuth refresh tokens (off-mount)
Directoryplugin-state/
Directory<slug> /
- bridge-token persisted host-bridge token
Directoryide-bridge/
- <port> .lock IDE Bridge UUID token
<project> is the per-project namespace. <service> is an MCP service id, either a built-in worker or a plugin slug. <provider_id> is an LLM provider id from claude.llm. <slug> is a plugin slug, and <port> is the IDE Bridge port.
Paths at a glance
Section titled “Paths at a glance”| Path | Holds | Mounted | Mode |
|---|---|---|---|
tokens/<project>/<service>/<file> | Credentials for one MCP service | That service’s worker only, at /tokens (read-only) | file 0o600, dir 0o700 |
tokens/<project>/llm/<provider_id>_api_key | API key for one LLM provider | proxy container only, at /tokens (read-only), as env name SPW_KEY_<PROVIDER_ID> | file 0o600, dir 0o700 |
claude-home/<project>/.claude/.credentials.json | Anthropic OAuth credentials | ${CLAUDE_HOME} at /home/speedwave (read-write) | managed by Claude Code |
oauth/<project>/<service>.json | Plugin OAuth refresh tokens and client secrets | Not mounted; a host-side oauth worker reads it | file 0o600, dir 0o700 |
plugin-state/<slug>/bridge-token | Persisted host-bridge auth token | Not mounted | file 0o600 when present |
ide-bridge/<port>.lock | IDE Bridge UUID v4 auth token | /home/speedwave/.claude/ide/ (read-only) | file 0o600, dir 0o700 |
Per-service worker tokens
Section titled “Per-service worker tokens”Each credential-bearing MCP service gets its own directory, tokens/<project>/<service>/, holding whatever files that service declares, created only for services whose credential file list is non-empty. That one directory gets mounted read-only into the matching worker, at /tokens, and the PLUGIN_TOKEN_PATH_MISMATCH SecurityCheck rule confirms the mounted path actually matches tokens/<project>/<service>/ before the container starts. A compromised worker exposes only that service’s own credentials.
LLM provider keys
Section titled “LLM provider keys”An LLM provider key configured under claude.llm lands at tokens/<project>/llm/<provider_id>_api_key, named after the provider id plus the suffix _api_key. That llm directory is mounted read-only into the proxy container only, with each key injected as an environment variable named SPW_KEY_<PROVIDER_ID>, the provider id uppercased with hyphens turned to underscores:
openrouter -> SPW_KEY_OPENROUTERmy-anthropic -> SPW_KEY_MY_ANTHROPIC
tokens/proj/llm/openrouter_api_keyAnthropic OAuth credentials
Section titled “Anthropic OAuth credentials”Anthropic OAuth credentials live at claude-home/<project>/.claude/.credentials.json, written and refreshed by Claude Code inside the ${CLAUDE_HOME} bind mount at /home/speedwave. Speedwave’s part is limited to locating the file for the compose mount and clearing it on speedwave logout.
Plugin OAuth refresh tokens
Section titled “Plugin OAuth refresh tokens”Plugin OAuth refresh tokens and client secrets never live under tokens/; they go off-mount instead, to oauth/<project>/<service>.json, which keeps every path under tokens/ read-only everywhere it is mounted. The filename is the service id, so a built-in OAuth service such as sharepoint writes sharepoint.json.
Plugin state and the bridge token
Section titled “Plugin state and the bridge token”Mutable per-plugin state lives at plugin-state/<slug>/, separate from the signed plugin files themselves. One example is the persisted host-bridge auth token, plugin-state/<slug>/bridge-token. Desktop’s host bridge writes it with mode 0o600, and only when the plugin manifest opts into persistent_token.
IDE Bridge lock file
Section titled “IDE Bridge lock file”The IDE Bridge lock file, ide-bridge/<port>.lock, holds a UUID v4 auth token that Desktop regenerates on every start and never persists across restarts. It’s written 0o600 inside a 0o700 parent directory and mounted into the container read-only, at /home/speedwave/.claude/ide/.
File permissions
Section titled “File permissions”Speedwave sets every credential file to mode 0o600 and its parent directory to 0o700, owned by your user account. On Windows, the equivalent is a DACL with a single full-control entry for your account, applied when the file or directory is created.
On Unix, Speedwave also checks these modes at startup and auto-fixes incorrect bits; it cannot fix ownership mismatches, which need root. Windows has no equivalent startup check: a DACL is set once at creation time and never re-verified or repaired on later starts.