Features
- One API across fourteen providers, streaming and tool use included
- Saved agents: a prompt, a model, and an allowlist over your tools
- Workflows that run those agents as a graph, in parallel where it can
- Agent Skills loaded on demand, so a hundred skills cost a hundred lines
- 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
- Repeatable multi-step jobs: research then draft then critique
- 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.
bridge init && bridge serve --openFunctional 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 a claim here can be held against the code by anyone who has 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 |
| Agent delegation depthMAX_DEPTH · web/delegation.go | MAX_DEPTH | 2 | web/delegation.go |
| Workflow steps in parallel, per levelWF_PAR · workflow/runner.go | WF_PAR | 4 | workflow/runner.go |
| Skill catalogue line lengthBRIEF_CAP · skills/skills.go | BRIEF_CAP | 200 chars | skills/skills.go |
| Skill file read capFILE_CAP · skills/skills.go | FILE_CAP | 256 KiB | skills/skills.go |
| Minimum Go toolchainGO_MIN · go.mod | GO_MIN | 1.23 | go.mod |
Pin descriptions
Eight interfaces, no framework. The root package imports no concrete provider, router, memory store or transport, and the agent and workflow packages import neither each other nor the web server, 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.
- agent.Storeinterface
- List, Get, Save, Delete. Saved agents are one YAML file each, so a team can review them in a pull request.
- workflow.Executorinterface
- RunAgent and RunPrompt. The workflow engine knows nothing about the Brain; the caller supplies this, which is why its whole test suite runs without a socket.
Typical application
Three providers registered together, with memory and a hard ceiling, then a saved agent run against them. The agent pins no model, so the policy on the right decides which one answers, and a call marked local_only can never reach a hosted provider even if the policy lists one first.
package main import ( "context" "fmt" "os" "gitlab.com/withvishal/bridge/tool" "gitlab.com/withvishal/bridge/tool/agent" "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/compat" "gitlab.com/withvishal/bridge/tool/providers/ollama") func main() { claude, _ := anthropic.New( anthropic.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY"))) // Ten more vendors arrive as presets over one adapter. groq, _ := compat.NewPreset("groq", compat.WithAPIKey(os.Getenv("GROQ_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(groq), bridge.WithProvider(local), bridge.WithMemory(store), bridge.WithBudget(budget.New( budget.WithCeiling(5.00))), // hard ceiling, USD ) defer b.Close() // Saved agents are YAML files. This one pins no model, // so the policy beside this listing routes it. agents, _ := agent.NewFileStore("~/.bridge/agents") researcher, _ := agents.Get("researcher") resp, _ := agent.NewRunner(b).Call(context.Background(), researcher, "What did we decide about billing?", nil) 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.1.1-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.7 MB |
| darwin | amd64 | 14.5 MB |
| linux | amd64 | 14.3 MB |
| linux | arm64 | 13.4 MB |
| windows | amd64 | 14.7 MB |
| windows | arm64 | 13.5 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