@octocodeai/freellama-mcp-server 0.5.0 → 0.6.1

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.
@@ -11,10 +11,14 @@ the operating system and drivers schedule physical work.
11
11
 
12
12
  ## Responsibility boundary
13
13
 
14
- The following table defines the ownership boundary:
14
+ This is the canonical ownership rule; other guides link here.
15
15
 
16
16
  | Responsibility | Owner |
17
17
  |---|---|
18
+ | Goal decomposition, prompts, system messages, task dependencies, and answer verification | Calling agent |
19
+ | Ollama processes and endpoints, exact `--cpu-model` assignments, runtime settings, and approval of pulls, stops, and deletes | Operator |
20
+ | Prompt templates and model defaults | Ollama model metadata or a `Modelfile` |
21
+ | Physical CPU/GPU scheduling and memory | OS, drivers, and accelerator runtime |
18
22
  | Model files, runners, Metal, MLX, llama.cpp, and token generation | Ollama |
19
23
  | Native `/api/*` and OpenAI-compatible `/v1/*` semantics | Ollama |
20
24
  | Installed-model discovery and capability normalization | FreeLlama |
@@ -23,9 +27,33 @@ The following table defines the ownership boundary:
23
27
  | Forecast memory reservations, host-pressure holds, and requests to unload idle unpinned models | FreeLlama managed execution |
24
28
  | Explicit per-model CPU/GPU backend assignment | FreeLlama and separate Ollama processes |
25
29
  | Grounded research adapters, citations, and verification verdicts | FreeLlama MCP server |
30
+ | Bearer authentication of every route except the static `/_freellama/ui` shell | FreeLlama; external ingress owns TLS and tenant authorization |
26
31
 
