Skip to content

Data and Trust Boundaries

Bifrost analyzes source on the machine where its process runs. That local execution boundary does not mean source stays outside every networked service: an MCP or editor host receives Bifrost’s tool results, and the host may send returned snippets, paths, symbols, or diagnostics to its configured model provider. Review the host and model provider’s data policy separately.

ComponentReads or receivesWrites or sends
Bifrost analyzer, CLI, and LSPFiles under the configured workspace root plus local Git metadata needed for indexingStructured results to stdout, stdio MCP, LSP, or the embedding caller; generated persistent data under .bifrost/cache/.
Agent MCP hostBifrost tool schemas and returned results, which may include source excerptsMay include those results in model requests, logs, transcripts, or host caches according to host configuration.
Agent-plugin launcherPinned release metadata and explicit environment or argument overridesMay download a checksum-verified Bifrost release from GitHub into a user cache.
Optional semantic searchWorkspace code chunks and a local embedding modelDownloads model files from Hugging Face on first use unless BIFROST_EMBED_MODEL_DIR points to local files; inference runs in a local Python sidecar and derived index data is cached.

The process root is explicit through --root, a packaged-launcher BIFROST_WORKSPACE_ROOT override, the MCP client’s standard roots response, or a negotiated codex/sandbox-state-meta value. Without an explicit override, the packaged launcher starts Bifrost unbound. A roots-capable client supplies the first usable local filesystem root in its ordered response. On a rootless connection without advertised roots, Bifrost offers the sandbox-state extension; current Codex uses it to supply the active turn’s canonical task directory on every analyzer tool call. Bifrost does not infer analyzer scope from launcher cwd, because plugin hosts may use the installed package directory there. A client supporting neither contract leaves the server unbound. Confirm the effective root before trusting a query or exposing a repository to an agent session.

Workspace-relative query files cannot escape the configured root. Results can still contain source excerpts from indexed files inside that root. Path filters narrow an individual request; they are not an access-control boundary for the already configured process.

Analyzer facts and optional semantic-index data use .bifrost/cache/bifrost_cache.v<N>.db at the primary Git repository root by default, where <N> is the cache schema version the running build reads. Every entry point resolves that one location: an explicit --root process, a rootless MCP process bound through client roots, and one bound through Codex sandbox metadata all reach the same database, and every linked worktree of a checkout shares the primary’s content-addressed cache rather than keeping a private copy. A workspace root outside any repository keeps .bifrost/cache/bifrost_cache.v<N>.db under that root. When the primary checkout is on a network filesystem, set BIFROST_CACHE_ROOT to a machine-local filesystem. Bifrost then derives a stable <repository-name>-<path-hash>/bifrost_cache.v<N>.db child beneath that root; linked worktrees still converge while unrelated repositories do not contend for one SQLite writer. Naming the file by schema version lets checkouts on different Bifrost versions share the directory without sharing a file: each build opens only its own, seeds it once by copying the newest store it can migrate forward, and never writes the older file the other checkout still uses. A superseded store is removed at startup or during opportunistic collection, but only after two weeks without use. Results stay scoped to the bound root regardless: the cache is keyed by content, and answers are resolved against the bound worktree’s current blob object IDs. The cache is local persistent data derived from workspace source and Git objects; protect and retain it according to the same sensitivity policy as the repository.

A process that cannot write the primary repository root fails with an actionable error rather than degrading silently. On Linux, Bifrost also refuses to create its SQLite WAL cache on NFS or SMB because their locking and shared-memory semantics do not satisfy the WAL contract; BIFROST_ALLOW_UNSAFE_NETWORK_CACHE=1 is an explicit unsafe escape hatch. In a sandboxed shell, prefer approving or elevating a local write the same way a sandboxed git commit writing .git is approved. Use BIFROST_CACHE_ROOT for durable relocation. Set BIFROST_CACHE_DIR only for a deliberate exact-directory override; the database is then $BIFROST_CACHE_DIR/bifrost_cache.v<N>.db, and concurrent unrelated repositories using that process contend for the same SQLite writer.

