Skip to content

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.

  • 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.

PathHoldsMountedMode
tokens/<project>/<service>/<file>Credentials for one MCP serviceThat service’s worker only, at /tokens (read-only)file 0o600, dir 0o700
tokens/<project>/llm/<provider_id>_api_keyAPI key for one LLM providerproxy container only, at /tokens (read-only), as env name SPW_KEY_<PROVIDER_ID>file 0o600, dir 0o700
claude-home/<project>/.claude/.credentials.jsonAnthropic OAuth credentials${CLAUDE_HOME} at /home/speedwave (read-write)managed by Claude Code
oauth/<project>/<service>.jsonPlugin OAuth refresh tokens and client secretsNot mounted; a host-side oauth worker reads itfile 0o600, dir 0o700
plugin-state/<slug>/bridge-tokenPersisted host-bridge auth tokenNot mountedfile 0o600 when present
ide-bridge/<port>.lockIDE Bridge UUID v4 auth token/home/speedwave/.claude/ide/ (read-only)file 0o600, dir 0o700

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.

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:

SPW_KEY env-name and path examples
openrouter -> SPW_KEY_OPENROUTER
my-anthropic -> SPW_KEY_MY_ANTHROPIC
tokens/proj/llm/openrouter_api_key

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 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.

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.

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/.

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.