@octocodeai/freellama-mcp-server 0.5.0 → 0.6.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.
@@ -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 | 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
 
@@ -79,8 +107,7 @@ flowchart TD
79
107
  RAW --> PRIMARY["Primary Ollama"]
80
108
  P -->|"Yes"| C{"Control endpoint"}
81
109
  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"]
110
+ C -->|"routes"| DECIDE["Decide without inference"]
84
111
  C -->|"tasks"| RUN["Route, admit, and execute"]
85
112
  C -->|"sessions"| SESSION["Create in-memory affinity id"]
86
113
  C -->|"scopes"| SCOPES["Retain revision-protected messages"]
@@ -94,9 +121,7 @@ The control API exposes these endpoints:
94
121
  | `GET /_freellama/v1/health` | Health, admission capacity, and configured backends | No |
95
122
  | `GET /_freellama/v1/machine` | Machine profile | No |
96
123
  | `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
124
  | `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
125
  | `POST /_freellama/v1/sessions` | New model-affinity session | No |
101
126
  | `DELETE /_freellama/v1/sessions/:session_id` | Release model-affinity session | No |
102
127
  | `POST /_freellama/v1/scopes` | Create bounded message history | No |
@@ -104,12 +129,49 @@ The control API exposes these endpoints:
104
129
  | `POST /_freellama/v1/scopes/:id/fork` | Fork history at an expected revision | No |
105
130
  | `DELETE /_freellama/v1/scopes/:id` | Delete retained history | No |
106
131
  | `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 |
132
+ | `POST /_freellama/v1/tasks` | Managed chat, vision, tools, or embedding task (body shape under [Request shapes](#request-shapes)) | Yes |
108
133
  | `GET /_freellama/v1/jobs` | Deferred job metadata without prompts or results | No |
109
134
  | `GET /_freellama/v1/jobs/:id` | One deferred receipt and retained result | No |
110
135
  | `POST /_freellama/v1/jobs/:id/cancel` | Cancel one deferred task and release its local permits | No new inference |
111
136
  | `DELETE /_freellama/v1/jobs/:id` | Cancel active work, release local permits, and remove its retained record | No new inference |
112
137
 
138
+ ### Request shapes
139
+
140
+ The control API uses snake_case JSON. A managed task body is the routing fields plus the payload:
141
+
142
+ ```json
143
+ {
144
+ "task": "vision", "objective": "fastest", "model": "my-vision-model",
145
+ "session_id": "<uuid from POST /sessions>", "required_capabilities": ["vision"],
146
+ "prompt": "Text Recognition:", "images": ["<base64, no data-URI prefix>"],
147
+ "priority": "background", "keep_alive": "5m", "max_wait_seconds": 30, "timeout_seconds": 120,
148
+ "stop_on_repetition": true,
149
+ "request_options": { "options": { "temperature": 0, "num_predict": 600 }, "format": "json", "think": false }
150
+ }
151
+ ```
152
+
153
+ `model` is read the way Ollama reads it: an exact installed tag, else `name:latest`, else the one
154
+ installed tag of that family; an unknown or ambiguous name is refused with the installed candidates.
155
+ `messages` (Ollama message objects, images included) replaces `prompt`; `input` serves embeddings;
156
+ `context_tokens` owns `num_ctx` and placement owns `num_gpu`, so neither is accepted inside
157
+ `request_options.options`. `stop_on_repetition: true` streams the chat from Ollama and stops as soon
158
+ as the output repeats its unit twice after the first copy over 96+ characters: the connection
159
+ closes, which cancels generation upstream, and everything generated is kept with
160
+ `done_reason: "repetition"`. An Ollama "token repeat limit" abort is kept the same way
161
+ (`done_reason: "repeat_limit"`). A stopped stream has no Ollama timing fields, so it trains no
162
+ throughput feedback. The receipt holds `route`, `admission` (`queue_wait_ms`,
163
+ `resource_wait_ms`, `transition_wait_ms`, `total_wait_ms`), `execution` (placement, observation,
164
+ `resource_admission`, `context_sizing`, `memory_reservation`), `metrics`, `feedback` and
165
+ `response`, which is Ollama's own answer (`message.content`, `eval_count`, durations).
166
+
167
+ A batch nests whole task bodies:
168
+
169
+ ```json
170
+ { "max_parallelism": 2, "tasks": [ { "id": "item-1", "independent": true, "task": { "task": "vision", "model": "my-vision-model", "prompt": "...", "images": ["..."] } } ] }
171
+ ```
172
+
173
+ `POST /sessions` with an empty object returns `session_id`; `POST /warm` takes `{"model": "<tag>"}`.
174
+
113
175
  The machine profile is host-derived rather than model-name-derived. It reports total physical
114
176
  memory on macOS (`sysctl`), Linux (`/proc`), and Windows (system APIs), along with CPU, OS,
115
177
  architecture, and disk. `memory_bytes` is portable host RAM. `unified_memory_bytes` is populated
@@ -117,7 +179,10 @@ only when host and accelerator memory are known to share a pool; it must not be
117
179
  GPU VRAM. Ollama's `/api/ps` remains the placement authority.
118
180
 
119
181
  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.
182
+ resend identical bytes, then streams the upstream response. It removes hop-by-hop headers, adds
183
+ `x-freellama-proxy: 1`, always targets the primary upstream, and does not apply CPU model
184
+ assignment. Existing Ollama clients keep predictable compatibility; clients that opt into the
185
+ managed API receive routing and policy behavior.
121
186
 
122
187
  ## Model discovery
123
188
 
@@ -131,12 +196,26 @@ flowchart LR
131
196
  BENCH["Local benchmark report"] --> CAT
132
197
  POLICY["Task policy"] --> CAT
133
198
  ASSIGN["CPU model assignments"] --> CAT
134
- CAT --> MODEL["CatalogModel<br/>capabilities · context · residency<br/>benchmark · policy rank · backend"]
199
+ LOOPS["Observed repetition loops"] --> CAT
200
+ CAT --> MODEL["CatalogModel<br/>capabilities · context · residency<br/>benchmark · policy rank · backend · loops"]
135
201
  ```