27
- FreeLlama remains a sidecar rather than an Ollama fork. For the compatibility rationale, see the
28
- [Ollama sidecar boundary](OLLAMA_SIDECAR.md).
32
+ FreeLlama is a governed router, not an unrestricted hardware scheduler: a CPU preference cannot move
33
+ an arbitrary tag, and one managed call contains one task. Only the calling agent knows which tasks
34
+ are independent.
35
+
36
+ ### Ollama sidecar
37
+
38
+ FreeLlama is a loopback sidecar, not an Ollama fork. It talks to Ollama over its documented HTTP
39
+ contract, which also makes a second, process-isolated CPU backend possible without changing client
40
+ payloads:
41
+
42
+ ```mermaid
43
+ flowchart LR
44
+ C["Ollama-compatible client"] --> F["FreeLlama loopback sidecar"]
45
+ F -->|"raw /api and /v1"| G["Primary Ollama"]
46
+ F -->|"managed primary task"| G
47
+ F -->|"managed assigned task"| U["Optional CPU Ollama"]
48
+ G --> E["Metal, MLX, CUDA, ROCm, Vulkan, or CPU runner"]
49
+ U --> E2["CPU runner"]
50
+ ```
51
+
52
+ FreeLlama does not make an individual model decode faster. It can improve workload completion by
53
+ avoiding unsuitable routes, reducing avoidable transitions, refusing unsupported work early, and
54
+ overlapping independent CPU and GPU model requests when the machine benefits from that layout.
55
+ Sources: [Ollama API](https://docs.ollama.com/api/introduction),
56
+ [streaming](https://docs.ollama.com/api/streaming), [usage](https://docs.ollama.com/api/usage).
29
57
 
30
58
  ## System topology
31
59
 
@@ -64,9 +92,10 @@ flowchart TB
64
92
  ADAPTER --> GPU
65
93
  ```
66
94
 
67
- The CLI and MCP server do not reimplement routing. The CLI calls the core directly. The MCP server
68
- uses the feature-gated NAPI boundary for native operations and the control API for serve-backed
69
- operations.
95
+ The CLI and MCP server do not reimplement routing. CLI commands other than `serve`, `doctor`,
96
+ `init`, and benchmarking are HTTP clients of a running `freellama serve`. The MCP server reaches the
97
+ same control API through the feature-gated NAPI boundary, and unless `FREELLAMA_MCP_AUTOSTART_SERVE=0`
98
+ it starts the bundled `serve` in the background at launch when nothing answers on the default endpoint.
70
99
 
71
100
  ## Request classification
72
101
 
@@ -79,8 +108,7 @@ flowchart TD
79
108
  RAW --> PRIMARY["Primary Ollama"]
80
109
  P -->|"Yes"| C{"Control endpoint"}
81
110
  C -->|"health, machine, models"| READ["Read local and Ollama state"]
82
- C -->|"recommendations, routes"| DECIDE["Decide without inference"]
83
- C -->|"natural-routes"| INTENT["Run intent model, then route"]
111
+ C -->|"routes"| DECIDE["Decide without inference"]
84
112
  C -->|"tasks"| RUN["Route, admit, and execute"]
85
113
  C -->|"sessions"| SESSION["Create in-memory affinity id"]
86
114
  C -->|"scopes"| SCOPES["Retain revision-protected messages"]
@@ -94,30 +122,72 @@ The control API exposes these endpoints:
94
122
  | `GET /_freellama/v1/health` | Health, admission capacity, and configured backends | No |
95
123
  | `GET /_freellama/v1/machine` | Machine profile | No |
96
124
  | `GET /_freellama/v1/models` | Normalized installed catalog, evidence, residency, and execution backend | No |
97
- | `POST /_freellama/v1/recommendations` | Installed route or reviewed installation plan | No |
98
125
  | `POST /_freellama/v1/routes` | Deterministic route decision | No |
99
- | `POST /_freellama/v1/natural-routes` | Schema-bound intent interpretation followed by deterministic routing | Intent model only |
100
126
  | `POST /_freellama/v1/sessions` | New model-affinity session | No |
101
127
  | `DELETE /_freellama/v1/sessions/:session_id` | Release model-affinity session | No |
128
+ | `POST /_freellama/v1/sessions/:session_id/kill` | Release a session and cancel its in-flight tasks; the runner stays loaded | No new inference |
102
129
  | `POST /_freellama/v1/scopes` | Create bounded message history | No |
103
130
  | `GET /_freellama/v1/scopes/:id` | Scope metadata; optional explicit history inclusion | No |
104
131
  | `POST /_freellama/v1/scopes/:id/fork` | Fork history at an expected revision | No |
105
132
  | `DELETE /_freellama/v1/scopes/:id` | Delete retained history | No |
106
133
  | `POST /_freellama/v1/warm` | Admitted load of an exact installed runner profile | Load only |
107
- | `POST /_freellama/v1/tasks` | Managed chat, vision, tools, or embedding task | Yes |
134
+ | `POST /_freellama/v1/tasks` | Managed chat, vision, tools, or embedding task (body shape under [Request shapes](#request-shapes)) | Yes |
135
+ | `POST /_freellama/v1/task-batches` | Caller-declared independent tasks with ordered per-item receipts | Yes |
108
136
  | `GET /_freellama/v1/jobs` | Deferred job metadata without prompts or results | No |
109
137
  | `GET /_freellama/v1/jobs/:id` | One deferred receipt and retained result | No |
110
138
  | `POST /_freellama/v1/jobs/:id/cancel` | Cancel one deferred task and release its local permits | No new inference |
111
139
  | `DELETE /_freellama/v1/jobs/:id` | Cancel active work, release local permits, and remove its retained record | No new inference |
112
140
 
141
+ Status, usage, metrics, and runtime-config endpoints are listed in [monitoring](MONITORING.md).
142
+
143
+ ### Request shapes
144
+
145
+ The control API uses snake_case JSON. A managed task body is the routing fields plus the payload:
146
+
147
+ ```json
148
+ {
149
+ "task": "vision", "objective": "fastest", "model": "my-vision-model",
150
+ "session_id": "<uuid from POST /sessions>", "required_capabilities": ["vision"],
151
+ "prompt": "Text Recognition:", "images": ["<base64, no data-URI prefix>"],
152
+ "priority": "background", "keep_alive": "5m", "max_wait_seconds": 30, "timeout_seconds": 120,
153
+ "stop_on_repetition": true,
154
+ "request_options": { "options": { "temperature": 0, "num_predict": 600 }, "format": "json", "think": false }
155
+ }
156
+ ```
157
+
158
+ `model` is read the way Ollama reads it: an exact installed tag, else `name:latest`, else the one
159
+ installed tag of that family; an unknown or ambiguous name is refused with the installed candidates.
160
+ `messages` (Ollama message objects, images included) replaces `prompt`; `input` serves embeddings;
161
+ `context_tokens` owns `num_ctx` and placement owns `num_gpu`, so neither is accepted inside
162
+ `request_options.options`. `stop_on_repetition: true` streams the chat from Ollama and stops as soon
163
+ as the output repeats its unit twice after the first copy over 96+ characters: the connection
164
+ closes, which cancels generation upstream, and everything generated is kept with
165
+ `done_reason: "repetition"`. An Ollama "token repeat limit" abort is kept the same way
166
+ (`done_reason: "repeat_limit"`). A stopped stream has no Ollama timing fields, so it trains no
167
+ throughput feedback. The receipt holds `route`, `admission` (`queue_wait_ms`,
168
+ `resource_wait_ms`, `transition_wait_ms`, `total_wait_ms`), `execution` (placement, observation,
169
+ `resource_admission`, `context_sizing`, `memory_reservation`), `metrics`, `feedback` and
170
+ `response`, which is Ollama's own answer (`message.content`, `eval_count`, durations).
171
+
172
+ A batch nests whole task bodies:
173
+
174
+ ```json
175
+ { "max_parallelism": 2, "tasks": [ { "id": "item-1", "independent": true, "task": { "task": "vision", "model": "my-vision-model", "prompt": "...", "images": ["..."] } } ] }
176
+ ```
177
+
178
+ `POST /sessions` with an empty object returns `session_id`; `POST /warm` takes `{"model": "<tag>"}`.
179
+
113
180
  The machine profile is host-derived rather than model-name-derived. It reports total physical
114
- memory on macOS (`sysctl`), Linux (`/proc`), and Windows (system APIs), along with CPU, OS,
181
+ memory on macOS (`sysctl`), Linux (`/proc`), and Windows (CIM through PowerShell), along with CPU, OS,
115
182
  architecture, and disk. `memory_bytes` is portable host RAM. `unified_memory_bytes` is populated
116
183
  only when host and accelerator memory are known to share a pool; it must not be treated as discrete
117
184
  GPU VRAM. Ollama's `/api/ps` remains the placement authority.
118
185
 
119
186
  All other paths use the compatibility proxy. It buffers request bodies up to 64 MB so a retry can
120
- resend identical bytes, then streams the upstream response. It does not apply CPU model assignment.
187
+ resend identical bytes, then streams the upstream response. It removes hop-by-hop headers, adds
188
+ `x-freellama-proxy: 1`, always targets the primary upstream, and does not apply CPU model
189
+ assignment. Existing Ollama clients keep predictable compatibility; clients that opt into the
190
+ managed API receive routing and policy behavior.
121
191
 
122
192
  ## Model discovery
123
193
 
@@ -131,12 +201,26 @@ flowchart LR
131
201
  BENCH["Local benchmark report"] --> CAT
132
202
  POLICY["Task policy"] --> CAT
133
203
  ASSIGN["CPU model assignments"] --> CAT
134
- CAT --> MODEL["CatalogModel<br/>capabilities · context · residency<br/>benchmark · policy rank · backend"]
204
+ LOOPS["Observed repetition loops"] --> CAT
205
+ CAT --> MODEL["CatalogModel<br/>capabilities · context · residency<br/>benchmark · policy rank · backend · loops"]
135
206
  ```
136
207
 
137
208
  FreeLlama fetches tags and residency from each configured backend. Models assigned to CPU are
138
209
  removed from the primary catalog view and included only from the secondary backend. Static catalog
139
- metadata is cached for 30 seconds; residency is refreshed before routing.
210
+ metadata is cached for 30 seconds; residency and observed loops are refreshed before routing.
211
+
212
+ Every field comes from the model's own metadata and from what FreeLlama observed, never from its
213
+ name. `GET /_freellama/v1/models` adds, per model:
214
+
215
+ - `context_default`: the context Ollama gives a request that leaves `num_ctx` unset (`source` is
216
+ `modelfile`, `config`, `ollama_context_length`, `vram_tier`, `resident_runner`, or `unknown`). A managed
217
+ task that sends a different `num_ctx` reloads the runner.
218
+ - `resident_context`: the `context_length` of the loaded runner from `/api/ps`.
219
+ - `observed_loops`: per task kind, managed runs since start and how many ended in a repetition
220
+ loop (`{runs, loops}`); process-local, not persisted.
221
+ - `kv_cache_bytes_per_token_f16`: estimated from the declared architecture's block count, KV head
222
+ count and key/value lengths, for any architecture; `null` when the metadata declares recurrent,
223
+ state-space, sliding-window, shared or cross-attention caches, which the dense formula misstates.
140
224
 
141
225
  A failed `/api/show` response skips that model instead of failing the entire catalog. An unreachable
142
226
  configured backend fails catalog discovery closed because FreeLlama cannot prove the assigned model's
@@ -150,7 +234,7 @@ matches exact tags and digest prefixes, preserves local supported features, and
150
234
  source excerpts and usage notes. Its bounded in-memory cache expires successes after one hour and
151
235
  failures after one minute. Failed or unmatched lookups leave local inventory and evidence intact.
152
236
  Public claims do not enter the Rust catalog, task policy, quality confidence, or routing decisions.
153
- See [Ollama model metadata](MODEL_METADATA.md) for the public contract and request bounds.
237
+ See [Model metadata](MODEL_SELECTION.md#model-metadata) for the public contract and request bounds.
154
238
 
155
239
  ## Deterministic routing
156
240
 
@@ -164,7 +248,7 @@ flowchart TD
164
248
  F --> X{"Explicit model?"}
165
249
  X -->|"Yes"| E["Use exact model or refuse"]
166
250
  X -->|"No"| O{"Objective"}
167
- O -->|"fastest"| S["Rank local performance,<br/>residency, and deterministic ties"]
251
+ O -->|"fastest"| S["Rank local benchmark,<br/>smaller size, and deterministic ties"]
168
252
  O -->|"balanced"| B["Prefer policy-qualified candidates;<br/>otherwise use eligible models with low confidence"]
169
253
  O -->|"quality"| Q["Require policy-qualified candidates,<br/>then prefer policy order"]
170
254
  E --> H["Grade advertised-context compatibility and evidence"]
@@ -176,8 +260,18 @@ flowchart TD
176
260
  G -->|"Yes or unset"| D["RouteDecision"]
177
261
  ```
178
262
 
179
- Explicit model selection never substitutes another model. Every rejected candidate includes a
180
- reason so callers can distinguish capability, context, policy, and installation failures.
263
+ Explicit model selection never substitutes another model. An explicit `model` is read the way
264
+ Ollama reads it: the exact tag, else `name:latest`, else the one installed tag of that family; an
265
+ unknown or ambiguous name is refused with the installed candidates. Every rejected candidate
266
+ includes a reason so callers can distinguish capability, context, policy, and installation failures.
267
+
268
+ Routing never ranks by a model's name or architecture. Automatic selection (fallback ranking and
269
+ session affinity) ranks a model last for a task kind when it has looped on that kind at least twice
270
+ in at most twice as many managed runs; the decision then carries
271
+ `repeats_on_this_task_last_resort`. An operator policy naming the model for the task, or an explicit
272
+ `model`, always wins. No request option is hard-coded for a model: apart from an operator policy's
273
+ per-model `model_options` (`think`, `num_predict`), stop sequences and decoding settings belong to
274
+ the caller.
181
275
 
182
276
  `context_window_fit` means only that requested `num_ctx` fits the model's advertised context
183
277
  window. It is not a live-memory, free-VRAM, K/V-cache, thermal, or runner-admission verdict.
@@ -198,37 +292,12 @@ Confidence is a grade derived from independent evidence dimensions:
198
292
  `minConfidence: "medium"` refuses before generation when either input is missing. The gate lives in
199
293
  `select_route`, so the HTTP API, CLI, MCP server, and embedded core share the same behavior.
200
294
 
201
- ## Natural-language routing
202
-
203
- Natural-language routing cannot select a model directly:
204
-
205
- ```mermaid
206
- sequenceDiagram
207
- participant C as Client
208
- participant F as FreeLlama
209
- participant I as Intent model
210
- participant R as Deterministic router
211
-
212
- C->>F: Natural-language request
213
- F->>I: Strict JSON schema and bounded profile
214
- I-->>F: Task, objective, context, tool, and vision fields
215
- F->>F: Apply deterministic guards
216
- F->>R: Normalized RouteInput
217
- R-->>F: RouteDecision
218
- F-->>C: Intent, adjustments, and route
219
- ```
220
-
221
- Word-boundary guards prevent incidental substrings such as `photosynthesis` from creating a vision
222
- requirement. Explicit requirements in the original text override weak or unsupported inferred fields.
223
-
224
- The natural route endpoint does not run the selected task. Submit a managed task to execute it.
225
-
226
295
  ## Managed task execution
227
296
 
228
- The implementation separates [admission scheduling](../packages/rust-core/src/platform/admission.rs),
229
- [execution coordination](../packages/rust-core/src/platform/execution.rs),
230
- [read-only readiness](../packages/rust-core/src/platform/readiness.rs), and
231
- [typed errors](../packages/rust-core/src/platform/error.rs). The platform module wires HTTP endpoints,
297
+ The implementation separates [admission scheduling](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/admission.rs),
298
+ [execution coordination](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/execution/mod.rs),
299
+ [read-only readiness](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/readiness.rs), and
300
+ [typed errors](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/error.rs). The platform module wires HTTP endpoints,
232
301
  configuration, discovery, and shared state; extracting these owners preserves the public routing API.
233
302
 
234
303
  Managed tasks combine routing with admission and backend-aware transition coordination. With
@@ -243,7 +312,7 @@ flowchart TD
243
312
  T["POST /tasks or /task-batches"] --> R["Select eligible model + backend"]
244
313
  R --> K["Estimate metadata-backed F16 K/V<br/>(or report unknown)"]
245
314
  K --> A{"Acquire selected backend's<br/>3:2:1 fair weighted budget"}
246
- A -->|"No"| E503["503 server busy"]
315
+ A -->|"No"| E503["429 queue full or<br/>503 wait timeout"]
247
316
  A -->|"Yes"| B{"Execution backend"}
248
317
  B -->|"Primary"| GL{"GPU model resident<br/>under transition lock?"}
249
318
  B -->|"CPU assignment"| CO["Add num_gpu: 0"]
@@ -271,8 +340,8 @@ falling back to two. The optional CPU pool defaults to one. A saturated GPU burs
271
340
  consume the permit held for a small CPU helper. With one parallel slot, those values represent one
272
341
  ordinary chat and one embedding. Operators can tune both budgets from queue-wait and resident-memory evidence.
273
342
  After FreeLlama admission, each Ollama process applies its own `OLLAMA_MAX_QUEUE`, scheduler,
274
- `OLLAMA_NUM_PARALLEL`, and loaded-model limit. Raw proxy requests bypass weighted admission but
275
- still pass the raw concurrency cap, backend exclusion, and host-pressure gate.
343
+ `OLLAMA_NUM_PARALLEL`, and loaded-model limit. Raw proxy generation requests bypass weighted
344
+ admission but still pass the raw concurrency cap, backend exclusion, and host-pressure gate.
276
345
 
277
346
  | Task | Default cost |
278
347
  |---|---:|
@@ -312,9 +381,10 @@ stable ID and `independent:true`; dependent workflow execution is rejected befor
312
381
  It bounds local dispatch and returns ordered per-item success/error receipts. Every child still
313
382
  passes the same global admission and transition path above.
314
383
 
315
- The K/V preflight derives single-sequence F16 K+V bytes-per-token only for supported model
316
- architectures with sufficient metadata. Explicit key/value dimensions take precedence; sliding-window,
317
- shared-KV, recurrent, and unknown layouts report unknown. F16 is advisory because quantized KV can
384
+ The K/V preflight derives single-sequence F16 K+V bytes-per-token for any architecture whose
385
+ metadata declares the block count and head counts. Explicit key/value dimensions take precedence
386
+ over embedding length divided by heads; sliding-window, shared-KV, recurrent, cross-attention, and
387
+ unknown layouts report unknown. F16 is advisory because quantized KV can
318
388
  use less memory. The coarse model-file budget refuses files over 80% of local CPU/unified RAM only
319
389
  for loopback backends. Forecasts use each backend's independently attributed parallelism and KV
320
390
  cache settings where process inspection is available, with explicit fallback sources otherwise.
@@ -322,32 +392,45 @@ Process observations refresh on requests after five seconds; measurements made u
322
392
  settings cannot supply an exact-fit estimate. Ollama remains the live loader and final memory
323
393
  authority. Configured settings alone do not prove physical processor placement.
324
394
 
325
- The shared [resource governor](../packages/rust-core/src/platform/resources.rs) samples local
395
+ The shared [resource governor](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/resources/mod.rs) samples local
326
396
  available-memory estimates, load per logical CPU, OS memory pressure, active swap-out growth, and
327
- thermal throttling when reported. It holds new local work below the larger of 15% available RAM or
328
- 1 GiB, and requires two healthy samples above the larger of 20% or 2 GiB to resume. Historical swap
329
- occupancy alone is not pressure. Samples are cached for two seconds; unavailable signals stay unknown.
330
- Remote backends bypass this host gate.
397
+ thermal throttling when reported. OS memory pressure holds every local demand; active swap-out
398
+ growth holds new loads; CPU-load and thermal holds apply to CPU-assigned work and to cold loads
399
+ (decoding weights is CPU work and a new heat source) but not to a bounded request on a runner
400
+ already resident on the GPU, which neither waits for the cores nor cools the package by waiting (`ResourceDemand::is_held_by`; the assessment's
401
+ `held_by` lists the holds that applied). Low available RAM (below the larger of 15% or 1 GiB, clearing after two
402
+ healthy samples above the larger of 20% or 2 GiB) depends on the platform (`ResourcePolicy::low_memory`).
403
+ A new load must leave that reserve free, but never more than its own size above the 1 GiB floor.
404
+ On macOS (`advisory`) the estimate undercounts what the OS can reclaim, so a load that does not cover
405
+ it first unloads idle runners and then dispatches with a `memory_advisory`. On Linux and other
406
+ platforms (`refuse`) a new load that does not fit first unloads idle runners and then waits
407
+ with `held_insufficient_capacity` until a permit release or a fresh sample frees capacity, or refuses
408
+ with 503 at its deadline: Linux `MemAvailable` already includes reclaimable cache and is the hard cap
409
+ in a container, so over-admitting invites the OOM killer. Already-resident runners add no memory and
410
+ are admitted in both modes, also during an active-swapping hold, so a large load never locks out
411
+ reuse of its own runner; swapping still holds new loads. Historical swap occupancy alone is not pressure. Samples are cached for two
412
+ seconds; unavailable signals stay unknown. Remote backends bypass this host gate.
331
413
 
332
414
  Each pressure signal recovers independently after two fresh samples that meet its recovery
333
- threshold. A recovered CPU-load signal therefore clears even while RAM remains low. That keeps
334
- unchanged resident runners eligible under a memory-only hold while cold loads continue waiting.
415
+ threshold. A recovered CPU-load signal therefore clears even while RAM remains low.
335
416
 
336
- The default `require_memory` telemetry policy holds local inference when available RAM is missing,
337
- even when a raw request has no model-footprint estimate. `best_effort` is an explicit opt-in;
417
+ On Linux and macOS the default `require_memory` telemetry policy holds local inference when
418
+ available RAM is missing, even when a raw request has no model-footprint estimate. Windows and other
419
+ platforms have no host collector, so they default to `best_effort` and admit with
420
+ `admitted_telemetry_unknown`; elsewhere `best_effort` is an explicit opt-in;
338
421
  `require_all` additionally requires the collector's applicable load, OS-pressure, and thermal signals.
339
422
  Unsupported Linux collector signals remain explicitly unavailable rather than being fabricated.
340
423
  The pure `ResourceSnapshot::assess_capacity` calculation is shared by admission and previews.
341
424
  Previews use the same footprint lookup, subtract existing reservations, and expose both queue and
342
- resource readiness. An available weighted slot cannot by itself produce `runnable_now` when model
343
- headroom is insufficient. Preview capacity is advisory and conservative, never a reservation.
425
+ resource readiness. Insufficient model headroom reports `runnable_low_memory_estimate` and admits
426
+ no siblings on macOS; elsewhere it reports `held_insufficient_capacity`. Preview capacity is advisory and conservative, never a reservation.
344
427
 
345
428
  Managed CPU/unified-memory tasks reserve estimated additional model-file and known F16 KV bytes
346
429
  across both backends. Verified runner footprints replace that estimate only for the same backend,
347
430
  immutable model digest, and equal-or-larger observed context. Exact resident digest/context matches
348
- avoid double-counting existing allocations. The reservation is rechecked after transition locking;
349
- an increased requirement that no longer fits refuses with 503, without waiting while holding the
350
- backend lock. Permits release on completion or cancellation. On discrete-GPU hosts, observed free
431
+ avoid double-counting existing allocations. The reservation is rechecked after transition locking
432
+ without waiting while holding the backend lock; an increased requirement that no longer fits the
433
+ estimate dispatches with a `memory_advisory`, and a pressure hold refuses with 503. Permits release on completion or cancellation. On discrete-GPU hosts, observed free
351
434
  VRAM discounts the estimated host-memory requirement by the bytes the GPU can hold. Missing VRAM
352
435
  telemetry reserves the full estimated footprint in host RAM. The governor cannot constrain external
353
436
  allocations or preempt an already-running model.
@@ -369,11 +452,11 @@ Resident tasks share a backend lock. Nonresident tasks take that backend's exclu
369
452
  load cannot race another managed task on the same server. CPU and GPU backends have separate locks
370
453
  and admission pools, so they can progress independently.
371
454
 
372
- In `serve`, mutating raw proxy requests also take the primary backend's exclusive transition lock,
373
- returning 503 when busy. The response body holds this guard through EOF or disconnect. Metadata
374
- GET/HEAD and `/api/show` requests remain available. Raw inference waits at most 500 ms for host
375
- pressure to clear, then returns 503 with `Retry-After`; empty `keep_alive:0` unload requests bypass
376
- pressure. Raw request-body collection has the configured request deadline too; an incomplete upload
455
+ In `serve`, raw generation requests also take the primary backend's exclusive transition lock,
456
+ returning 503 when it stays busy past the raw queue wait. The response body holds this guard through
457
+ EOF or disconnect. Metadata GET/HEAD, `/api/show`, model-store calls (pull, push, copy, delete, and
458
+ blob uploads), and empty `keep_alive:0` unload requests take no lock and bypass pressure. Raw
459
+ inference waits at most two seconds for host pressure to clear, then returns 503 with `Retry-After`. Raw request-body collection has the configured request deadline too; an incomplete upload
377
460
  returns HTTP 408 and releases its guards without contacting Ollama. Admission receipts report
378
461
  `queue_wait_ms`, `resource_wait_ms`, `transition_wait_ms`, and
379
462
  their sum as `total_wait_ms`. Health and route receipts expose sampled pressure and reservations.
@@ -418,35 +501,18 @@ cold-load cost do not poison the comparison. It requires more than a 10% advanta
418
501
  break a tie before the sample threshold. Quality routing, explicit model selection, and session
419
502
  affinity do not follow the latency loop.
420
503
 
421
- The same selection function supplies preview/recommendation receipts, intent-model execution, and
422
- managed task execution. This keeps advertised placement and actual request routing aligned.
504
+ The same selection function supplies preview receipts and managed task execution. This keeps advertised placement and actual request routing aligned.
423
505
 
424
506
  Raw proxy traffic always uses the primary upstream. For setup and runtime verification, see
425
507
  [Run models on CPU and GPU](CPU_GPU_ROUTING.md).
426
508
 
427
509
  ## MCP tool flow
428
510
 
429
- The MCP server keeps general model work separate from file-backed research and destructive lifecycle
430
- operations:
431
-
432
- ```mermaid
433
- flowchart TD
434
- MC["MCP client"] --> TOOL{"Tool"}
435
- TOOL -->|"doctor"| NAPI["Native core diagnostics"]
436
- TOOL -->|"models"| MIX["Control API or direct Ollama/library HTTP"]
437
- TOOL -->|"run_task"| TASK["Control API route or task"]
438
- TOOL -->|"task_jobs"| JOB["Deferred receipts and per-task cancellation"]
439
- TOOL -->|"ollama_manage"| LIFE["Direct Ollama pull or unload"]
440
- TOOL -->|"ollama_delete"| DELETE["Explicit destructive Ollama delete"]
441
- TOOL -->|"delegate_research"| AD["Confined adapter subprocess"]
442
- AD --> FS["Allowlisted workspace"]
443
- AD --> TASK
444
- AD --> VER["Answer, citations, usage,<br/>and verification verdict"]
445
- ```
446
-
447
- The tool split prevents `run_task` from acquiring file access and prevents lifecycle operations from
448
- being hidden inside a generic action. For schemas and security annotations, see the
449
- [MCP server reference](../packages/mcp/README.md).
511
+ The MCP server keeps general model work (`run_task`), file-backed research (`delegate_research`, a
512
+ confined adapter subprocess), and destructive lifecycle operations (`ollama_manage`,
513
+ `ollama_delete`) in separate tools, so `run_task` never acquires file access and lifecycle
514
+ operations are not hidden inside a generic action. The canonical tool table, schemas, and security
515
+ annotations are in the [MCP server reference](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#tools).
450
516
 
451
517
  ## Grounded research flow
452
518
 
@@ -499,8 +565,8 @@ Adapter cache totals remain null if any turn is unreported, with partial-report
499
565
  See [Ollama usage](https://docs.ollama.com/api/usage) and
500
566
  [the pinned prefix-cache implementation](https://github.com/ggml-org/llama.cpp/blob/74a7c897f049c17e7080423aa2111776eff6ebbf/tools/server/server-context.cpp#L3201).
501
567
 
502
- For adapter implementation, defaults, and measured caveats, see the
503
- [local adapter reference](../benchmark/local/docs/07-adapter-contracts.md).
568
+ Adapter implementations and defaults live in
569
+ [`packages/mcp/src/research/`](../packages/mcp/src/research/).
504
570
 
505
571
  ## Context and token boundary
506
572
 
@@ -519,7 +585,7 @@ flowchart LR
519
585
 
520
586
  Raw source, images, and embedding vectors do not need to enter the frontier model's context.
521
587
  Embedding vectors are withheld by default because they are large and not human-readable. For the
522
- measured accounting, see [Token economics](ECONOMICS.md).
588
+ measured accounting, see [Token economics](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#token-economics).
523
589
 
524
590
  ## State and failure behavior
525
591
 
@@ -543,6 +609,14 @@ expected revision. Warming uses ordinary admission and fit checks; omitted resid
543
609
  a finite measured policy. See [Scope history and model warming](SCOPES_AND_WARMING.md) for the
544
610
  public contract and configured limits.
545
611
 
612
+ In `serve`, raw generation traffic shares the primary transition lock and receives
613
+ host-pressure gating, while managed tasks also reserve forecast memory. Direct Ollama callers bypass
614
+ these controls. FreeLlama cannot preempt inference or constrain other processes. A configured but
615
+ unreachable CPU backend makes managed catalog discovery fail closed; raw primary passthrough remains
616
+ usable. Runtime feedback is task-specific, token-normalized, and warm-only: it can steer unpinned
617
+ `fastest` or `balanced` work after three samples per backend and a greater-than-10% advantage, but
618
+ cannot change CPU eligibility or steer quality routing.
619
+
546
620
  The design fails closed when it cannot establish a required contract. Examples include an
547
621
  unreachable configured backend, an unknown confidence grade, a policy without qualified models, an
548
622
  explicit model that is not installed, or a task that exceeds the advertised context window.
@@ -550,8 +624,9 @@ explicit model that is not installed, or a task that exceeds the advertised cont
550
624
  ## Product boundary
551
625
 
552
626
  FreeLlama is not an inference engine, remote provider marketplace, billing layer, hosted model
553
- registry, general agent runtime, or A2A coordinator. It can authenticate every route with one
554
- operator-managed bearer token and refuses unauthenticated nonloopback listeners. An external layer
627
+ registry, general agent runtime, or A2A coordinator. It can authenticate every route except the
628
+ static UI shell with one operator-managed bearer token and refuses unauthenticated nonloopback
629
+ listeners. An external layer
555
630
  must still provide TLS, tenant authorization, tenant-specific limits, and isolation.
556
631
 
557
632
  Use Ollama directly when a caller only needs raw speed from one exact model. Use FreeLlama when the