Architecture
Layer8 Proxy is a credential broker with a hardened egress path. This page
covers the broker/ACL/egress model and the kind taxonomy that discriminates
what agents can see and what they can reach.
The broker / ACL / egress model
┌────────────┐ ┌────────────┐ ┌──────────┐
agent ──HTTPS─▶│ locksmith │──CONNECT─▶│ pipelock │──HTTPS──▶│ upstream │
bearer/mtls │ (broker) │ proxied │ (egress) │ │ provider │
└─────┬──────┘ └────────────┘ └──────────┘
│
│ infra call
▼
┌────────────┐
│ lf-scan │ (operator-only middleware)
└────────────┘
- Broker (locksmith). Terminates the agent connection, authenticates the per-agent bearer (or mTLS cert), checks the ACL, resolves the target registration, strips agent-sent auth headers, and injects the real upstream credential. One audit row per request.
- ACL. Each agent has a flat allowlist (or denylist) of registration
names. The allowlist references names directly; locksmith resolves the
kindat request time. A call to a name outside the allowlist returns403 tool_not_allowedand an audit row. - Egress. Registrations marked
egress: proxiedroute through pipelock via HTTP CONNECT; pipelock enforces a network-layer allowlist + blocklist + DLP.egress: directregistrations (typically LAN-local models) bypass the CONNECT proxy.
The kind taxonomy (ADR-0004)
Pre-Phase-E, every registration was a homogeneous "tool" with one discovery
endpoint (/tools) and one admin family. Three forces drove a split:
- Agent reasoning differs by type. An LLM provider is token-priced, prompt-shaped, and rate-limit-sensitive; a web-search tool is response-shaped and latency-sensitive. Mixing them conflated two mental models during agent-side selection.
- Operator reasoning differs for infra middleware.
lf-scanis called by locksmith itself, never by an agent. Stuffing it into/toolsmeant operators had to ACL-deny it from every agent — inverting the trust default. - Authless tools needed a distinct shape. DuckDuckGo, Wikipedia, and
similar public endpoints have no credential to inject. Absence of an
auth:block used to mean both "no injection" and "operator forgot the key" — two indistinguishable cases.
The decision: a kind discriminator with three locked values.
model— LLM, embedding, reranker, audio, image, multimodal. Agents discover viaGET /models(ACL-filtered, kind=model only).tool— anything that is not a model: web search, code repos, document fetch, sandboxes, KV stores. Agents discover viaGET /tools(ACL-filtered, kind=tool only).infra— operator-only middleware that locksmith itself calls (today:lf-scan). Not discoverable by agents — there is noGET /infraendpoint.
Names live in a single global namespace; a name belongs to exactly one kind.
Cross-kind reuse is rejected at register-time with 409 / name_in_use.
Authless registrations use an explicit auth: none. Implicit absence of an
auth: block on kind=tool / kind=model is rejected at register-time with
400 / auth_required — closing the "forgot-the-API-key" footgun while
preserving operator intent for deliberately public endpoints.
Where state lives
Per-host proxy-operator state lives in a site repo:
site.cfg— site identity + pinned Layer8 Proxy version..env— provider keys,LF_SCAN_INTERNAL_TOKEN, backup creds (gitignored).pipelock/pipelock.yaml— allowlist + blocklist + DLP policy.locksmith/base.yaml— locksmith base config (listen, egress_proxy, audit).locksmith/secrets/— sealed-cred files (systemd-creds on Linux; openssl-AES fallback on macOS dev). Plaintext is never committed.agents.yaml— per-agent ACL manifest; each entry maps to alocksmith agent register --name X --allowlist ...call.
The seed catalog (baked into the locksmith image) supplies 16 default
registrations (anthropic, openai, openrouter, ai-gateway, ollama, lmstudio,
tavily, github, duckduckgo, wikipedia, lf-scan + 5 OAuth providers). The site
tools/ directory holds only site-local overrides for registrations not in the
seed catalog.
See also
- Agent Locksmith architecture — the daemon's internal request flow (header strip, credential inject, egress, audit).
- Operator Console — the web console over the admin API.
- Deploy — bring up the bundle.