Skip to main content

Janus — Requirements

Status: draft for review · Last updated: 2026-10-11

Requirement IDs are stable and referenced from issues. Priority uses MoSCoW for the 1.0 release: Must, Should, Could. The milestone column points at the roadmap.

Functional requirements​

FR-1 Transparent proxy​

IDRequirementPriMS
FR-1.1Accept the Anthropic Messages API on a local port: POST /v1/messages (streaming and non-streaming) and POST /v1/messages/count_tokens. Any other path is forwarded upstream untouched.MM1
FR-1.2With all features disabled, the upstream request and the client response are byte-equivalent to a direct connection, apart from hop-by-hop headers and one named exception: on Messages requests Janus narrows Accept-Encoding to gzip (or to none, if the client did not offer gzip), so that every response can be read for the ledger. The client only ever receives an encoding it asked for.MM1
FR-1.3Client credentials (API key or OAuth bearer) pass through unchanged. Janus never stores, logs, or substitutes them.MM1
FR-1.4Streaming responses are relayed as they arrive. Buffering happens only where a feature explicitly needs it (FR-5.1).MM1
FR-1.5Unknown request fields, beta headers, and content block types are preserved, not dropped.MM1

FR-2 Observability and learning​

IDRequirementPriMS
FR-2.1Per-request capture (readable Markdown plus raw request and response), switchable, with secrets redacted in the readable copy.MM1
FR-2.2A decision record for every request: request class, route taken, the rule or reason, stages applied, backend, latency, token usage split by uncached input / cache write / cache read / output.MM1
FR-2.3An append-only ledger of decision records, and a janus stats command reporting cache-weighted cost, cost by request class, and estimated savings against the baseline.MM1
FR-2.4Shadow mode: serve the upstream answer, also run the request locally, record both for comparison. Never affects what the client receives.SM2
FR-2.5Replay: re-run captured requests against a chosen backend or model offline and report differences.SM2
FR-2.6janus audit: show exactly what left the machine for a given request or session.SM6

FR-3 Local backend (LM Studio)​

IDRequirementPriMS
FR-3.1Health check, model discovery, and loaded-model detection against LM Studio.MM2
FR-3.2Send Messages-shaped requests to LM Studio: natively where LM Studio offers an Anthropic-compatible endpoint, otherwise by translating to and from OpenAI chat completions, including tool calls and streaming.MM2
FR-3.3Configurable mapping from requested model names to local models, with per-model context limit and timeout.MM2
FR-3.4Requests that exceed the local model's context window are never sent to it.MM2
FR-3.5The LM Studio base URL is a config setting, overridable by flag and environment, and is never hard-coded. The default is http://studio.local:1234, not localhost, so that Janus always talks to the intended LM Studio instance whichever machine it runs on.MM1

FR-4 Classification and routing​

IDRequirementPriMS
FR-4.1Classify each request from deterministic signals (requested model, tools present, size, system prompt fingerprint, endpoint) into a named class. Unrecognised requests are class unknown and pass through.MM2
FR-4.2A rule-based policy maps class and attributes to a route: upstream, local, or local-then-escalate. Rules live in config.MM2
FR-4.3Model-alias routing: a request for a configured alias (for example janus-local) always goes local, so Claude Code's small/fast model and subagents can be pinned to the local model from its own settings.MM2
FR-4.4Conversation integrity: Janus does not change backend inside a conversation where doing so would produce a history the upstream API rejects.MM3

FR-5 Triage and escalation​

IDRequirementPriMS
FR-5.1For local-then-escalate routes, hold the local response until it passes validation; on failure, send the original request upstream. The client sees one clean response.MM3
FR-5.2Validators: well-formed response, tool calls match the declared schema, not empty, not truncated, no refusal or confusion patterns. Each is individually switchable.MM3
FR-5.3Optional local-model triage for requests the rules can't place, under a configurable latency budget; over budget means upstream.SM3
FR-5.4An explicit override to force a request or session upstream or local.SM3
FR-5.5Escalation rate per class is recorded; a class that escalates above a threshold is routed upstream directly.CM3

