Files
stack/docs/plans/2026-10-12_local-model-proxy.md
T

4.5 KiB

Status: written by Sage, lead. It follows docs/plans/BRIEF-TEMPLATE.md. It answers Vikunja P19 #237. Jason confirmed it through Mos as "Q127: yes" (sage-0110). Role sessions talk only to a local proxy, CLIProxyAPI first, with keys the stack issues and rotates. The upstream tokens and keys stay in the proxy, which is set once for the whole machine, and nobody hand-edits a credential file. Decision 114's hold on session traffic through CLIProxyAPI is lifted for #237 (lead decision 120). This row is the test that comes before any design: it runs after rows 92 and 93, the redeploy and Jason's re-test.

A local model proxy for role sessions (2026-10-12)

Stand-in-key test of CLIProxyAPI for role sessions

Problem

Every role session logs in with the token in ~/.config/mosaic-dev/secrets/claude-session.env, which Jason made by hand (decision 119). He wants credentials set by the stack, not by him. The session allowlist already passes ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY (packages/seat/src/session.mjs:62-64), so a Claude Code session can point at a gateway without a code change. Pi sessions can't, because no OpenAI base-URL variable passes. CLIProxyAPI listens on 127.0.0.1:8317 (~/.local/opt/EasyCLIProxyAPI/cpa-core/cli-proxy-api, running since 2026-10-06). Nobody has checked whether Claude Code or pi works through it. Nobody has checked whether it can issue a key per agent without its WebUI either.

Owner and reviewer

  • Owner: Researcher.
  • Reviewer: Dewey. Sage reruns every script at the gate.

Files owned

  • agents/researcher/work/i1-proxy-test/: scripts, a stand-in upstream, logs, REPORT.md and a manifest. Nothing outside it.

What ships

All of this runs against a second CLIProxyAPI process that the test starts from the same binary. It gets its own made-up config, port, data directory and management key under the packet directory. The running proxy on 8317, its config and its data aren't touched, read or called. The upstream is a stand-in HTTP server in the packet. It records every request and answers like the Anthropic Messages API, including streamed answers and tool calls. The stand-in proxy is configured to use it as its Claude upstream. No real token or key exists anywhere in the test, and no request leaves the machine.

  • The proxy's version, and the config fields and management endpoints the test uses, each cited to its own docs or --help output.
  • Claude Code (the pinned binary, MOSAIC_CLAUDE_BIN) and pi (the pinned version) each run one non-interactive turn through the stand-in proxy, using only the session's allowlisted variables. If pi can't, the report names the variable or adapter change it needs. For each, the stand-in upstream's log shows:
    • a streamed answer arriving intact;
    • a tool call and its result making the round trip;
    • cache_control blocks and the anthropic-beta and anthropic-version headers as the client sent them, or exactly what the proxy dropped or changed;
    • which client key the proxy saw, and that the upstream saw only the proxy's own made-up upstream key.
  • Per-agent keys from the command line: the test creates two client keys through the stand-in proxy's management API or CLI, with no WebUI. A session with key A works. Revoking A refuses A's next request and leaves B working. Each request's key shows up in the proxy's usage or logs. The report says how many steps that takes and whether a restart is needed.
  • The proxy's behavior with an unknown key, a missing key, and an upstream that is down. The report gives the error each client prints.
  • A cleanup script that stops the stand-in processes and leaves no process, port or file outside the packet. The report says how to run everything again.
  • REPORT.md lists what holds, what doesn't, and what the #237 design row has to settle. That includes where the issued keys live, how the bus hands one to a session, and rotation.

Out of scope

Any change to the running proxy, its config or its keys. That goes back to Mos (sage-0110). Reading its management key: no agent does that, ever. Real credentials or spend. Switching a live seat to the proxy, and the subscription-terms question: both go to Jason after this test. The #237 design and build rows. Containerized sessions (I1).

Gate

Dewey approves on the row's issue, naming the packet manifest. Sage reruns every script from the packet and checks that the running proxy's process, port and config modification time are unchanged and that nothing the test created is left behind.