136
202
 
137
203
  FreeLlama fetches tags and residency from each configured backend. Models assigned to CPU are
138
204
  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.
205
+ metadata is cached for 30 seconds; residency and observed loops are refreshed before routing.
206
+
207
+ Every field comes from the model's own metadata and from what FreeLlama observed, never from its
208
+ name. `GET /_freellama/v1/models` adds, per model:
209
+
210
+ - `context_default`: the context Ollama gives a request that leaves `num_ctx` unset (`source` is
211
+ `modelfile`, `config`, `ollama_context_length`, `vram_tier`, or `resident_runner`). A managed
212
+ task that sends a different `num_ctx` reloads the runner.
213
+ - `resident_context`: the `context_length` of the loaded runner from `/api/ps`.
214
+ - `observed_loops`: per task kind, managed runs since start and how many ended in a repetition
215
+ loop (`{runs, loops}`); process-local, not persisted.
216
+ - `kv_cache_bytes_per_token_f16`: estimated from the declared architecture's block count, KV head
217
+ count and key/value lengths, for any architecture; `null` when the metadata declares recurrent,
218
+ state-space, sliding-window, shared or cross-attention caches, which the dense formula misstates.
140
219
 
141
220
  A failed `/api/show` response skips that model instead of failing the entire catalog. An unreachable
142
221
  configured backend fails catalog discovery closed because FreeLlama cannot prove the assigned model's
@@ -150,7 +229,7 @@ matches exact tags and digest prefixes, preserves local supported features, and
150
229
  source excerpts and usage notes. Its bounded in-memory cache expires successes after one hour and
151
230
  failures after one minute. Failed or unmatched lookups leave local inventory and evidence intact.
152
231
  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.