FR-6 Delegation​

IDRequirementPriMS
FR-6.1janus mcp: an MCP server exposing worker tools backed by the local model.MM4
FR-6.2Worker tools for: answering a question about one or more files, searching a tree and summarizing the findings, and drafting or transforming text and code to a spec.MM4
FR-6.3Worker results are compact and bounded in size; the bulk input stays local.MM4
FR-6.4Delegated work appears in the ledger with an estimate of upstream tokens avoided.SM4
FR-6.5Ships guidance (CLAUDE.md snippet, subagent definitions) that makes Claude reach for the workers.SM4

FR-7 Context economy​

IDRequirementPriMS
FR-7.1A transform pipeline applied to upstream-bound requests. Every transform is deterministic and memoized: the same input block always yields the same output bytes for the life of a conversation.MM5
FR-7.2A net-savings guard estimates each transform's cache-weighted effect and skips it when the effect is not positive.MM5
FR-7.3Tool-result digestion: oversized tool results are replaced by a local-model digest; the original stays retrievable.SM5
FR-7.4Stale-context pruning: superseded content (for example repeated reads of the same file) is collapsed without a model.CM5
FR-7.5Conversation compaction requests can be served by the local model.CM5

FR-8 Privacy​

IDRequirementPriMS
FR-8.1Detect secrets (key formats, high-entropy strings, configured patterns) in upstream-bound requests.MM6
FR-8.2Replace detected secrets with stable placeholders and restore them in the response, including inside streamed tool-call arguments. An unresolvable placeholder blocks the turn.MM6
FR-8.3Local-only policy: content matching configured path globs or markers is never sent upstream. The request is served locally or refused. Fails closed.MM6
FR-8.4Capture and ledger files are created owner-readable only, with configurable retention.MM1
FR-8.5Listen on loopback by default; binding elsewhere needs an explicit setting.MM1

FR-9 Resilience​

IDRequirementPriMS
FR-9.1On upstream failure (network error, 429, 5xx, overloaded), fall back to the local model where policy allows, and mark the response as degraded.MM3
FR-9.2On local failure or timeout, fall back to upstream pass-through, except for local-only content.MM3
FR-9.3Circuit breakers and health checks per backend so a dead backend costs one timeout, not one per request.SM3

FR-10 Configuration and operation​

IDRequirementPriMS
FR-10.1One config file, overridable by flags and environment; validated at startup with actionable errors.MM1
FR-10.2Single static binary for macOS, Linux, and Windows.MM7
FR-10.3janus doctor: checks upstream reachability, LM Studio, loaded models, and prints the exact environment needed to point Claude Code at Janus.SM1
FR-10.4Every feature has an off switch, and off is the default until the feature has shown a net benefit.Mall

Non-functional requirements​

IDRequirement
NFR-1No worse than direct. Pass-through overhead p50 under 10 ms and no added time-to-first-byte beyond that.
NFR-2Precedence. Where requirements conflict: privacy, then correctness, then availability, then savings.
NFR-3Dependencies. Standard library first. Each third-party dependency is justified in an ADR.
NFR-4Testability. Both backends are faked with httptest; the suite runs offline. Golden fixtures cover streaming, tool use, and thinking.
NFR-5Compatibility. Tested against current Claude Code and LM Studio releases; fixture suite refreshed when either changes its wire behaviour.
NFR-6Explainability. No request is altered or rerouted without a decision record that says why.
NFR-7Safe defaults. A fresh install is a pass-through proxy with logging; nothing reroutes or rewrites until configured.

Constraints and assumptions​

  • Claude Code is the only client designed for. It is configured through ANTHROPIC_BASE_URL and its model-selection environment variables.
  • LM Studio is running at the configured base URL (FR-3.5) with at least one model loaded and its server enabled. Reaching it by hostname rather than loopback requires LM Studio to serve on the local network.
  • Local model capability is the limiting factor for G1 and is established empirically (roadmap M0), not assumed.