docs/agent-networks/01-end-to-end-flows.md
Three cross-module mermaid diagrams. Each per-module guide repeats the slice that's relevant to its own scope — these are the canonical top-down views.
How an operator's change to a Provider, Policy, Guardrail, Budget Rule, or Settings record ends up as live middleware on a peer's proxy.
sequenceDiagram
autonumber
actor Op as Operator
participant UI as Dashboard
participant HTTP as management/handlers
participant Mgr as agentnetwork.Manager
participant Store as management/store (SQL)
participant Ctl as network_map.Controller
participant Synth as agentnetwork.SynthesizeServices
participant Grpc as management gRPC
participant Proxy as netbird-proxy
participant Xlate as middleware_translate
participant Chain as middleware.Chain
Op->>UI: edit provider/policy/budget/settings
UI->>HTTP: REST PUT/POST /api/agent-network/*
HTTP->>Mgr: SaveProvider / SavePolicy / SaveBudgetRule / SaveSettings
Mgr->>Store: persist (gorm)
Mgr-->>Ctl: account change event (Network-Map dirty)
loop per connected peer
Ctl->>Synth: SynthesizeServices(ctx, store, accountID)
Synth->>Store: load providers, policies, guardrails, budget rules, settings
Synth-->>Synth: build per-peer Service list
Note over Synth: each Service has a middleware
chain with capture_prompt /
capture_completion / redact_pii
baked from account settings
Synth-->>Ctl: []rpservice.Service
Ctl->>Grpc: NetworkMap push (services + middleware configs)
end
Grpc-->>Proxy: NetworkMap stream
Proxy->>Xlate: translate proto MiddlewareConfig → runtime Spec
Xlate->>Chain: register / replace per-service chain
Note over Chain: chain replacement is live
(no proxy restart, in-flight
requests unaffected)
Notes on the diagram
network_map.Controller synthesises on every push, not on a
timer. A single config change costs O(connected peers × policies ×
providers) per push. See modules/22-management-handlers-wiring.md.SynthesizeServices is the single source of truth for the wire
format the proxy executes. Anything the proxy does that the
synthesiser didn't request is a bug. See
modules/21-management-agentnetwork.md.llm_limit_check ⇒ unbounded spend). See
modules/33-proxy-runtime.md.What happens when an agent on the client peer sends a chat-completion / messages request through the synthesised reverse-proxy.
sequenceDiagram
autonumber
actor Agent as Agent (local)
participant Px as netbird-proxy
participant Auth as auth middleware
participant Map as service-mapping
participant Req as llm_request_parser
participant Rt as llm_router
participant Chk as llm_limit_check
participant Inj as llm_identity_inject
participant Grd as llm_guardrail
participant Up as upstream LLM
participant Resp as llm_response_parser
participant Cost as cost_meter
participant Rec as llm_limit_record
participant Log as access-log
participant MgmtGrpc as management gRPC
Agent->>Px: POST /v1/chat/completions (OpenAI / Anthropic)
Px->>Auth: identify peer (user, groups)
Auth->>Map: resolve service from Host + path
Map-->>Req: dispatch chain in slot order
Req->>Req: parse body → provider, model, prompt, token estimate
Note over Req: capture_prompt gates raw_prompt
capture (nil = legacy emit,
false = drop, true = emit)
Req->>Rt: pass metadata
Rt->>Chk: route to upstream candidate
Chk->>MgmtGrpc: CheckLLMPolicyLimits(provider, model, est_tokens, groups, user)
MgmtGrpc-->>Chk: decision = allow / deny + deny_code
alt decision == deny
Chk-->>Log: emit access-log with deny_code
(if EnableLogCollection)
Chk-->>Agent: 429 (or 403 per deny_code)
else decision == allow
Chk->>Inj: continue
Inj->>Inj: inject NetBird identity headers per provider config
Inj->>Grd: continue
Grd->>Grd: enforce model allowlist
Grd->>Up: forward (over WireGuard)
Up-->>Resp: response (JSON or SSE stream)
Resp->>Resp: parse usage tokens, completion
Note over Resp: capture_completion gates raw
completion capture
Resp->>Cost: tokens
Cost->>Cost: lookup pricing.yaml + compute cost
Cost->>Rec: tokens + cost
Rec->>MgmtGrpc: RecordLLMUsage(provider, model, prompt_t, completion_t, cost, groups, user)
Rec-->>Log: emit access-log entry
(if EnableLogCollection)
Log-->>Agent: 200 + body (streamed if SSE)
end
Notes on the diagram
llm_limit_check must precede llm_router so
a denied request never hits upstream, and llm_limit_record must
pair with llm_limit_check so a successful check is always recorded
(or the rate-limit semantics break). See
modules/31-proxy-middleware-builtin.md.llm_guardrail is also where PII redaction happens
(redact_pii = settings.RedactPii). Phones, emails, credit cards,
PII names — see redact.go for the full set. See
modules/31-proxy-middleware-builtin.md.modules/32-proxy-llm-parsers.md.settings.EnableLogCollection. With
it OFF, neither the deny nor the allow leg writes an entry — the
chain still runs (budget rules are still enforced) but no audit trail
is kept. See
modules/33-proxy-runtime.md.How an account's budget rules tighten ceilings on every request and how consumption flows back into the dashboard.
flowchart LR
subgraph Operator
DashBud[Dashboard Budget Settings tab]
end
subgraph Mgmt[Management]
Save[POST/PUT /api/agent-network/budget-rules]
Store[(SQL store)]
Synth[SynthesizeServices]
Check[CheckLLMPolicyLimits RPC]
Rec[RecordLLMUsage RPC]
Cons[/api/agent-network/consumption]
end
subgraph Proxy[Proxy]
Chk[llm_limit_check]
RecMw[llm_limit_record]
end
subgraph DashView[Dashboard Budget Dashboard tab]
Panel[AgentConsumptionPanel]
end
DashBud -->|create / update rules| Save
Save --> Store
Store --> Synth
Synth -->|push synth-services to peer| Proxy
Chk -->|per request| Check
Check -->|aggregate matching rules
min-wins all-must-pass| Store
Check -->|allow / deny| Chk
RecMw -->|post-response| Rec
Rec -->|tokens + cost + groups + user| Store
Store -->|read counters| Cons
Cons --> Panel
Notes on the diagram
modules/21-management-agentnetwork.md.CheckLLMPolicyLimits and reports back via
RecordLLMUsage. This keeps account-wide accounting in one place
and avoids per-proxy drift.RecordLLMUsage must carry group_ids and user_id so the
decrement hits the right rule(s). The wire that carries those
fields onto the response leg is respInput in reverseproxy.go. See
modules/33-proxy-runtime.md./api/agent-network/consumption — not gRPC, not WebSocket. Poll
interval lives in AgentConsumptionPanel.tsx. See
modules/40-dashboard.md.modules/00-overview.md