Only .bifrost/cache/ is generated state. .bifrost/queries/, .bifrost/policies/, and .bifrost/suppressions.json are project-owned inputs that may be reviewed and committed. A legacy ignore rule for the whole .bifrost/ directory can hide those inputs; replace it deliberately with a cache-only rule after reviewing any user-authored ignore content.

When upgrading from the former .bifrost/bifrost_cache.db layout, Bifrost keeps that database and its exact SQLite sidecars in place so it cannot delete files beneath an older process that is still using them. An exact generated whole-directory ignore is narrowed automatically to those legacy filenames. After every older Bifrost process has stopped, you may delete .bifrost/bifrost_cache.db, -wal, -shm, and -journal; the current cache under .bifrost/cache/ is independent and rebuildable.

Removing the database while Bifrost is stopped forces later work to rebuild it. A running process may also hold in-memory source and analysis state. If a test requires a clean cache, stop Bifrost first and record that removal in the evaluation method.

The agent plugin does not bundle the Bifrost executable. Release metadata names a preferred, checksum-pinned binary and the minimum compatible binary in that minor series. Stable patch releases in the range keep the existing MCP and LSP contracts: they may add tools or optional fields, but they do not remove tools or change existing meanings. A breaking plugin-facing change requires a new minor release, and skills that require a newer tool raise the declared minimum.

All Portable Agent Plugins v1/Codex, Claude Code, Cursor, Pi, and Amp adapters use the same launcher for MCP, and Claude Code uses it for LSP as well. The launcher resolves, in order:

  1. BIFROST_BINARY_PATH, when explicitly configured and compatible;
  2. an exact preferred binary in the launcher-managed cache;
  3. the newest compatible cached patch, selected by version rather than directory order;
  4. a compatible bifrost on PATH only when BIFROST_LAUNCHER_ALLOW_PATH=1;
  5. the exact preferred GitHub release, whose archive and checksum sidecar are verified against pinned SHA-256 metadata.

Different major or minor versions are rejected. Prerelease versions are also rejected unless release metadata explicitly permits them. The launcher never downloads an unpinned compatible fallback.

When the shared agent launcher starts a compatible fallback, it does not delay MCP or LSP registration. If automatic installation is enabled, it starts a detached helper that downloads and verifies only the checksum-pinned preferred release into the managed cache. The running server remains on the compatible binary and keeps its negotiated capabilities. A fresh host task selects the prepared preferred binary and negotiates its current tool surface.

The VS Code extension and the identical VSIX published to Open VSX carry the same preferred/minimum/prerelease fields. Their LSP provisioner reuses an exact or compatible managed binary before offering to download the checksum-pinned preferred release. Declining that download therefore does not disable LSP when a compatible managed patch is already cached.

Managed binaries are versioned under the launcher cache. The default root is ~/Library/Caches/bifrost-agent on macOS, %LOCALAPPDATA%/Bifrost/AgentPlugin on Windows, and $XDG_CACHE_HOME/bifrost-agent or ~/.cache/bifrost-agent on Linux. Set BIFROST_LAUNCHER_CACHE_DIR to relocate it or BIFROST_LAUNCHER_AUTO_INSTALL=0 to prohibit automatic downloads.

Run the package launcher’s doctor command to inspect the preferred and selected versions, source, compatibility mode, and cache path without modifying the cache or downloading anything. It executes the selected candidate with --version, so only inspect trusted binary locations. Run prepare to perform the same range-aware, checksum-pinned resolution before starting an MCP host. Both commands accept --json. If preparation changes the available binary, start a fresh host task so the MCP tool list is negotiated again.

  • Pin and verify the effective Bifrost binary and workspace root.
  • Decide whether launcher downloads are allowed.
  • Treat .bifrost/cache/bifrost_cache.v<N>.db, host transcripts, and model-provider logs as repository-sensitive artifacts.
  • Configure repository exclusions and request path filters, but do not mistake filters for process isolation.
  • Inspect representative tool output before granting an agent access; source excerpts can leave the local process through the host.
  • Start a fresh host session after MCP configuration changes and re-check the advertised tool surface.