@octocodeai/freellama-mcp-server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,55 @@
1
+ # ADR: Resource-aware backend routing
2
+
3
+ Status: Accepted and implemented
4
+
5
+ ## Context
6
+
7
+ FreeLlama can isolate explicitly assigned helper models in a second Ollama process. Live trials
8
+ proved that CPU and GPU requests can overlap, but exact operator assignment alone was too rigid for
9
+ agents, and one global admission pool can let GPU work starve a CPU helper. Unconstrained
10
+ automatic migration is unsafe because capability, quality, session, and memory constraints
11
+ must continue to win.
12
+
13
+ ## Decision
14
+
15
+ Keep backend eligibility operator-owned and add three bounded controls:
16
+
17
+ 1. Callers may send `auto`, `prefer_cpu`, or `prefer_gpu`; this is a fallback-capable hint.
18
+ 2. GPU and CPU backends own independent weighted admission pools and transition locks.
19
+ 3. `auto` can use task-specific normalized warm latency after three samples exist on both backends
20
+ and one backend has more than a 10% advantage.
21
+
22
+ Explicit models and session affinity override the hint. Quality routing never follows latency.
23
+ Generation normalizes by output tokens; embeddings normalize by input tokens. Cold-load duration
24
+ does not enter feedback. Raw Ollama passthrough remains byte-transparent to the primary upstream.
25
+ Verified feedback is stored in a bounded, versioned snapshot and replaced atomically. A corrupt or
26
+ unsupported snapshot fails startup instead of silently changing learned routing behavior.
27
+
28
+ The contract is hardware-neutral: the operator supplies loopback endpoints and exact CPU-eligible
29
+ tags, while FreeLlama discovers host capacity and observes Ollama placement. The measured 48 GB Mac
30
+ result is validation evidence, not a routing constant. Device-visibility variables remain
31
+ Ollama-process configuration because NVIDIA, ROCm, Vulkan, Metal, and CPU-only hosts differ.
32
+
33
+ ## Alternatives
34
+
35
+ | Alternative | Decision | Reason |
36
+ |---|---|---|
37
+ | Exact assignment only | Rejected | Safe but too rigid for agents and blind to runtime capacity |
38
+ | Let agents supply an upstream or `num_gpu` | Rejected | Bypasses operator eligibility and compatibility boundaries |
39
+ | Rewrite every raw Ollama request | Rejected | Breaks passthrough semantics and surprises existing clients |
40
+ | Persist every raw runtime event | Rejected | Unbounded traces add privacy and storage risk; persist only aggregate prompt-free feedback |
41
+ | Live memory/thermal controller | Deferred | No stable sensor and held-out workload yet justify it |
42
+
43
+ ## Verification contract
44
+
45
+ - Preview returns placement, upstream, preference satisfaction, reason, and admission capacity.
46
+ - Two samples per backend do not change `auto`; the third makes the comparison decision-ready.
47
+ - Explicit model and session pins do not move.
48
+ - A one-unit GPU pool and one-unit CPU pool admit one task on each concurrently.
49
+ - CPU-managed requests contain `options.num_gpu: 0`; raw `/api/*` bodies are unchanged.
50
+ - Health exposes both pools and per-task feedback counts.
51
+ - Restart reloads the same bounded feedback counts; an unsupported schema refuses startup.
52
+
53
+ Rollback is configuration-only for callers: omit the preference or use `auto`. Operators can remove
54
+ the CPU backend to restore a single-primary layout. Reverting independent pools requires a code
55
+ rollback and is not recommended because it reintroduces cross-backend starvation.
@@ -0,0 +1,416 @@
1
+ # FreeLlama architecture
2
+
3
+ FreeLlama is a localhost control plane in front of Ollama. Ollama owns model storage, model loading,
4
+ scheduling, inference engines, and token generation. FreeLlama owns model-aware policy around those
5
+ operations.
6
+
7
+ ## Responsibility boundary
8
+
9
+ The following table defines the ownership boundary:
10
+
11
+ | Responsibility | Owner |
12
+ |---|---|
13
+ | Model files, runners, Metal, MLX, llama.cpp, and token generation | Ollama |
14
+ | Native `/api/*` and OpenAI-compatible `/v1/*` semantics | Ollama |
15
+ | Installed-model discovery and capability normalization | FreeLlama |
16
+ | Task routing, advertised-context compatibility, K/V lower-bound preflight, evidence policy, and model rejection reasons | FreeLlama |
17
+ | Managed admission, session affinity, and model-transition coordination | FreeLlama |
18
+ | Explicit per-model CPU/GPU backend assignment | FreeLlama and separate Ollama processes |
19
+ | Grounded research adapters, citations, and verification verdicts | FreeLlama MCP server |
20
+
21
+ FreeLlama remains a sidecar rather than an Ollama fork. For the compatibility rationale, see the
22
+ [Ollama sidecar boundary](OLLAMA_SIDECAR.md).
23
+
24
+ ## System topology
25
+
26
+ Every public surface uses the Rust core or calls a narrow local dependency:
27
+
28
+ ```mermaid
29
+ flowchart TB
30
+ subgraph clients["Clients"]
31
+ CLI["freellama CLI"]
32
+ MCP["MCP client"]
33
+ RUST["Embedded Rust application"]
34
+ RAW["Ollama-compatible client"]
35
+ end
36
+
37
+ subgraph freellama["FreeLlama"]
38
+ CORE["freellama-core"]
39
+ API["Control API<br/>/_freellama/v1/*"]
40
+ PX["Compatibility proxy"]
41
+ ADAPTER["Research adapter process"]
42
+ end
43
+
44
+ GPU["Primary Ollama<br/>GPU-capable"]
45
+ CPU["Optional Ollama<br/>CPU-assigned models"]
46
+ FILES["Allowlisted workspace files"]
47
+
48
+ CLI --> CORE
49
+ MCP --> CORE
50
+ RUST --> CORE
51
+ CORE --> API
52
+ RAW --> PX
53
+ API --> GPU
54
+ API --> CPU
55
+ PX --> GPU
56
+ MCP --> ADAPTER
57
+ ADAPTER --> FILES
58
+ ADAPTER --> GPU
59
+ ```
60
+
61
+ The CLI and MCP server do not reimplement routing. The CLI calls the core directly. The MCP server
62
+ uses the feature-gated NAPI boundary for native operations and the control API for serve-backed
63
+ operations.
64
+
65
+ ## Request classification
66
+
67
+ The listener classifies requests by path before any model-aware work occurs:
68
+
69
+ ```mermaid
70
+ flowchart TD
71
+ IN["Request to FreeLlama"] --> P{"Path starts with<br/>/_freellama/v1/?"}
72
+ P -->|"No"| RAW["Stream through compatibility proxy"]
73
+ RAW --> PRIMARY["Primary Ollama"]
74
+ P -->|"Yes"| C{"Control endpoint"}
75
+ C -->|"health, machine, models"| READ["Read local and Ollama state"]
76
+ C -->|"recommendations, routes"| DECIDE["Decide without inference"]
77
+ C -->|"natural-routes"| INTENT["Run intent model, then route"]
78
+ C -->|"tasks"| RUN["Route, admit, and execute"]
79
+ C -->|"sessions"| SESSION["Create in-memory affinity id"]
80
+ ```
81
+
82
+ The control API exposes these endpoints:
83
+
84
+ | Method and path | Purpose | Inference |
85
+ |---|---|---|
86
+ | `GET /_freellama/v1/health` | Health, admission capacity, and configured backends | No |
87
+ | `GET /_freellama/v1/machine` | Machine profile | No |
88
+ | `GET /_freellama/v1/models` | Normalized installed catalog, evidence, residency, and execution backend | No |
89
+ | `POST /_freellama/v1/recommendations` | Installed route or reviewed installation plan | No |
90
+ | `POST /_freellama/v1/routes` | Deterministic route decision | No |
91
+ | `POST /_freellama/v1/natural-routes` | Schema-bound intent interpretation followed by deterministic routing | Intent model only |
92
+ | `POST /_freellama/v1/sessions` | New model-affinity session | No |
93
+ | `DELETE /_freellama/v1/sessions/:session_id` | Release model-affinity session | No |
94
+ | `POST /_freellama/v1/tasks` | Managed chat, vision, tools, or embedding task | Yes |
95
+
96
+ The machine profile is host-derived rather than model-name-derived. It reports total physical
97
+ memory on macOS (`sysctl`), Linux (`/proc`), and Windows (system APIs), along with CPU, OS,
98
+ architecture, and disk. `memory_bytes` is portable host RAM. `unified_memory_bytes` is populated
99
+ only when host and accelerator memory are known to share a pool; it must not be treated as discrete
100
+ GPU VRAM. Ollama's `/api/ps` remains the placement authority.
101
+
102
+ All other paths use the compatibility proxy. It buffers request bodies up to 64 MB so a retry can
103
+ resend identical bytes, then streams the upstream response. It does not apply CPU model assignment.
104
+
105
+ ## Model discovery
106
+
107
+ The catalog joins data from Ollama and FreeLlama's optional evidence files:
108
+
109
+ ```mermaid
110
+ flowchart LR
111
+ TAGS["Ollama /api/tags"] --> CAT["Catalog builder"]
112
+ SHOW["Ollama /api/show"] --> CAT
113
+ PS["Ollama /api/ps"] --> CAT
114
+ BENCH["Local benchmark report"] --> CAT
115
+ POLICY["Task policy"] --> CAT
116
+ ASSIGN["CPU model assignments"] --> CAT
117
+ CAT --> MODEL["CatalogModel<br/>capabilities · context · residency<br/>benchmark · policy rank · backend"]
118
+ ```
119
+
120
+ FreeLlama fetches tags and residency from each configured backend. Models assigned to CPU are
121
+ removed from the primary catalog view and included only from the secondary backend. Static catalog
122
+ metadata is cached for 30 seconds; residency is refreshed before routing.
123
+
124
+ A failed `/api/show` response skips that model instead of failing the entire catalog. An unreachable
125
+ configured backend fails catalog discovery closed because FreeLlama cannot prove the assigned model's
126
+ state.
127
+
128
+ ## Deterministic routing
129
+
130
+ Routing starts with an explicit task contract. Supported task kinds are `completion`, `coding`,
131
+ `code_repair`, `tools`, `browser`, `vision`, `embedding`, and `long_context`.
132
+
133
+ ```mermaid
134
+ flowchart TD
135
+ I["Route input"] --> C["Derive required capabilities<br/>and requested context"]
136
+ C --> F["Filter installed candidates"]
137
+ F --> X{"Explicit model?"}
138
+ X -->|"Yes"| E["Use exact model or refuse"]
139
+ X -->|"No"| O{"Objective"}
140
+ O -->|"fastest"| S["Rank local performance,<br/>residency, and deterministic ties"]
141
+ O -->|"balanced"| B["Require policy-qualified candidates,<br/>then balance score and residency"]
142
+ O -->|"quality"| Q["Require policy-qualified candidates,<br/>then prefer policy order"]
143
+ E --> H["Grade advertised-context compatibility and evidence"]
144
+ S --> H
145
+ B --> H
146
+ Q --> H
147
+ H --> G{"Minimum confidence met?"}
148
+ G -->|"No"| R["Refuse with missing evidence"]
149
+ G -->|"Yes or unset"| D["RouteDecision"]
150
+ ```
151
+
152
+ Explicit model selection never substitutes another model. Every rejected candidate includes a
153
+ reason so callers can distinguish capability, context, policy, and installation failures.
154
+
155
+ `context_window_fit` means only that requested `num_ctx` fits the model's advertised context
156
+ window. It is not a live-memory, free-VRAM, K/V-cache, thermal, or runner-admission verdict.
157
+ Execution separately reports a conservative model-metadata K/V lower-bound preflight and post-run
158
+ placement evidence; Ollama remains authoritative for actual runner allocation and admission.
159
+
160
+ ### Confidence evidence
161
+
162
+ Confidence is a grade derived from independent evidence dimensions:
163
+
164
+ | Policy evidence | Benchmark evidence | Confidence | Meaning |
165
+ |---|---|---|---|
166
+ | Present | Present | `medium` | The task policy qualifies the model and the machine has measured it |
167
+ | Present | Missing | `low` | Quality evidence exists without local functional measurement |
168
+ | Missing | Present | `low` | Local throughput exists without a quality contract |
169
+ | Missing | Missing | `low` | Routing relies on capability metadata only |
170
+
171
+ `minConfidence: "medium"` refuses before generation when either input is missing. The gate lives in
172
+ `select_route`, so the HTTP API, CLI, MCP server, and embedded core share the same behavior.
173
+
174
+ ## Natural-language routing
175
+
176
+ Natural-language routing cannot select a model directly:
177
+
178
+ ```mermaid
179
+ sequenceDiagram
180
+ participant C as Client
181
+ participant F as FreeLlama
182
+ participant I as Intent model
183
+ participant R as Deterministic router
184
+
185
+ C->>F: Natural-language request
186
+ F->>I: Strict JSON schema and bounded profile
187
+ I-->>F: Task, objective, context, tool, and vision fields
188
+ F->>F: Apply deterministic guards
189
+ F->>R: Normalized RouteInput
190
+ R-->>F: RouteDecision
191
+ F-->>C: Intent, adjustments, and route
192
+ ```
193
+
194
+ Word-boundary guards prevent incidental substrings such as `photosynthesis` from creating a vision
195
+ requirement. Explicit requirements in the original text override weak or unsupported inferred fields.
196
+
197
+ The natural route endpoint does not run the selected task. Submit a managed task to execute it.
198
+
199
+ ## Managed task execution
200
+
201
+ Managed tasks combine routing with admission and backend-aware transition coordination:
202
+
203
+ ```mermaid
204
+ flowchart TD
205
+ T["POST /tasks or /task-batches"] --> R["Select eligible model + backend"]
206
+ R --> K["Calculate metadata-backed K/V lower bound<br/>(or report unknown)"]
207
+ K --> A{"Acquire selected backend's<br/>3:2:1 fair weighted budget"}
208
+ A -->|"No"| E503["503 server busy"]
209
+ A -->|"Yes"| B{"Execution backend"}
210
+ B -->|"Primary"| GL{"GPU model resident<br/>under transition lock?"}
211
+ B -->|"CPU assignment"| CO["Add num_gpu: 0"]
212
+ CO --> CL{"CPU model resident<br/>under transition lock?"}
213
+ GL -->|"Yes"| GR["GPU shared lock"]
214
+ GL -->|"No"| GX["GPU exclusive transition lock"]
215
+ CL -->|"Yes"| CR["CPU shared lock"]
216
+ CL -->|"No"| CX["CPU exclusive transition lock"]
217
+ GR --> OQ["Send to selected Ollama queue"]
218
+ GX --> OQ
219
+ CR --> OQ
220
+ CX --> OQ
221
+ OQ --> SEND["Ollama schedules bounded request"]
222
+ SEND --> RETRY{"500, 502, 504,<br/>or connection failure?"}
223
+ RETRY -->|"Retryable"| OQ
224
+ RETRY -->|"Success"| OBS["Query selected Ollama /api/ps"]
225
+ OBS --> OUT["Route, assignment, physical observation,<br/>admission, metrics, and response"]
226
+ RETRY -->|"503, timeout, or final failure"| ERR["Return upstream error"]
227
+ ```
228
+
229
+ Admission is independent per backend and uses weighted fair round robin: interactive gets three
230
+ turns, normal two, and background one, preserving FIFO inside each class and preventing starvation.
231
+ The primary/GPU pool defaults to two weighted units and the
232
+ optional CPU pool defaults to one. A saturated GPU burst therefore cannot consume the permit held
233
+ for a small CPU helper. Those values represent one ordinary chat and one embedding, not detected
234
+ hardware capacity; operators can tune both budgets from queue-wait and resident-memory evidence.
235
+ After FreeLlama admission, each Ollama process applies its own `OLLAMA_MAX_QUEUE`, scheduler,
236
+ `OLLAMA_NUM_PARALLEL`, and loaded-model limit. Raw proxy requests bypass FreeLlama admission and
237
+ enter the primary Ollama queue directly.
238
+
239
+ | Task | Cost |
240
+ |---|---:|
241
+ | Embedding | `ceil(input_items / 4)` |
242
+ | Chat, coding, tools, browser, or long context | 2 |
243
+ | Vision | 4 |
244
+
245
+ FreeLlama acquires the admission slot before a transition lock to avoid deadlock. A model marked
246
+ resident during discovery is checked again while the shared transition lock is held; stale or
247
+ unavailable residency falls back to the exclusive transition path. Session affinity is bound only
248
+ after successful upstream execution, so refused and failed tasks cannot change later routing.
249
+
250
+ `POST /_freellama/v1/task-batches` is for caller-declared independent work only: every item has a
251
+ stable ID and `independent:true`; dependent workflow execution is rejected before any upstream call.
252
+ It bounds local dispatch and returns ordered per-item success/error receipts. Every child still
253
+ passes the same global admission and transition path above.
254
+
255
+ The K/V preflight derives F16 K+V bytes-per-token only when `/api/show` exposes the required model
256
+ shape. It blocks only a known weights-plus-cache lower bound above 80% of total CPU/unified memory.
257
+ It deliberately reports unknown rather than guessing for other architectures or discrete GPU free
258
+ VRAM; Ollama remains the live loader and final memory authority.
259
+
260
+ Resident tasks share a backend lock. Nonresident tasks take that backend's exclusive lock so a cold
261
+ load cannot race another managed task on the same server. CPU and GPU backends have separate locks
262
+ and admission pools, so they can progress independently.
263
+
264
+ HTTP `500`, `502`, and `504` status codes and connection failures use bounded retry with backoff.
265
+ FreeLlama does not retry `503 Service Unavailable` because retrying while holding admission can
266
+ amplify overload. It does not retry a generation timeout because the first request might still run.
267
+
268
+ ## CPU and GPU backend selection
269
+
270
+ CPU eligibility is an explicit operator assignment. Within that safe set, a caller may provide a
271
+ guarded preference and `auto` may learn from warm runtime receipts:
272
+
273
+ ```mermaid
274
+ flowchart TD
275
+ I["Task, objective, capabilities,<br/>model/session pins, preference"] --> E["Filter eligible installed models"]
276
+ E --> P{"Explicit model or<br/>session affinity?"}
277
+ P -->|"Yes"| M["Preserve pinned model"]
278
+ P -->|"No"| H{"Preference or auto hint<br/>has eligible candidates?"}
279
+ H -->|"No"| D["Deterministic router default"]
280
+ H -->|"Yes"| S["Select within hinted backend"]
281
+ M --> A{"In cpu_models set?"}
282
+ D --> A
283
+ S --> A
284
+ A -->|"No"| G["Primary upstream<br/>GPU requested"]
285
+ A -->|"Yes"| C["Secondary upstream<br/>CPU requested"]
286
+ C --> N["Pin options.num_gpu = 0"]
287
+ G --> O["Observe /api/ps processor"]
288
+ N --> O
289
+ O -->|"verified"| F["Record normalized warm<br/>work-unit latency"]
290
+ O -->|"unknown, mixed, mismatch"| W["Report; withhold feedback"]
291
+ F -.->|"After 3 samples/backend/task;<br/>not quality routing"| H
292
+ ```
293
+
294
+ The hint never changes the operator's CPU assignment. If the preferred backend has no eligible
295
+ model, routing falls back and returns `preference_satisfied: false`. Feedback is task-specific,
296
+ bounded, versioned, and prompt-free. The CLI persists it with atomic file replacement by default;
297
+ restart-reset behavior is available only through the explicit `--ephemeral-feedback` mode. It
298
+ records normalized latency only for already-resident, physically verified tasks so prompt size and
299
+ cold-load cost do not poison the comparison. It requires more than a 10% advantage; capacity can
300
+ break a tie before the sample threshold. Quality routing, explicit model selection, and session
301
+ affinity do not follow the latency loop.
302
+
303
+ The same selection function supplies preview/recommendation receipts, intent-model execution, and
304
+ managed task execution. This keeps advertised placement and actual request routing aligned.
305
+
306
+ Raw proxy traffic always uses the primary upstream. For setup and runtime verification, see
307
+ [Run models on CPU and GPU](CPU_GPU_ROUTING.md).
308
+
309
+ ## MCP tool flow
310
+
311
+ The MCP server keeps general model work separate from file-backed research and destructive lifecycle
312
+ operations:
313
+
314
+ ```mermaid
315
+ flowchart TD
316
+ MC["MCP client"] --> TOOL{"Tool"}
317
+ TOOL -->|"doctor"| NAPI["Native core diagnostics"]
318
+ TOOL -->|"models"| MIX["Control API or direct Ollama/library HTTP"]
319
+ TOOL -->|"run_task"| TASK["Control API route or task"]
320
+ TOOL -->|"ollama_manage"| LIFE["Direct Ollama pull or unload"]
321
+ TOOL -->|"ollama_delete"| DELETE["Explicit destructive Ollama delete"]
322
+ TOOL -->|"delegate_research"| AD["Confined adapter subprocess"]
323
+ AD --> FS["Allowlisted workspace"]
324
+ AD --> TASK
325
+ AD --> VER["Answer, citations, usage,<br/>and verification verdict"]
326
+ ```
327
+
328
+ The tool split prevents `run_task` from acquiring file access and prevents lifecycle operations from
329
+ being hidden inside a generic action. For schemas and security annotations, see the
330
+ [MCP server reference](../packages/mcp/README.md).
331
+
332
+ ## Grounded research flow
333
+
334
+ Use `delegate_research` for narrow questions that require reading repository files:
335
+
336
+ ```mermaid
337
+ flowchart TD
338
+ Q["Question and workspacePath"] --> P["Resolve path through symlinks"]
339
+ P --> A{"Inside allowed roots?"}
340
+ A -->|"No"| REFUSE["Refuse before model execution"]
341
+ A -->|"Yes"| G{"Model evidence grade usable?"}
342
+ G -->|"No"| REFUSE
343
+ G -->|"Yes or unmeasured"| LOOP["Bounded adapter loop"]
344
+ LOOP --> MANAGED["Each model turn: managed coding task"]
345
+ MANAGED --> RECEIPT["Admission + physical placement receipt"]
346
+ LOOP --> READ["Read and search files"]
347
+ READ --> ANSWER["Local-model answer"]
348
+ ANSWER --> V["Grade observed files, calls,<br/>model, and task envelope"]
349
+ V --> OUT["accept, verify, or escalate<br/>plus citations"]
350
+ ```
351
+
352
+ The verdict does not ask the local model whether it researched the answer. It uses the adapter's
353
+ recorded calls, successful file evidence, the selected model's measured grade, and the question's
354
+ shape.
355
+
356
+ The adapter loop preserves its control contract through four mechanisms:
357
+
358
+ - Pagination keeps complete output on disk while showing bounded pages to the model.
359
+ - Context fitting byte-preserves the system prompt and question by default, compacts older
360
+ observations, and fails before Ollama if pinned content cannot fit. The first estimate is
361
+ configurable; real `prompt_eval_count` values calibrate subsequent fits conservatively.
362
+ - JSON repair retains gathered evidence across a bounded format correction.
363
+ - Repeat suppression serves an identical earlier result without rerunning the subprocess command.
364
+
365
+ For the benchmark implementation of this loop, see [`AGENTS.md`](../AGENTS.md).
366
+
367
+ ## Context and token boundary
368
+
369
+ The intended orchestration pattern keeps judgment in the strongest model and token-heavy operations
370
+ local:
371
+
372
+ ```mermaid
373
+ flowchart LR
374
+ FRONTIER["Frontier model<br/>judgment and review"] --> DISPATCH["Small orchestrator<br/>tool dispatch and verification"]
375
+ DISPATCH --> FREE["FreeLlama"]
376
+ FREE --> LOCAL["Local Ollama models<br/>files, images, and embeddings"]
377
+ LOCAL --> FREE
378
+ FREE -->|"bounded answer, evidence,<br/>metrics, verdict"| DISPATCH
379
+ DISPATCH -->|"verified conclusion"| FRONTIER
380
+ ```
381
+
382
+ Raw source, images, and embedding vectors do not need to enter the frontier model's context.
383
+ Embedding vectors are withheld by default because they are large and not human-readable. For the
384
+ measured accounting, see [Token economics](ECONOMICS.md).
385
+
386
+ ## State and failure behavior
387
+
388
+ FreeLlama keeps these values in memory:
389
+
390
+ - Catalog metadata cache
391
+ - Current residency snapshots
392
+ - Session-to-model affinity
393
+ - Independent GPU and CPU priority-fair weighted admission pools
394
+ - Per-task normalized warm latency and queue feedback for each backend, restored from an optional
395
+ versioned atomic snapshot
396
+ - Separate CPU and GPU transition locks
397
+
398
+ Sessions are bounded (default 1024) and expire after idle time (default one hour); they store only
399
+ model affinity, never prompts or Ollama KV. Restarting `freellama serve` clears sessions and the catalog cache. Persisted placement feedback is
400
+ reloaded; `--ephemeral-feedback` intentionally resets it. Ollama owns model residency, so loaded
401
+ models survive a FreeLlama restart.
402
+
403
+ The design fails closed when it cannot establish a required contract. Examples include an
404
+ unreachable configured backend, an unknown confidence grade, a policy without qualified models, an
405
+ explicit model that is not installed, or a task that exceeds the advertised context window.
406
+
407
+ ## Product boundary
408
+
409
+ FreeLlama is not an inference engine, remote provider marketplace, billing layer, hosted model
410
+ registry, general agent runtime, or A2A coordinator. It can authenticate every route with one
411
+ operator-managed bearer token and refuses unauthenticated nonloopback listeners. An external layer
412
+ must still provide TLS, tenant authorization, tenant-specific limits, and isolation.
413
+
414
+ Use Ollama directly when a caller only needs raw speed from one exact model. Use FreeLlama when the
415
+ workload needs routing evidence, bounded admission, backend placement, compatibility proxying,
416
+ grounded research, or inspectable receipts.