232
+ See [Model metadata](MODEL_SELECTION.md#model-metadata) for the public contract and request bounds.
154
233
 
155
234
  ## Deterministic routing
156
235
 
@@ -176,8 +255,17 @@ flowchart TD
176
255
  G -->|"Yes or unset"| D["RouteDecision"]
177
256
  ```
178
257
 
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.
258
+ Explicit model selection never substitutes another model. An explicit `model` is read the way
259
+ Ollama reads it: the exact tag, else `name:latest`, else the one installed tag of that family; an
260
+ unknown or ambiguous name is refused with the installed candidates. Every rejected candidate
261
+ includes a reason so callers can distinguish capability, context, policy, and installation failures.
262
+
263
+ Routing never ranks by a model's name or architecture. Automatic selection (fallback ranking and
264
+ session affinity) ranks a model last for a task kind when it has looped on that kind at least twice
265
+ in at most twice as many managed runs; the decision then carries
266
+ `repeats_on_this_task_last_resort`. An operator policy naming the model for the task, or an explicit
267
+ `model`, always wins. No request option is added because of which model was chosen: stop sequences
268
+ and decoding settings belong to the caller.
181
269
 
182
270
  `context_window_fit` means only that requested `num_ctx` fits the model's advertised context
183
271
  window. It is not a live-memory, free-VRAM, K/V-cache, thermal, or runner-admission verdict.
@@ -198,37 +286,12 @@ Confidence is a grade derived from independent evidence dimensions:
198
286
  `minConfidence: "medium"` refuses before generation when either input is missing. The gate lives in
199
287
  `select_route`, so the HTTP API, CLI, MCP server, and embedded core share the same behavior.
200
288
 
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
289
  ## Managed task execution
227
290
 
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,
291
+ The implementation separates [admission scheduling](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/admission.rs),
292
+ [execution coordination](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/execution/mod.rs),
293
+ [read-only readiness](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/readiness.rs), and
294
+ [typed errors](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/error.rs). The platform module wires HTTP endpoints,
232
295
  configuration, discovery, and shared state; extracting these owners preserves the public routing API.
233
296
 
234
297
  Managed tasks combine routing with admission and backend-aware transition coordination. With
@@ -322,16 +385,26 @@ Process observations refresh on requests after five seconds; measurements made u
322
385
  settings cannot supply an exact-fit estimate. Ollama remains the live loader and final memory
323
386
  authority. Configured settings alone do not prove physical processor placement.
324
387
 
325
- The shared [resource governor](../packages/rust-core/src/platform/resources.rs) samples local
388
+ The shared [resource governor](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/resources/mod.rs) samples local
326
389
  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.
390
+ thermal throttling when reported. OS memory pressure holds every local demand; active swap-out
391
+ growth holds new loads; CPU-load and thermal holds apply to CPU-assigned work and to cold loads
392
+ (decoding weights is CPU work and a new heat source) but not to a bounded request on a runner
393
+ already resident on the GPU, which neither waits for the cores nor cools the package by waiting (`ResourceDemand::is_held_by`; the assessment's
394
+ `held_by` lists the holds that applied). Low available RAM (below the larger of 15% or 1 GiB, clearing after two
395
+ healthy samples above the larger of 20% or 2 GiB) depends on the platform (`ResourcePolicy::low_memory`).
396
+ On macOS (`advisory`) the estimate undercounts what the OS can reclaim, so a load that does not cover
397
+ it first unloads idle runners and then dispatches with a `memory_advisory`. On Linux, Windows, and
398
+ other platforms (`refuse`) a new load that does not fit first unloads idle runners and then waits
399
+ with `held_insufficient_capacity` until a permit release or a fresh sample frees capacity, or refuses
400
+ with 503 at its deadline: Linux `MemAvailable` already includes reclaimable cache and is the hard cap
401
+ in a container, so over-admitting invites the OOM killer. Already-resident runners add no memory and
402
+ are admitted in both modes, also during an active-swapping hold, so a large load never locks out
403
+ reuse of its own runner; swapping still holds new loads. Historical swap occupancy alone is not pressure. Samples are cached for two
404
+ seconds; unavailable signals stay unknown. Remote backends bypass this host gate.
331
405
 
332
406
  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.
407
+ threshold. A recovered CPU-load signal therefore clears even while RAM remains low.
335
408
 
336
409
  The default `require_memory` telemetry policy holds local inference when available RAM is missing,
337
410
  even when a raw request has no model-footprint estimate. `best_effort` is an explicit opt-in;
@@ -339,15 +412,15 @@ even when a raw request has no model-footprint estimate. `best_effort` is an exp
339
412
  Unsupported Linux collector signals remain explicitly unavailable rather than being fabricated.
340
413
  The pure `ResourceSnapshot::assess_capacity` calculation is shared by admission and previews.
341
414
  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.
415
+ resource readiness. Insufficient model headroom reports `runnable_low_memory_estimate` and admits
416
+ no siblings on macOS; elsewhere it reports `held_insufficient_capacity`. Preview capacity is advisory and conservative, never a reservation.
344
417
 
345
418
  Managed CPU/unified-memory tasks reserve estimated additional model-file and known F16 KV bytes
346
419
  across both backends. Verified runner footprints replace that estimate only for the same backend,
347
420
  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
421
+ avoid double-counting existing allocations. The reservation is rechecked after transition locking
422
+ without waiting while holding the backend lock; an increased requirement that no longer fits the
423
+ 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
424
  VRAM discounts the estimated host-memory requirement by the bytes the GPU can hold. Missing VRAM
352
425
  telemetry reserves the full estimated footprint in host RAM. The governor cannot constrain external
353
426
  allocations or preempt an already-running model.
@@ -418,35 +491,18 @@ cold-load cost do not poison the comparison. It requires more than a 10% advanta
418
491
  break a tie before the sample threshold. Quality routing, explicit model selection, and session
419
492
  affinity do not follow the latency loop.
420
493
 
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.
494
+ The same selection function supplies preview receipts and managed task execution. This keeps advertised placement and actual request routing aligned.
423
495
 
424
496
  Raw proxy traffic always uses the primary upstream. For setup and runtime verification, see
425
497
  [Run models on CPU and GPU](CPU_GPU_ROUTING.md).
426
498
 
427
499
  ## MCP tool flow
428
500
 
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).
501
+ The MCP server keeps general model work (`run_task`), file-backed research (`delegate_research`, a
502
+ confined adapter subprocess), and destructive lifecycle operations (`ollama_manage`,
503
+ `ollama_delete`) in separate tools, so `run_task` never acquires file access and lifecycle
504
+ operations are not hidden inside a generic action. The canonical tool table, schemas, and security
505
+ annotations are in the [MCP server reference](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#tools).
450
506
 
451
507
  ## Grounded research flow
452
508
 
@@ -499,8 +555,8 @@ Adapter cache totals remain null if any turn is unreported, with partial-report
499
555
  See [Ollama usage](https://docs.ollama.com/api/usage) and
500
556
  [the pinned prefix-cache implementation](https://github.com/ggml-org/llama.cpp/blob/74a7c897f049c17e7080423aa2111776eff6ebbf/tools/server/server-context.cpp#L3201).
501
557
 
502
- For adapter implementation, defaults, and measured caveats, see the
503
- [local adapter reference](../benchmark/local/docs/07-adapter-contracts.md).
558
+ Adapter implementations and defaults live in
559
+ [`packages/mcp/src/research/`](../packages/mcp/src/research/).
504
560
 
505
561
  ## Context and token boundary
506
562
 
@@ -519,7 +575,7 @@ flowchart LR
519
575
 
520
576
  Raw source, images, and embedding vectors do not need to enter the frontier model's context.
521
577
  Embedding vectors are withheld by default because they are large and not human-readable. For the
522
- measured accounting, see [Token economics](ECONOMICS.md).
578
+ measured accounting, see [Token economics](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#token-economics).
523
579
 
524
580
  ## State and failure behavior
525
581
 
@@ -543,6 +599,14 @@ expected revision. Warming uses ordinary admission and fit checks; omitted resid
543
599
  a finite measured policy. See [Scope history and model warming](SCOPES_AND_WARMING.md) for the
544
600
  public contract and configured limits.
545
601
 
602
+ In `serve`, mutating passthrough traffic shares the primary transition lock and receives
603
+ host-pressure gating, while managed tasks also reserve forecast memory. Direct Ollama callers bypass
604
+ these controls. FreeLlama cannot preempt inference or constrain other processes. A configured but
605
+ unreachable CPU backend makes managed catalog discovery fail closed; raw primary passthrough remains
606
+ usable. Runtime feedback is task-specific, token-normalized, and warm-only: it can steer unpinned
607
+ `fastest` or `balanced` work after three samples per backend and a greater-than-10% advantage, but
608
+ cannot change CPU eligibility or steer quality routing.
609
+
546
610
  The design fails closed when it cannot establish a required contract. Examples include an
547
611
  unreachable configured backend, an unknown confidence grade, a policy without qualified models, an
548
612
  explicit model that is not installed, or a task that exceeds the advertised context window.
package/docs/CLI.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The `freellama` command starts and inspects the local management layer that agents use to offload
4
4
  work. It exposes diagnostics, model routing, managed execution, resource controls, benchmarking,
5
- and Ollama-compatible passthrough. Use the [README quick start](../README.md#quick-start) for first
5
+ and Ollama-compatible passthrough. Use the [README CLI section](https://github.com/bgauryy/FreeLlama/blob/main/README.md#or-use-the-cli) for first
6
6
  use and this reference to look up commands and controls.
7
7
 
8
8
  ## Choose a command
@@ -12,13 +12,12 @@ flowchart TD
12
12
  Q{"What do you need?"}
13
13
  Q -->|"Prepare first use"| I["init"]
14
14
  Q -->|"Inspect this machine"| D["doctor or machine"]
15
- Q -->|"Inspect or choose a model"| M["models, route, or recommend"]
16
- Q -->|"Execute a managed request"| T["session, natural-route, or task"]
15
+ Q -->|"Inspect or choose a model"| M["models or route"]
16
+ Q -->|"Execute a managed request"| T["session or task"]
17
17
  Q -->|"Run the control plane"| S["serve"]
18
18
  Q -->|"Preserve only Ollama APIs"| P["proxy"]
19
- Q -->|"Measure or compare"| B["bench-all, run, or eval"]
20
- Q -->|"Create a routing policy"| E["policy-from-eval"]
21
- Q -->|"Compare CLI and MCP"| L["tools"]
19
+ Q -->|"Measure models"| B["bench-all"]
20
+ Q -->|"Write a routing policy"| PE["policy from-eval"]
22
21
  ```
23
22
 
24
23
  | Command | Purpose | Needs `freellama serve` |
@@ -35,17 +34,12 @@ flowchart TD
35
34
  | `scope` | Create, inspect, fork, or delete bounded message history | Yes |
36
35
  | `warm` | Warm an installed model through managed admission | Yes |
37
36
  | `route` | Choose a model and request profile without executing it | Yes |
38
- | `recommend` | Return an installed route or a reviewed installation plan | Yes |
39
- | `natural-route` | Convert natural language to a route intent locally, then route it | Yes |
40
37
  | `task` | Route and execute one nonstreaming task | Yes |
41
38
  | `jobs` | List, inspect, cancel, or remove deferred tasks and warming operations | Yes |
42
39
  | `proxy` | Run only the Ollama-compatible retry and telemetry sidecar | No |
43
40
  | `bench-all` | Measure installed models by capability group | No |
44
- | `policy-from-eval` | Generate policy from quality-evaluation pass rates | No |
45
- | `tools` | Print MCP tools and their CLI equivalents | No |
41
+ | `policy from-eval` | Write a task policy (`platform.toml`) from a quality-evaluation aggregate and the installed tags | No |
46
42
  | `doctor` | Inspect Ollama, hardware, versions, and effective settings | No |
47
- | `run` | Run a frozen suite against one Ollama build | No |
48
- | `eval` | Compare the same frozen suite against stock and candidate builds | No |
49
43
 
50
44
  Run `npx @octocodeai/freellama <command> --help` for every accepted flag and enum value. The executable's help
51
45
  is authoritative; this page explains how the commands fit together.
@@ -53,13 +47,16 @@ is authoritative; this page explains how the commands fit together.
53
47
  ## Start the control plane
54
48
 
55
49
  ```bash
56
- npx @octocodeai/freellama serve --recommendation-catalog recommendations.example.toml
50
+ npx @octocodeai/freellama serve
57
51
  ```
58
52
 
59
53
  The default listener is `http://127.0.0.1:11435`, and the default Ollama upstream is
60
54
  `http://127.0.0.1:11434`. Use `--listen` and `--upstream` to change them. Nonloopback listeners
61
55
  require `--allow-remote` and a token from `--auth-token-file` or
62
- `FREELLAMA_AUTH_TOKEN_FILE`. Authentication applies to managed and passthrough routes.
56
+ `FREELLAMA_AUTH_TOKEN_FILE`. Authentication applies to managed and passthrough routes. The token
57
+ file must be a regular file, not a symlink, and hold one token of at least 32 bytes; surrounding
58
+ whitespace is trimmed. On Unix it must also be owner-only (mode 0600). Windows file permissions
59
+ (ACLs) are not checked, so protect the file with your user profile's permissions there.
63
60
 
64
61
  `serve` persists bounded adaptive feedback under the platform data directory by default. Override
65
62
  the path with `--feedback-file`; use `--ephemeral-feedback` only for disposable runs. See the
@@ -98,8 +95,8 @@ placement.
98
95
 
99
96
  ### Bound admission
100
97
 
101
- `--max-concurrent-tasks` is the primary/GPU cost budget, not a request count. Without a flag,
102
- environment variable, or runtime-file value it defaults to 2 units per `OLLAMA_NUM_PARALLEL` slot of
98
+ `--max-concurrent-tasks` is the primary/GPU cost budget, not a request count. Without a flag or
99
+ runtime-file value it defaults to 2 units per `OLLAMA_NUM_PARALLEL` slot of
103
100
  the Ollama server (read from its process environment where visible; Ollama's own default is 1, so 2).
104
101
  `freellama config` shows the effective value and where it came from.
105
102
  `--cpu-max-concurrent-tasks` controls the independent CPU pool and defaults to 1. Default base costs
@@ -133,19 +130,27 @@ context sizing, can also live in a runtime file (`--runtime-config`) that `serve
133
130
  changes. See [Monitoring and live tuning](MONITORING.md). The standalone
134
131
  `proxy` command keeps its cap opt-in for compatibility.
135
132
 
136
- The local host-pressure gate defaults to holding below 15% available RAM and resuming above 20%
137
- after two healthy samples; minimum reserves are 1 GiB and 2 GiB, respectively. Tune the percentages
138
- with `--resource-hold-available-percent` and `--resource-resume-available-percent`; the hold value
139
- must be lower than the resume value, and neither can exceed 100. Health reports the policy, sampled
140
- signals, unknown measurements, and reserved memory. These flags do not change Ollama or OS settings.
141
-
142
- The reserve applies to every new managed load, not only to the pressure gate: a task is admitted
143
- when effective available RAM covers already-reserved bytes, the task's estimated bytes, and the
144
- reserve (the hold reserve normally; the larger resume reserve while capacity is recovering).
145
- Effective available RAM is free memory plus a bounded reclaimable estimate, so it can be far lower
146
- than the OS "free" percentage. A refusal reports `assessment.status: "held_insufficient_capacity"`
147
- with `required_with_reserve_bytes` and `effective_available_bytes`; free memory, choose a smaller
148
- model, or lower the percentages deliberately.
133
+ The local host-pressure gate reports low available RAM below 15% and clears it above 20% after two
134
+ healthy samples; minimum reserves are 1 GiB and 2 GiB, respectively. Tune the percentages with
135
+ `--resource-hold-available-percent` and `--resource-resume-available-percent`; the hold value must be
136
+ lower than the resume value, and neither can exceed 100. Health reports the policy, sampled signals,
137
+ unknown measurements, and reserved memory. These flags do not change Ollama or OS settings.
138
+
139
+ On macOS, low available RAM is advisory and never refuses a task. Effective available RAM is free
140
+ memory plus a bounded reclaimable estimate, so it can be far lower than what the OS can actually
141
+ reclaim. When it does not cover already-reserved bytes, the task's estimated bytes, and the reserve,
142
+ FreeLlama first unloads idle unpinned runners, then dispatches anyway: the receipt reports
143
+ `status: "admitted_low_memory_estimate"` and `assessment.memory_advisory: "below_reserve"` with
144
+ `required_with_reserve_bytes` and `effective_available_bytes`. Ollama and the OS decide whether the
145
+ load fits. On Linux, Windows, and other platforms, where available RAM already counts reclaimable
146
+ cache (and is the hard cap in a container), the same shortfall unloads idle runners and then holds the
147
+ new load with `held_insufficient_capacity` until capacity returns, refusing with 503 at its deadline.
148
+ OS memory pressure holds work on every platform. Active swapping and low RAM hold new loads only:
149
+ an already-resident runner adds no memory and stays admitted. CPU-load (one-minute load at or above
150
+ 1.5 per logical CPU) and thermal-throttling holds apply to CPU-assigned work and to cold loads, which
151
+ decode weights on the host cores and add a new heat source; a bounded request on a runner already
152
+ resident on the GPU neither waits for the cores nor cools the package by waiting, so it proceeds. The receipt's `resource_admission.assessment.held_by`
153
+ lists the holds that applied to the request.
149
154
  Both `serve` and `proxy` accept `--resource-telemetry-policy`:
150
155
 
151
156
  - `require-memory` (default): wait or refuse local inference when available RAM is unknown, including
@@ -163,7 +168,7 @@ its phase and omits estimates that were not obtained.
163
168
 
164
169
  See [resource admission](ARCHITECTURE.md#managed-task-execution) for scope and limitations.
165
170
 
166
- `route`, `recommend`, and `task` accept
171
+ `route` and `task` accept
167
172
  `--execution-preference auto|prefer-cpu|prefer-gpu`. This is a fallback-capable hint over models
168
173
  already assigned by the operator; it never rewrites raw passthrough and never makes an ineligible
169
174
  model eligible. Preview the route and inspect the `execution` receipt to confirm whether the hint
@@ -203,13 +208,6 @@ without them it falls back to capability/context-compatible models and reports l
203
208
  and missing quality evidence. `quality` requires a policy unless you supply an explicit model.
204
209
  An explicit minimum-confidence gate still refuses insufficient evidence in every objective.
205
210
 
206
- `recommend` is side-effect-free. If no installed model qualifies, it can return an installation
207
- plan from the reviewed recommendation catalog, but it never pulls a model.
208
-
209
- `natural-route` asks the configured local intent model to produce structured intent, validates that
210
- intent, and then invokes the same deterministic router as `route`. It does not let the intent model
211
- choose the final model directly.
212
-
213
211
  ## Execute tasks
214
212
 
215
213
  The prompt for `task` is positional:
@@ -233,6 +231,8 @@ Useful task options include:
233
231
  - `--priority interactive|normal|background` for fair admission scheduling.
234
232
  - `--max-wait-seconds` for a shorter admission/resource wait budget.
235
233
  - `--timeout-seconds` for a total deadline including discovery, waiting, loading, and inference.
234
+ - `--stop-on-repetition` to stream the task and stop once the output repeats itself, keeping all
235
+ generated text.
236
236
  - `--defer` to return a job ID immediately.
237
237
 
238
238
  Inspect deferred work with `jobs`, retrieve a result with `jobs --id <uuid>`, and cancel one task
@@ -266,7 +266,7 @@ benchmark record for the selected model.
266
266
 
267
267
  ```mermaid
268
268
  flowchart LR
269
- Q["Quality evaluation aggregate"] --> P["policy-from-eval"]
269
+ Q["Quality evaluation aggregate"] --> P["freellama policy from-eval"]
270
270
  P --> PF["platform.toml"]
271
271
  T["Local throughput benchmark"] --> BR["benchmark-report.json"]
272
272
  PF --> S["freellama serve"]
@@ -274,36 +274,64 @@ flowchart LR
274
274
  S --> C["Medium confidence for configured, measured routes"]
275
275
  ```
276
276
 
277
- Generate the policy from correctness data and the benchmark report from local runtime data:
277
+ Generate the policy from correctness data with `policy from-eval` and the benchmark report from
278
+ local runtime data:
278
279
 
279
280
  ```bash
280
- npx @octocodeai/freellama policy-from-eval \
281
- --aggregate benchmark/local/results/MODEL/aggregate.json \
281
+ npx @octocodeai/freellama policy from-eval \
282
+ --aggregate aggregate.json \
282
283
  --task coding \
283
284
  --min-pass 0.8 \
284
285
  --out platform.toml
285
286
 
286
287
  npx @octocodeai/freellama bench-all --output benchmark-report.json
287
- npx @octocodeai/freellama serve --recommendation-catalog recommendations.example.toml
288
+ npx @octocodeai/freellama serve
288
289
  ```
289
290
 
290
- `serve` discovers `platform.toml` and `benchmark-report.json` in its working directory. Explicit
291
- `--policy-file` and `--benchmark-report` values take precedence.
291
+ `serve` resolves each file in this order: the explicit flag, its environment variable, the working
292
+ directory, then the per-user config directory (`$XDG_CONFIG_HOME/freellama/` or
293
+ `~/.config/freellama/`; `%APPDATA%\FreeLlama\` on Windows).
292
294
 
293
- Replace `MODEL` with the directory containing your completed quality-evaluation aggregate.
295
+ | File | Flag | Environment variable | Discovered name |
296
+ |---|---|---|---|
297
+ | Task policy | `--policy-file` | `FREELLAMA_POLICY_FILE` | `platform.toml` |
298
+ | Benchmark report | `--benchmark-report` | `FREELLAMA_BENCHMARK_REPORT` | `benchmark-report.json` |
294
299
 
295
- `policy-from-eval` reads `pass_at_1`, not the throughput produced by `bench-all`. It refuses expired
296
- aggregates and fewer than three trials unless `--allow-smoke` is explicit, and it skips models that
297
- are not installed. This prevents speed data from being mislabeled as quality evidence.
300
+ A task policy file has this shape:
298
301
 
299
- ## Compare the CLI and MCP surfaces
302
+ ```toml
303
+ schema_version = 1
300
304
 
301
- ```bash
302
- npx @octocodeai/freellama tools
305
+ [policies.code_repair]
306
+ qualified_models = ["qwen3.8:27b-mlx"] # best first; quality-qualified only
307
+
308
+ # Optional request defaults for one exact tag on this task: think and num_predict (>= 1).
309
+ [policies.code_repair.model_options."qwen3.8:27b-mlx"]
310
+ think = false
311
+ num_predict = 512
303
312
  ```
304
313
 
305
- The command prints the maintained parity map. MCP-only operations are `delegate_research` and the
306
- online `models { view: "library" }` view. CLI-only operations include `serve`, `proxy`,
307
- `recommend`, `natural-route`, `bench-all`, `policy-from-eval`, `run`, and `eval`.
314
+ `serve` rejects unknown fields, including `num_ctx`: context size is routing-owned, so set
315
+ `context_tokens` per request instead. Caller request options win over `model_options`, and
316
+ `think = true` applies only to models with the thinking capability. See the annotated
317
+ [platform.example.toml](https://github.com/bgauryy/FreeLlama/blob/main/platform.example.toml).
318
+
319
+ The MCP server autostarts `serve` with its own environment and an arbitrary working directory, so
320
+ put a machine-wide policy in the config directory or set the variables in the MCP client's `env`.
321
+ `serve` prints each file it picked up.
322
+
323
+ Replace `MODEL` with the directory containing your completed quality-evaluation aggregate.
324
+
325
+ `policy from-eval` reads `pass_at_1`, not the throughput produced by `bench-all`. It refuses
326
+ expired aggregates and fewer than three trials unless `--allow-smoke` is explicit, and it skips
327
+ models that are not installed on `--ollama-endpoint` (default `FREELLAMA_OLLAMA_ENDPOINT`, then
328
+ `http://127.0.0.1:11434`). This prevents speed data from being mislabeled as quality evidence.
329
+ It accepts the task kinds `route` accepts, with `-` or `_` (`code-repair` or `code_repair`), writes
330
+ to stdout unless `--out` is given, and reports a refusal as one `error: ...` line with exit status 1.
331
+
332
+ ## Compare the CLI and MCP surfaces
333
+
334
+ MCP-only operations are `delegate_research` and the online `models { view: "library" }` view.
335
+ CLI-only operations include `serve`, `proxy`, `bench-all`, `policy from-eval`, and `auth-token`.
308
336
 
309
- For the MCP tool contracts, read the [MCP package reference](../packages/mcp/README.md).
337
+ For the MCP tool contracts, read the [MCP package reference](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md).
@@ -9,7 +9,7 @@ memory checks, and model transitions for each backend; the operator configures t
9
9
  eligible tags. A configured CPU backend is intent: inspect the placement observation before
10
10
  treating it as proof of CPU execution.
11
11
 
12
- This configuration is useful for embeddings, intent interpretation, and other small helper models.
12
+ This configuration is useful for embeddings, short classification, and other small helper models.
13
13
  Benchmark large CPU workloads before adopting them. Apple silicon shares memory bandwidth; systems
14
14
  with discrete GPUs have different contention and transfer costs, so neither result transfers
15
15
  without measurement.
@@ -28,7 +28,9 @@ machine-specific:
28
28
 
29
29
  `doctor` reports `machine.memory_bytes` on macOS, Linux, and Windows. It reports
30
30
  `machine.unified_memory_bytes` only when unified memory is known; that compatibility field is not a
31
- VRAM estimate on discrete-GPU hosts. Model-library fit is therefore a host-memory preflight, and
31
+ VRAM estimate on discrete-GPU hosts. `machine.gpu` names the accelerator when the OS reports it
32
+ (Apple model and core count, or NVIDIA name and memory on Linux), and `performance_cpus` /
33
+ `efficiency_cpus` split hybrid CPUs on macOS. These are identity facts, not placement proof. Model-library fit is therefore a host-memory preflight, and
32
34
  actual accelerator placement must come from Ollama's resident-runner report.
33
35
 
34
36
  An agent can choose `auto`, `prefer_cpu`, or `prefer_gpu`, but it cannot invent topology. The
@@ -352,7 +354,6 @@ and `execution.lifecycle`; a failed unload is reported without discarding the co
352
354
  Prefer the following assignments:
353
355
 
354
356
  - Small embedding models
355
- - Lightweight intent models
356
357
  - Short extraction or classification helpers with measured CPU behavior
357
358
 
358
359
  Benchmark these assignments before adopting them: