ADR-0055: Neutron N2 first model adapter
Status
Accepted as the N2 adapter decision. Implementation is a later pull request after N1 contracts land. This ADR does not authorize Desktop model calls, hosted-provider credentials, a new package, or mutation.
Context
Neutron Runtime N1 defines versioned, root-bound, offline contract snapshots (@intentloom/protocol/neutron-runtime). ADR-0054 already defined the provider-neutral ModelAdapter boundary and the offline DeterministicTestModelAdapter. That adapter is a fixture. It does not satisfy the N2 exit gate.
NEUTRON_RUNTIME_ROADMAP.md N2 requires one real provider, end to end, for one read-only loop:
client
→ Neutron session
→ model request
→ typed tool request
→ Intentloom application operation
→ structured tool result
→ model responseThe first adapter needs an explicit decision for credentials, network disclosure, streaming, cancellation, retention, errors, limits, and tests. Local-first and fail-closed defaults apply. Hosted vendors can wait.
Decision
Provider
The first real N2 adapter is Ollama, reached only at a caller-supplied local base URL (default http://127.0.0.1:11434). No second hosted adapter ships in the N2 increment.
Reasons:
- the user already runs the process; Intentloom does not download a model;
- no cloud account or API token is required for the default local daemon;
- network is explicit localhost egress, not a hidden hosted call;
- the same
ModelAdapterand N1 envelopes stay provider-neutral.
deterministic-test remains the CI fixture. It does not count as N2 completion.
Package and consumer boundary
Reuse @intentloom/application/model-adapter and @intentloom/protocol/neutron-runtime. Do not add packages/neutron-runtime. Do not grow oversized root barrels; keep subpath exports.
N2 consumers are application + focused tests, then an optional CLI inspect helper if a real caller exists in the same increment. Desktop, TUI, MCP, and daemon RPC must not call models in N2. Desktop model UI stays N6.
Credentials
- Default Ollama local daemon: no credential.
- If a later optional token appears, resolve it only from an explicit invocation argument or a documented process environment variable. Never from project metadata,
.aif/, git, or Desktop settings files. - Do not persist tokens. Treat empty/cleared input as locally revoked.
- N2 does not add a secrets store.
Network disclosure
networkModeisexplicit-egressonly when the caller configures a base URL. Unconfigured staysoffline/unconfiguredand fails closed.- Disclose scheme, host, and port. Do not send the repository, env files, or credentials in the disclosure record.
- Refuse non-loopback hosts in N2 unless a later ADR expands the allowlist.
- No telemetry, no implicit DNS to vendor APIs, no model pull.
Streaming
- Streaming is optional and must use the existing cancellable turn boundary.
- N2 may buffer a complete turn for the first inspect/discuss loop.
- Partial tokens are not approval, evidence, or tool results.
Cancellation, timeouts, and limits
- Honor
AbortSignal. A cancelled turn emits N1cancelledand writes nothing. - Enforce caller timeout and adapter capability
maxOutputTokens. - Bound request body, response body, tool-argument JSON, and context tokens using N1
NeutronUsageBudget. Exceeding a limit isbudget-exceeded. - One in-flight turn per session in N2. No background retry storm.
Data retention
- Prompts, completions, and tool payloads are ephemeral process memory.
- Do not write model transcripts into the project tree.
- Existing Neutron subagent JSON records stay the only on-disk Neutron artifacts, and N2 must not put raw model text there unless a later retention ADR says so.
dataHandlingfor Ollama N2 isephemeral.
Tools and mutation
N2 may invoke only N1 read-only tools (inspect, doctor, memorySearch, timeline, conformance, securityAudit, projectDiff) through existing application operations. Generic shell, arbitrary filesystem, apply, sync write, and Git mutation stay forbidden. Model output cannot approve a plan.
Errors
Normalize provider/transport failures to N1 NeutronErrorCode:
- unreachable daemon →
adapter-unconfiguredortimeout; - refused host →
network-forbidden; - invalid tool →
unsupported-tool; - schema failure →
validation-failed.
Do not leak raw HTTP bodies that may contain secrets.
Test strategy
- Contract tests keep using
deterministic-testand frozen fixtures. - Ollama adapter unit tests use a local fake HTTP listener or recorded fixtures. CI must not require a live Ollama process or a pulled model.
- One optional maintainer-manual live path may be documented; it is not a merge gate.
- Prove the inspect/discuss loop leaves project bytes unchanged.
Consequences
- N2 has one authorized real adapter and a written threat boundary.
- Hosted OpenAI/Anthropic/Gemini adapters remain out of scope until their own ADR.
- Desktop still does not call models.
- Users who do not run Ollama keep the offline/unconfigured path.
Follow-up
- Implement the Ollama adapter and the read-only discuss/inspect loop in a dedicated PR after N1 merges. Done on
feat/neutron-n2-ollama-adapter. - Keep N3 context assembly and N4 tool routing on their roadmap gates.
- Do not start N6 Desktop Neutron Workspace from this ADR.