Local proxy & autoconfig
A passive agent monitors nothing: something has to route AI traffic to it.
The agent solves this itself. It runs a local LLM API proxy, and
autoconfig points the machine's AI tooling at it. From the moment it is
installed, the AI traffic it can reach is inspected and logged without anyone
wiring anything by hand.
The proxy
client ──► lumen-agent proxy (127.0.0.1:7646) ──► api.anthropic.com
│
├─ prompt inspected before it leaves the machine
├─ completion inspected before the client sees it
└─ finding recorded for both
- Providers. Anthropic (
/v1/messages) and OpenAI-compatible (/v1/chat/completions,/v1/responses, …) are recognized by path;--upstream name=urlsends a provider somewhere else. - Redact rewrites the request body, so the secret never reaches the provider. Block returns the vendor's own error shape, so the client reports a normal API failure, not a broken connection.
- Streaming relays SSE through the hold-and-release window — only the provably clean prefix is forwarded.
- Provenance-aware. A chat request carries the whole transcript. The
newest user turn is enforced in full; a
tool_resultis judged by response rules (third-party data is indirect injection); earlier turns are logged but never blocked — otherwise one paragraph about prompt injection in the history would wedge the session for good. - Never in the way. Unparseable bodies, unknown paths, provider errors:
forwarded unchanged. Oversized bodies (> 8 MB) are relayed uninspected
with a
capture_skippedfinding — never a 413. - Credentials pass through and are never logged, stored, or written to a finding.
Standalone use, without a service:
lumen-agent proxy # 127.0.0.1:7646
export ANTHROPIC_BASE_URL=http://127.0.0.1:7646
export OPENAI_BASE_URL=http://127.0.0.1:7646/v1
In an install, the daemon serves the proxy whenever the config carries a
proxy: section — one engine, one policy, one findings file.
Autoconfig
lumen-agent autoconfig status # what is here, and what is routed
lumen-agent autoconfig apply # point it at the proxy
lumen-agent autoconfig revert # put everything back
| Target | What is changed |
|---|---|
| Shell profile | One managed block exporting ANTHROPIC_BASE_URL / OPENAI_BASE_URL, guarded by a sub-second health probe |
| Claude Code | env.ANTHROPIC_BASE_URL in its settings file — opt-in (--only claude-code) because a JSON setting cannot fail open |
| Zed | language_models.{anthropic,openai}.api_url — opt-in (--only zed), same reason |
| Claude Code hooks | The guard registered on UserPromptSubmit, PreToolUse, PostToolUse |
| MCP servers | Reported, not rewritten — the wrap command is printed instead |
Because this edits other programs' configuration, four rules hold:
- Every change is backed up next to the original.
- Every change is reversible with
revert, which restores the file. - A target already pointed somewhere else is never hijacked — a
corporate gateway is reported as a conflict and skipped;
--forceis required to override. - Redirection fails open, never closed. A stopped, crashed or
uninstalled agent must never cut the machine off from its AI providers.
applyrefuses to route at a proxy that does not answerGET /lumen/health; the shell block probes before exporting; and the targets that cannot be made conditional are opt-in.
Applying twice changes nothing the second time. autoconfig revert is
always the panic button.
The Claude Code hook collector
The proxy sees the conversation with the model; it cannot see what the agent
then does on the machine. lumen-agent hook covers those moments:
| Event | What it sees | What it can do |
|---|---|---|
UserPromptSubmit | the typed prompt, before the model | Block (the contract offers no rewrite, so Redact blocks and says why) |
PreToolUse | the tool and its arguments, before execution | Deny, or replace the arguments |
PostToolUse | the tool's result, before the model reads it | Block, or rewrite — where indirect injection from a fetched page is neutralized |
The guard is a fresh process per event and never talks to the daemon: it keeps enforcing after the daemon is stopped, crashed, or uninstalled. A guard that breaks the session is worse than no guard, so an unparseable payload or an internal error lets the action proceed and reports on stderr.
autoconfig apply --managed registers the guard in Claude Code's
enterprise policy file — outranks user settings, applies to every user,
needs administrator rights. That is the difference between a convenience and
a control.
What is captured, and what is not
| Surface | Status |
|---|---|
Claude Code, and any tool honouring ANTHROPIC_BASE_URL | Captured, prompt and completion, streaming included |
| What Claude Code does locally (commands, writes, fetched pages) | Captured through the hook collector |
| Scripts, notebooks, CLIs using OpenAI/Anthropic SDKs | Captured through the shell profile export |
| MCP tool calls and results | Captured when wrapped with lumen-agent mcp |
| Browser AI (ChatGPT, Claude.ai) | Not yet — that is the browser extension |
| Closed desktop apps with no base-URL setting | Not capturable this way |
The honest summary: after autoconfig apply, developer AI traffic on the
machine is monitored.