Features
- One API across Anthropic, OpenAI and Ollama, streaming included
- Typed memory in local SQLite, with keyword and semantic recall
- USD budget enforced before the call is made, not after
- Routing policy in YAML, per task kind, hot-reloaded on edit
- Model Context Protocol client over stdio and Streamable HTTP
- Embedded web UI, served from the binary, no Node and no build step
Applications
- Agents that must survive a provider outage without a rewrite
- Local-first tools where prompts must never leave the machine
- Long-running assistants that need to remember across sessions
- Anything with a hard monthly ceiling on model spend
Install it
One static binary. No runtime, no container, no build toolchain.
go install gitlab.com/withvishal/bridge/tool/cmd/bridge@latestgo get gitlab.com/withvishal/bridge/toolFunctional block diagram
One call, five stages. Brain.Call and Brain.Stream share this path. The budget gate sits before the request goes out, so a call that would breach the ceiling is refused rather than billed and then reported.
Route
Policy picks provider and model for this task kind, filtered by privacy tier and the per-task cost cap.
Budget gate
Estimated cost is checked against the remaining ceiling and the call's own cap. Over budget stops here.
Memory
Recalled records fold into one system message at the head of the transcript. A failed recall is never fatal.
Tool loop
Tool calls execute in parallel, results append, the provider runs again. Capped at ten hops.
Charge
One charge for the aggregated usage, then the turn is written to episodic memory.
Absolute maximum ratings
Every value below is a constant in the source, not a marketing figure. Each row names the file it is read from, so you can check the claim before you trust it.
| Parameter | Value | ||
|---|---|---|---|
| Tool-call hops per turnMAX_HOPS · options.go | MAX_HOPS | 10 | options.go |
| Tools executed in parallelMAX_PAR · options.go | MAX_PAR | 4 | options.go |
| Tool name patternNAME_RE · tool.go | NAME_RE | [a-zA-Z_][a-zA-Z0-9_]{0,63} | tool.go |
| MCP connect timeout, per servert_MCP · web/brain.go | t_MCP | 10 s | web/brain.go |
| MCP initialize handshaket_INIT · mcp/client.go | t_INIT | 15 s | mcp/client.go |
| Policy reload poll intervalt_POLL · router/yaml | t_POLL | 2 s | router/yaml |
| Memory half-life, workingT½_W · memory/sqlite | T½_W | 24 h | memory/sqlite |
| Memory half-life, episodicT½_E · memory/sqlite | T½_E | 720 h | memory/sqlite |
| Memory half-life, profileT½_P · memory/sqlite | T½_P | none, does not decay | memory/sqlite |
| Default bind addressADDR · web/config.go | ADDR | 127.0.0.1:7844 | web/config.go |
| Minimum Go toolchainGO_MIN · go.mod | GO_MIN | 1.23 | go.mod |
Pin descriptions
Six interfaces, no framework. The root package imports no concrete provider, router, memory store or transport, so you can replace any one of them without forking the others.
- Providerinterface
- A model backend. Name, Models, Privacy, EstimateCost, Call, Stream. One package per provider under providers/.
- Routerinterface
- Chooses provider and model for a call, given the candidates and the remaining budget. router/yaml is the shipping implementation.
- BudgetTrackerinterface
- EstimateCost, Charge, Remaining, Spent. Checked before the request goes out, so an over-budget call never bills.
- Memoryinterface
- Add, Recall, Prune, Close. Deliberately narrow. memory/sqlite adds backfill and auto-prune on the concrete type.
- Embedderinterface
- Name, Dimensions, Embed. Optional. Ollama implements it locally, so semantic recall needs no cloud key.
- Toolinterface
- An LLM-callable function. Registered directly, or surfaced from an MCP server with a prefix.
Typical application
A cloud model and a local one, registered together, with memory and a hard ceiling. The routing policy decides which one answers, and a call marked local_only can never reach the cloud provider even if the policy lists it first.
package main import ( "context" "fmt" "os" "gitlab.com/withvishal/bridge/tool" "gitlab.com/withvishal/bridge/tool/budget" "gitlab.com/withvishal/bridge/tool/memory/sqlite" "gitlab.com/withvishal/bridge/tool/providers/anthropic" "gitlab.com/withvishal/bridge/tool/providers/ollama") func main() { claude, _ := anthropic.New( anthropic.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY"))) local, _ := ollama.New( ollama.WithBaseURL("http://localhost:11434")) // A local file. Nothing in it leaves the machine. store, _ := sqlite.Open("~/.bridge/memory.db") b, _ := bridge.New( bridge.WithProvider(claude), bridge.WithProvider(local), bridge.WithMemory(store), bridge.WithBudget(budget.New(5.00)), // hard ceiling, USD ) defer b.Close() resp, _ := b.Call(context.Background(), bridge.Call{ Task: bridge.TaskReason, Privacy: bridge.PrivacyCloudOK, Prompt: "What did we decide about the billing refactor?", }) fmt.Println(resp.Text) fmt.Printf("%s via %s, $%.5f\n", resp.Model, resp.Provider, resp.CostUSD)}# ~/.bridge/policy.yaml# Re-read on edit. No restart, no redeploy.tasks: reason: privacy: cloud_ok prefer: - anthropic:claude-opus-4-7 - anthropic:claude-sonnet-4-6 fallback: - openai:gpt-5 max_cost_usd: 0.10 # Anything tagged local_only never reaches a # cloud provider, whatever the prefer list says. protect: privacy: local_only prefer: - ollama:llama3.3:70b max_cost_usd: 0.0Dependency budget
Two direct, twelve in total. Read with go version -m ./bridge. Two modules are direct requirements. The other ten arrive underneath the SQLite driver, which is pure Go, which is why the binary needs no C toolchain and cross-compiles from one machine.
Direct
- modernc.org/sqlite
- gopkg.in/yaml.v3
Transitive
- github.com/dustin/go-humanize
- github.com/google/uuid
- github.com/mattn/go-isatty
- github.com/ncruces/go-strftime
- github.com/remyoudompheng/bigfft
- golang.org/x/exp
- golang.org/x/sys
- modernc.org/libc
- modernc.org/mathutil
- modernc.org/memory
Ordering information
Every desktop target from one command. Stripped binary sizes, measured on 1.0.0-dev with Go 1.26.2. No target needs a C compiler, a cross-toolchain or a container to produce.
| GOOS | GOARCH | Stripped size |
|---|---|---|
| darwin | arm64 | 13.0 MB |
| darwin | amd64 | 13.7 MB |
| linux | amd64 | 13.5 MB |
| linux | arm64 | 12.6 MB |
| windows | amd64 | 13.9 MB |
| windows | arm64 | 12.8 MB |
Built with CGO_ENABLED=0 and -ldflags "-s -w".
Run the UI
The web interface is embedded in the binary and binds to localhost. It refuses any other address without an auth token, because your config holds API keys.
bridge init && bridge serve --open