@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.
package/README.md CHANGED
@@ -9,58 +9,22 @@ evidence for the calling agent to inspect.
9
9
 
10
10
  The agent owns prompts, task dependencies, and answer verification. The operator configures
11
11
  Ollama and model lifecycle permissions; Ollama performs inference. See
12
- [architecture](../../docs/ARCHITECTURE.md) for the full ownership boundary.
12
+ [architecture](https://github.com/bgauryy/FreeLlama/blob/main/docs/ARCHITECTURE.md) for the full ownership boundary.
13
13
  The server uses the official [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk).
14
14
 
15
15
  ## Understand the tools
16
16
 
17
- - `doctor`, `models`, `run_task`, `task_jobs`, `run_task_batch` — thin wrappers over the native NAPI bindings into the
18
- Rust core (`../rust-core/src/napi.rs`); no CLI subprocess, no reimplemented routing logic.
19
- `run_task { preview: true }` is the decision-only form and does not run inference.
20
- Preview and execution are separate calls: preview accepts routing fields only and rejects task
21
- payloads or runtime controls instead of silently ignoring them.
22
- `models { view: "library" }` queries the public `ollama.com` library (the former `search_models` tool).
23
- - `scope` — creates, inspects, forks, or deletes bounded process-local message history.
24
- - `warm_model` — warms an exact installed model through ordinary managed admission and placement.
25
- - `session` — creates and releases a bounded, idle-expiring model-affinity handle for related
26
- route/task calls. It does not store messages, prompt history, or Ollama's runner KV cache.
27
- - `ollama_manage`, `ollama_delete` — Ollama's HTTP API for lifecycle operations the routing layer
28
- doesn't cover.
29
- - `delegate_research` — offloads a grounded code-research question to a local model and returns a
30
- verdict computed from model evidence, successful tool calls, and question-shape heuristics.
31
- The verdict guides verification; it does not certify answer correctness.
32
-
33
- Use the smallest tool that owns the operation:
17
+ `doctor`, `models`, `run_task`, `task_jobs`, `scope`, and `session` call the Rust core through native NAPI bindings
18
+ (`packages/rust-core/src/napi.rs`), with no CLI subprocess and no routing decisions in TypeScript; the
19
+ TypeScript layer validates request shapes and derives presentation fields (see
20
+ [what the MCP layer computes](#what-the-mcp-layer-computes)). `run_task` has four modes: one task,
21
+ `tasks[]` (independent batch), `preview: true` (decision only, no inference), and `warm: true`
22
+ (load an exact installed model, no generation). Preview and execution are separate calls: preview
23
+ accepts routing fields only and rejects task payloads or runtime controls instead of silently
24
+ ignoring them. `ollama_manage` and `ollama_delete` call Ollama's HTTP API directly for lifecycle
25
+ operations the routing layer does not perform.
34
26
 
35
- ```mermaid
36
- flowchart TD
37
- Q{"What does the client need?"}
38
- Q -->|"Diagnose the local runtime"| D["doctor"]
39
- Q -->|"Inspect installed, resident, detailed, raw, or online models"| M["models"]
40
- Q -->|"Choose or execute one task"| R["run_task"]
41
- Q -->|"Inspect or cancel deferred work"| J["task_jobs"]
42
- Q -->|"Fan out independent tasks"| B["run_task_batch"]
43
- Q -->|"Keep/release related-task model affinity"| S["session"]
44
- Q -->|"Retain or fork message history"| H["scope"]
45
- Q -->|"Prepare runner residency"| W["warm_model"]
46
- Q -->|"Pull or stop a model"| O["ollama_manage"]
47
- Q -->|"Permanently remove a named model"| X["ollama_delete"]
48
- Q -->|"Ground an answer in workspace files"| G["delegate_research"]
49
- ```
50
-
51
- | Tool | Why it exists |
52
- |---|---|
53
- | `doctor` | Makes runtime, version, memory, and configuration drift visible before work starts. |
54
- | `models` | Separates installed, resident, detailed, raw, and public-library questions instead of guessing from model names. |
55
- | `run_task` | Applies the same deterministic routing, confidence, admission, and execution contract as the Rust control plane. |
56
- | `task_jobs` | Lists, retrieves, cancels, or removes a bounded process-local task submitted with `defer:true`. Removal stops active work first. |
57
- | `run_task_batch` | Executes only caller-declared independent tasks. Stable IDs, a bounded dispatcher, 3:2:1 fair priority classes, and per-item errors make fan-out inspectable rather than implicit. |
58
- | `session` | Lets an agent explicitly own the lifetime of a bounded affinity handle without misrepresenting it as conversation or KV storage. |
59
- | `scope` | Retains bounded message history with expected revisions and explicit history reads. |
60
- | `warm_model` | Loads an installed runner profile using the same memory, admission, placement, and job controls as task execution. |
61
- | `ollama_manage` | Exposes additive lifecycle operations that FreeLlama routing intentionally does not perform. |
62
- | `ollama_delete` | Keeps irreversible deletion separate and explicit so a client can guard it. |
63
- | `delegate_research` | Gives a local model bounded read-only tools and returns citations plus an independently computed verification verdict. |
27
+ Use the smallest tool that owns the operation; the canonical per-tool table is [Tools](#tools).
64
28
 
65
29
  ## Follow the agent workflow
66
30
 
@@ -79,7 +43,7 @@ submitted task; pass that UUID as `jobId` for every subsequent operation.
79
43
  Removal waits for local permits to be released before deleting the record. It returns the ID and
80
44
  terminal status; subsequent lookup returns `404`. It does not unload a shared Ollama model or
81
45
  prove that physical computation has stopped. Receipts are bounded and lost on server restart;
82
- see [retention and task states](../../docs/MONITORING.md#read-the-live-status).
46
+ see [retention and task states](https://github.com/bgauryy/FreeLlama/blob/main/docs/MONITORING.md#read-the-live-status).
83
47
 
84
48
  Follow this workflow. The server's initialization instructions carry a compressed form of the
85
49
  same contract (inventory first, preview semantics, evidence levels, ownership, and pull approval):
@@ -87,8 +51,7 @@ same contract (inventory first, preview semantics, evidence levels, ownership, a
87
51
  1. Start with `models {view:"installed"}`, then `models {view:"resident"}`. This gives a routing
88
52
  agent the smallest current inventory first.
89
53
  2. Call `doctor` only for runtime or configuration diagnosis. It returns `summary` by default;
90
- use `view:"scheduler"` for configured/snapshot scheduling evidence or `view:"full"` for the
91
- complete diagnostic. If Ollama is missing or unreachable, ask the operator to install or start it.
54
+ use `view:"status"` for live queues and limits or `view:"full"` for the complete diagnostic. If Ollama is missing or unreachable, ask the operator to install or start it.
92
55
  3. Classify the task. Offload embeddings, OCR/vision, bulk transforms, and sufficiently large
93
56
  grounded lookups; retain small lookups and high-stakes judgment in the calling agent.
94
57
  4. Prefer a qualified installed model and preview consequential work.
@@ -132,7 +95,41 @@ counts, placement, or unloading. It cannot prove research correctness, coding ju
132
95
  throughput, or fairness from one run. Check the returned confidence, policy evidence, and benchmark
133
96
  evidence before accepting a consequential answer.
134
97
 
135
- ### Measure avoided external cost
98
+ ### Token economics
99
+
100
+ Offloading keeps source material and intermediate tool output out of the calling agent's context;
101
+ the local model still spends tokens, power, and time. Per-call rows below come from one machine
102
+ (M4 Pro, 48 GB unified memory); `~` values are estimates.
103
+
104
+ | Work | Source tokens | Returned tokens | Preserved |
105
+ |---|---:|---:|---:|
106
+ | 6 grounded code questions | 59,208 | 1,742 | **97.1%** |
107
+ | 4 text embeddings (307 ms) | 17,600 | ~200 | **98.9%** |
108
+ | 1 image, OCR, byte-exact | 1,970 | 37 | **98.1%** |
109
+
110
+ A dated MCP-envelope audit (2026-09-03, `characters / 4` as a rough token estimate) measured the
111
+ duplicate text copy FreeLlama does not emit beside `structuredContent`: `doctor {view:"summary"}`
112
+ avoids ~3,064 chars, `doctor {view:"full"}` ~10,651, `models {view:"raw", limit:1}` ~404. These
113
+ are **not billed-token savings** unless the host would otherwise feed both representations to a
114
+ model. The tool schema itself is per-turn rent, bounded by the
115
+ [protocol context-budget test](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/test/integration/protocol.test.ts);
116
+ read documentation resources on demand and filter unneeded tools where the client supports it.
117
+
118
+ | Cost side | Measured |
119
+ |---|---|
120
+ | Grounded question latency | **7–62 s** vs ~1 s for a frontier model that already holds the file |
121
+ | Scaling | turn-dominated: `seconds ≈ 9.8 × tool_calls`, correlation 0.811 over 60 runs |
122
+ | Break-even | past ~1k tokens of source the token maths wins; below that, read the file directly |
123
+ | Judgment ceiling | ~67% accurate, in the same confident tone as the ~99% case |
124
+
125
+ Ollama prefix-cache reuse works on this path (a warm 2,462-token prefix re-prefilled in ~281 ms
126
+ versus ~18.6 s cold, and survived an interleaved conversation), so per-turn cost is new-token
127
+ prefill plus generation. Context compaction rewrites old observations and invalidates the cache
128
+ from that point; leave headroom (for example `OLLAMA_KV_CACHE_TYPE=q8_0`) so compaction stays rare.
129
+ Session-scale projections depend on provider, caching, and pricing; measure the client's actual
130
+ transcript before claiming a token or billing reduction.
131
+
132
+ #### Avoided external cost
136
133
 
137
134
  Every successful `run_task`, batch item, and `delegate_research` result includes `telemetry.local`
138
135
  when Ollama reports input/output token counts. To add `telemetry.externalEquivalent`, configure one
@@ -150,13 +147,28 @@ excludes provider caching and reasoning-token differences, retries, local electr
150
147
  amortization; it is not a provider bill or net-profit calculation. Partial or invalid rate-card
151
148
  configuration stops the MCP server at startup instead of emitting a misleading estimate.
152
149
 
153
- ### Route images and OCR
150
+ ### Route images
154
151
 
155
152
  Use `run_task` for supplied image bytes, not `delegate_research`. Preview
156
153
  `{task:"vision", requiredCapabilities:["vision"], preview:true}` before a consequential image
157
154
  task. Execute separately with a prompt and base64 `images` values without data-URI prefixes. The
158
- `images` field requires an explicitly trialed vision model; inspect the execution receipt for
159
- admission and observed placement.
155
+ `images` field needs an explicit trialed vision `model`, or an operator `[policies.vision]` entry in
156
+ the serve policy file; without either the core refuses rather than trusting a `vision` capability
157
+ tag. Inspect the execution receipt for admission and observed placement.
158
+
159
+ Use the prompt the model documents; dedicated OCR models expect their own task prompts.
160
+ FreeLlama adds no stop sequence or other option because of which model was chosen.
161
+
162
+ Some models repeat their answer until the output cap. Set `stopOnRepetition:true` to stream the
163
+ task and stop once the output repeats itself; everything generated is kept, and the result
164
+ carries `output_check: {stopped_early: true, stop_reason, unique_prefix_chars, ...}`. Without it, a
165
+ length-capped answer that ends in a loop gets `output_check: {repetition_loop: true,
166
+ unique_prefix_chars, period_chars}`. Either way the MCP answer text shows one copy and the
167
+ untrimmed output stays in `structuredContent.response`.
168
+
169
+ Routing learns from these loops, not from model names: a model that keeps looping on a task kind
170
+ (at least two loops in at most twice as many runs, listed as `observed_loops` by `models`) ranks
171
+ last for automatic selection of that task. An explicit `model` or an operator policy still wins.
160
172
 
161
173
  FreeLlama can prove that it routed and ran a request. It cannot infer OCR or visual-reasoning
162
174
  quality from a capability tag, a model name, or GPU placement. Quality depends on the exact
@@ -164,9 +176,8 @@ installed model build, prompt and decoding settings, context/output budget, and
164
176
  memory and accelerator performance. Validate representative held-out images on the target machine
165
177
  and supply policy/benchmark evidence before automatically accepting a quality-sensitive result.
166
178
 
167
- The caller owns task decomposition and concurrent submission. The operator owns endpoints, exact
168
- CPU assignments, runtime settings, and lifecycle approval. FreeLlama owns qualification, managed
169
- placement and admission. Ollama and the OS/driver own runner loading and physical CPU/GPU execution.
179
+ Ownership of decomposition, CPU assignments, placement, and physical execution follows the
180
+ [responsibility boundary](https://github.com/bgauryy/FreeLlama/blob/main/docs/ARCHITECTURE.md#responsibility-boundary).
170
181
 
171
182
  ## Follow the architecture
172
183
 
@@ -188,50 +199,33 @@ flowchart TD
188
199
  `doctor`, the installed/resident model views, and `run_task` use the NAPI binding instead of a CLI
189
200
  subprocess. Direct lifecycle and no-serve model views use Ollama HTTP. `delegate_research` starts a
190
201
  bounded adapter against an allowlisted workspace; each adapter model turn re-enters managed
191
- `run_task` as `coding`, so it shares routing, admission, and placement evidence. Routing logic is
192
- not duplicated in TypeScript.
193
-
194
- ## Read packaged documentation through MCP
195
-
196
- The published MCP package includes every Markdown file from the repository `docs/` directory. The
197
- repository directory remains the source of truth; the package build copies it into `docs/` and
198
- creates `docs/INDEX.md`.
202
+ `run_task` as `coding`, so it shares routing, admission, and placement evidence. The adapters are
203
+ TypeScript in `src/research/`, compiled to `dist/research/{bash-agent,octocode-agent}.js`, and run as
204
+ `node <file>` in their own process group with the server's Node.js; no Python is required.
199
205
 
200
- MCP clients can list resources and read `freellama://docs/index`, then fetch exactly one relevant
201
- guide such as `freellama://docs/PRODUCTION`, `freellama://docs/CLI`, or
202
- `freellama://docs/OLLAMA_SYSTEM_OPTIMIZATION`. Resources are deliberately lazy: do not load every
203
- guide into an agent context. The server fails on startup if the generated index is absent, and the
204
- release verifier checks that the packed documents match the root `docs/` set.
206
+ ### What the MCP layer computes
205
207
 
206
- ## Build
208
+ Model selection, confidence floors, admission, and placement are decided only in the Rust core.
209
+ The TypeScript server adds a small set of derived fields on top of core results:
207
210
 
208
- Build the native addon from the repository root and this package in place.
211
+ - request-shape validation (preview-only fields, embedding versus chat payloads, scope pairs);
212
+ - answer text, embedding summaries, and optional avoided-cost telemetry for `run_task`;
213
+ - `models {view:"resident"}` placement labels: `gpu_percent` from `resident_vram / resident_size`,
214
+ a processor label (core-observed processor first, otherwise derived from that ratio), and
215
+ mismatch or partial-offload warnings;
216
+ - library-tag `fitsInMemory` against a conservative host-memory budget and a trial candidate;
217
+ - the `delegate_research` verification verdict from per-model evidence and tool-call facts.
209
218
 
210
- ```bash
211
- # From the repository root (yarn workspaces — one install for every package)
212
- yarn install
213
- yarn build
214
- ```
219
+ ## Read packaged documentation through MCP
215
220
 
216
- `yarn build` writes **one** MCP file, `packages/mcp/dist/index.js` (shebang, executable). During
217
- checkout development it loads `native/freellama.<triple>.node`. Published installs resolve the
218
- matching `@octocodeai/freellama-native-<target>` optional package instead, so the base MCP package remains
219
- portable. Research adapters are copied into `adapters/` for packed installs.
221
+ The published MCP package includes the Markdown guides from the repository `docs/` directory.
222
+ The repository directory remains the source of truth; the package build copies it into `docs/`.
220
223
 
221
- Piecewise, if you are iterating on one layer:
224
+ MCP clients can list resources and read `freellama://docs/index` (the repository `docs/README.md`),
225
+ then fetch exactly one relevant guide such as `freellama://docs/PRODUCTION` or
226
+ `freellama://docs/CLI`. Resources are deliberately lazy: do not load every guide into an agent
227
+ context. The server fails on startup if the index is absent.
222
228
 
223
- ```bash
224
- # 1. Native addon → packages/mcp/native/freellama.<triple>.node
225
- yarn build:native
226
-
227
- # 2. This server → dist/index.js via esbuild (then copies the research adapters into adapters/)
228
- yarn workspace @octocodeai/freellama-mcp-server build
229
- ```
230
-
231
- `yarn start` needs `dist/index.js` and the compiled `.node` addon — `yarn build` from the repository
232
- root produces both in a checkout. `dist/index.js` loads `native/index.js`, which loads a local addon
233
- first and then a matching optional platform package. The `.node` binary is gitignored (a build
234
- artifact); `native/index.js` and `native/index.d.ts` are hand-written and checked in.
235
229
 
236
230
  ## Run
237
231
 
@@ -248,6 +242,8 @@ node packages/mcp/dist/index.js
248
242
  ```
249
243
 
250
244
  The server speaks MCP over stdio — configure it in your MCP client, do not run it interactively.
245
+ At launch it starts `freellama serve` in the background when the default endpoint does not answer;
246
+ see `FREELLAMA_MCP_AUTOSTART_SERVE` in [Configuration](CONFIGURATION.md#environment-variables).
251
247
 
252
248
  **Claude Desktop (`claude_desktop_config.json`):**
253
249
 
@@ -264,37 +260,17 @@ The server speaks MCP over stdio — configure it in your MCP client, do not run
264
260
 
265
261
  **Cursor / other clients** — use the same `command`/`args` shape in their MCP server config.
266
262
 
267
- ## Test
268
-
269
- Vitest, in three tiers (all TypeScript, under `test/`):
270
-
271
- | Tier | Command (from this package) | Checks | Needs |
272
- |---|---|---|---|
273
- | `test/unit/` | `yarn test` (watch: `yarn test:watch`) | pure functions straight from `src/*.ts` — no build step, this is the TDD loop | nothing, ~0.5s |
274
- | `test/integration/` | `yarn test:integration` | the built server over the real MCP protocol: tool contract, structured content, guardrails; rebuilds `dist/` itself | Ollama at `FREELLAMA_OLLAMA_ENDPOINT` (default :11434) |
275
- | `test/e2e/` | `yarn test:e2e` | every tool against the live system: real routing/execution, pull → delete round trip (net-zero), a real delegated research run | serve + Ollama + models, ~40s |
276
-
277
- The same commands work from the repository root (`yarn test` there also runs the CLI package's tests).
278
- The integration/e2e tiers fail fast with a readable message when Ollama is down, and the lifecycle
279
- test refuses to delete a model already installed on the test system.
280
-
281
- For default-endpoint autostart, a spawn failure, early exit, or readiness timeout rejects the
282
- request while leaving the MCP transport available for diagnosis or retry. Autostart does not apply
283
- to an explicit non-default endpoint; see `FREELLAMA_MCP_AUTOSTART_SERVE` below.
284
-
285
263
  ## Tools
286
264
 
287
265
  | Tool | Needs `freellama serve`? | What it does |
288
266
  |---|---|---|
289
- | `doctor` | No | Runtime/configuration diagnostic. `summary` (default) returns endpoint, version, resident count, host/profile signals, and next step; `scheduler` adds configured/snapshot admission data; `config` returns categorized settings; `full` adds all non-duplicated diagnostics; `status` returns serve's live view (per-backend queues, current and adaptive limits, circuit breakers, loaded models, host memory, Ollama's effective settings, today's usage); `usage` returns task and token totals per day and model (`days`, default 7). The report distinguishes an observed same-user macOS process from configuration hints and never claims remote process visibility. |
267
+ | `doctor` | No (except `status`/`usage`) | Runtime/configuration diagnostic. Target another Ollama with `ollamaEndpoint` and serve with `serveEndpoint`. `summary` (default) returns endpoint, version, resident count, host/profile signals, and next step; `full` adds all non-duplicated diagnostics, including admission and categorized Ollama settings; `status` returns serve's live view (per-backend queues, current and adaptive limits, circuit breakers, loaded models, host memory, Ollama's effective settings, today's usage); `usage` returns task and token totals per day and model (`days`, default 7). The report distinguishes an observed same-user macOS process from configuration hints and never claims remote process visibility. |
290
268
  | `models` | `installed` (default) and `resident` do; `detail`/`raw`/`library` don't | Views: `installed` (capabilities, use explanations, derived `model_type`, VRAM, context, policy_rank), `resident` (loaded now + managed GPU/CPU split), `detail` (one model, maximum context), paged `raw` (`GET /api/tags`), `library` (two-step ollama.com search: omit `model` for families, pass `model:"<family>"` for all tags/`fitsInMemory`). `includeLibrary:true` enriches installed/detail views with sourced public guidance; `includeReadme:true` returns bounded README text in library step 2 or enriched detail. |
291
- | `run_task` | Yes | **Routes or executes** a chat/generate/embed call. `preview: true` accepts routing fields only and returns a decision without generation. Execution omits preview and supplies the payload. Embedding results withhold raw vectors by default (`returnEmbeddings: true` to get them) |
269
+ | `run_task` | Yes | **Routes or executes** a chat/generate/embed call. `preview: true` accepts routing fields only and returns a decision without generation. Execution omits preview and supplies the payload. Embedding results withhold raw vectors by default (`returnEmbeddings: true` to get them). `tasks: [{id, independent:true, task}]` (max 64, `maxParallelism` bounds fan-out) runs a batch whose nested `task` takes the same fields; it is not a dependency scheduler. `warm: true` warms an exact installed `model` through managed admission with residency/profile controls and optional `defer:true`. |
292
270
  | `scope` | Yes | Creates, inspects, forks, or deletes process-local message history; history inclusion requires `includeMessages:true`. |
293
- | `warm_model` | Yes | Warms an exact installed model through managed admission; accepts residency/profile controls and optional `defer:true`. |
294
- | `session` | Yes | Creates or releases model affinity without storing messages or KV. |
271
+ | `session` | Yes | Creates, deletes, or kills model affinity without storing messages or KV; `kill` cancels the session's in-flight work. |
295
272
  | `task_jobs` | Yes | Inspects, cancels, or removes a deferred task or warming operation. |
296
- | `run_task_batch` | Yes | Executes only typed `{id, independent:true, task}` items. The nested `task` exposes the same task, routing, payload, and runtime controls as `run_task`; `maxParallelism` bounds fan-out. It is not a dependency graph scheduler. |
297
- | `ollama_manage` | No (direct to Ollama) | `action: "pull"` downloads a model; `action: "stop"` force-unloads it. Both additive and idempotent |
273
+ | `ollama_manage` | No (direct to Ollama) | `action: "pull"` downloads a model (additive); `action: "stop"` force-unloads it. Both are idempotent |
298
274
  | `ollama_delete` | No (direct to Ollama) | **Destructive**: permanently removes a model. Call only on an explicit human instruction naming the exact model |
299
275
  | `delegate_research` | Yes (and spawns the adapter) | Answers a grounded question from files under `workspacePath`; managed coding turns return placement receipts, citations, and an independent verification verdict |
300
276
 
@@ -305,21 +281,22 @@ Use `models {view:"installed", includeLibrary:true}` to enrich each installed mo
305
281
  Website access is optional for installed/detail views. Public guidance requires a matching exact tag
306
282
  and digest prefix; local capabilities remain authoritative and benchmark/policy evidence stays separate.
307
283
  Family claims have source excerpts and fetch dates, and lookup failures retain local inventory.
308
- Search reports `cloudAvailable` and `cloudOnly:null`; inspect exact tags to establish local availability.
309
- See [Ollama model metadata](../../docs/MODEL_METADATA.md) for response fields, lookup states, cache bounds,
284
+ Search reports `cloudAvailable` (a cloud variant exists), not whether a family is cloud-only; inspect
285
+ exact tags to establish local availability.
286
+ See [Model metadata](https://github.com/bgauryy/FreeLlama/blob/main/docs/MODEL_SELECTION.md#model-metadata) for response fields, lookup states, cache bounds,
310
287
  custom models, and variant limitations.
311
288
 
312
289
  ### Preserve Ollama request controls
313
290
 
314
291
  The tools declare an MCP object `outputSchema`. Schemas type the stable fields FreeLlama owns
315
292
  (such as route decision, page, answer, and session identifiers) while leaving Ollama-owned nested
316
- payloads forward-compatible. `structuredContent` is canonical; normal text is a concise cue. For
317
- the narrow `delegate_research` legacy case, set `legacyText:true` to receive serialized JSON text.
293
+ payloads forward-compatible. `structuredContent` is canonical; normal text is a concise cue
294
+ (`run_task` and `delegate_research` return the answer text).
318
295
 
319
296
  Use `models {view:"raw", limit:20}` and continue with its opaque `page.next_cursor`; a cursor
320
297
  refuses continuation if the live model list changed. Library tag responses use the same paging
321
- shape. Do not request `doctor {view:"full"}` in an agent loop: use `summary`, `scheduler`, or
322
- `config` for the smallest diagnostic that answers the question.
298
+ shape. Do not request `doctor {view:"full"}` in an agent loop: use `summary`, `status`, or `usage` for
299
+ the smallest diagnostic that answers the question.
323
300
 
324
301
  ### Preview and execution
325
302
 
@@ -342,8 +319,8 @@ Memory admission, authentication, and capability requirements apply in every mod
342
319
  tasks or `input` for embeddings, plus any applicable Ollama runtime controls.
343
320
 
344
321
  Preview rejects `prompt`, `systemPrompt`, `messages`, `input`, `images`, `tools`, `keepAlive`, `format`, `think`,
345
- `options`, `logprobs`, `topLogprobs`, `returnEmbeddings`, `priority`, `maxWaitSeconds`, `timeoutSeconds`, and
346
- `defer`, `scopeId`, and `scopeRevision`. This prevents a client from attaching
322
+ `options`, `logprobs`, `topLogprobs`, `returnEmbeddings`, `priority`, `maxWaitSeconds`, `timeoutSeconds`,
323
+ `stopOnRepetition`, `defer`, `scopeId`, and `scopeRevision`. This prevents a client from attaching
347
324
  work to a decision-only call and mistakenly assuming it ran.
348
325
 
349
326
  `run_task.messages` preserves Ollama message fields beyond `role` and `content`, including images,
@@ -363,7 +340,7 @@ Set `defer:true` on `run_task` to return a job ID immediately. Use `task_jobs {a
363
340
  metadata, `{action:"get", jobId}` for a retained result, and `{action:"cancel", jobId}` to cancel
364
341
  that task and wait for local permits to be released. `get` summarizes embedding vectors by default;
365
342
  set `returnEmbeddings:true` to include them. Cancellation does not unload a shared model or confirm
366
- physical runner shutdown. Jobs expire on restart; see [CLI controls](../../docs/CLI.md#execute-tasks)
343
+ physical runner shutdown. Jobs expire on restart; see [CLI controls](https://github.com/bgauryy/FreeLlama/blob/main/docs/CLI.md#execute-tasks)
367
344
  for input, result, registry, and retention limits. Batch items cannot defer.
368
345
 
369
346
  Set `timeoutSeconds` on a task or batch item for a total deadline covering discovery, queueing,
@@ -375,11 +352,10 @@ You own the task instructions. Pass system prompts as `messages` entries with `r
375
352
  or use `systemPrompt` to prepend one caller-supplied system message. FreeLlama preserves existing
376
353
  messages and adds no task instructions of its own. A plain `prompt` becomes one user message,
377
354
  and a supplied `messages` array takes precedence over `prompt`. This also applies to
378
- `task:"code_review"` (an alias for `coding`) and `run_task_batch`: no review wrapper, mandatory
355
+ `task:"code_review"` (an alias for `coding`) and `run_task {tasks}` batches: no review wrapper, mandatory
379
356
  JSON review format, or review-specific output-token minimum is added.
380
357
 
381
- The separate `delegate_research` adapter and natural-language routing interpreter retain internal
382
- protocol prompts for their own bounded jobs. Those prompts are not injected into `run_task`
358
+ The separate `delegate_research` adapter retains internal protocol prompts for its own bounded job. Those prompts are not injected into `run_task`
383
359
  conversations. Ollama can still apply the selected model's own template or Modelfile defaults.
384
360
 
385
361
  `model_type` is a display-oriented value derived from Ollama's additive capabilities:
@@ -387,6 +363,18 @@ conversations. Ollama can still apply the selected model's own template or Model
387
363
  capability set, not this summary label. Unknown future Ollama capabilities are omitted from the
388
364
  typed routing set instead of being treated as a known capability.
389
365
 
366
+ ### Call the control API directly
367
+
368
+ Scripts that bypass MCP post the same fields in snake_case to `POST /_freellama/v1/tasks`:
369
+ `task`, `objective`, `model`, `session_id`, `required_capabilities`, `prompt` or `messages`,
370
+ `images`, `priority`, `keep_alive`, `max_wait_seconds`, `timeout_seconds`, `stop_on_repetition`,
371
+ and `request_options: {options, format, think, logprobs, top_logprobs}`. A batch is
372
+ `POST /_freellama/v1/task-batches` with `{tasks: [{id, independent: true, task: {...}}], max_parallelism}`; sessions are
373
+ `POST /_freellama/v1/sessions` with `{}`. `model` accepts a bare name (`name` resolves to
374
+ `name:latest`, or the one installed tag of that family); an ambiguous or unknown name is refused
375
+ with the installed candidates. See [Request shapes](https://github.com/bgauryy/FreeLlama/blob/main/docs/ARCHITECTURE.md#request-shapes)
376
+ for a full body and the receipt fields.
377
+
390
378
  ### Retain history and warm models
391
379
 
392
380
  Use `scope {action:"create",messages}` to retain a caller-owned prefix. Pass its returned ID and
@@ -394,10 +382,10 @@ revision as `scopeId` and `scopeRevision` with only the new input to `run_task`;
394
382
  returns the next scope revision. Fork a snapshot before parallel branches. `sessionId` continues to
395
383
  mean model affinity only.
396
384
 
397
- Use `warm_model {model,contextTokens,keepAlive?}` for a matching runner profile. It accepts no task
385
+ Use `run_task {warm:true,model,contextTokens,keepAlive?}` for a matching runner profile. It accepts no task
398
386
  payload and does not pull a model. Add `defer:true` to inspect its progress through `task_jobs`.
399
387
  Explicit `keepAlive` wins over finite adaptive retention. See the canonical
400
- [Scope history and model warming reference](../../docs/SCOPES_AND_WARMING.md) for schemas, limits,
388
+ [Scope history and model warming reference](https://github.com/bgauryy/FreeLlama/blob/main/docs/SCOPES_AND_WARMING.md) for schemas, limits,
401
389
  concurrency, privacy, and cache boundaries.
402
390
 
403
391
  ### Use CPU assignments through MCP
@@ -414,7 +402,7 @@ comparable warm serial samples on both backends with a 10% advantage. It matches
414
402
  explicit observed context, effective controls, endpoint-attributed process settings, and managed
415
403
  admission class. Unknown identity, parallel intervals, and decision-only payload-free previews
416
404
  use capacity and policy signals. Stored legacy totals do not qualify speed hints. Feedback does
417
- not steer the `quality` objective. See [automatic feedback](../../docs/CPU_GPU_ROUTING.md#understand-automatic-feedback).
405
+ not steer the `quality` objective. See [automatic feedback](https://github.com/bgauryy/FreeLlama/blob/main/docs/CPU_GPU_ROUTING.md#understand-automatic-feedback).
418
406
  `minPlacementEvidence:"observed"` fails closed unless resident
419
407
  `/api/ps` evidence matches the configured processor; warm cold models once with `"configured"`.
420
408
  `keepAlive:"0"` uses an observe-then-unload transaction: FreeLlama retains the runner long enough
@@ -423,7 +411,9 @@ then reports the unload verification in `execution.lifecycle`.
423
411
 
424
412
  Preview `execution.agent_plan` separates `queue_readiness`, `resource_readiness`, and combined
425
413
  `dispatch_readiness`. Inspect `execution.resource_assessment` for required bytes and missing telemetry;
426
- the preview shares execution's footprint estimate but never reserves memory. Local inference requires
414
+ the preview shares execution's footprint estimate but never reserves memory. Low available RAM alone
415
+ never refuses work: previews report `runnable_low_memory_estimate`, and execution dispatches with
416
+ `resource_admission.status: "admitted_low_memory_estimate"`. Local inference requires
427
417
  RAM telemetry by default; configure an explicit alternative on `serve`, not in a model prompt.
428
418
  Resource errors retain a human-readable `error` plus machine-readable `code` and `resource_admission`
429
419
  fields in the HTTP response. MCP preserves JSON refusals in both error text and `structuredContent`,
@@ -432,7 +422,9 @@ Agents can use those fields to back off or explain a capacity hold without parsi
432
422
 
433
423
  `models {view: "resident"}` uses the managed catalog, so it includes resident models from both
434
424
  Ollama processes and labels explicitly assigned CPU models instead of querying only the primary
435
- server.
425
+ server. The per-model `placement` object is derived in the MCP layer from the catalog's
426
+ `resident_size`/`resident_vram` bytes and the core's placement observation; it is a display summary,
427
+ not new placement evidence.
436
428
 
437
429
  Before relying on that placement, query `/_freellama/v1/health` and require
438
430
  `contracts.placement_observation:"ollama_api_ps_after_execution"` and
@@ -443,154 +435,11 @@ The direct Ollama tools do not infer that assignment. `ollama_manage`, `ollama_d
443
435
  no-serve model views target their explicit `ollamaEndpoint` or `FREELLAMA_OLLAMA_ENDPOINT`, which
444
436
  defaults to the primary Ollama server. Point them at the CPU endpoint only when you intend to
445
437
  inspect or modify that separate server. Read
446
- [CPU and GPU model routing](docs/CPU_GPU_ROUTING.md) for the complete contract.
447
-
448
- ## Configuration
449
-
450
- The following settings have environment-variable overrides. Set them in the MCP client's
451
- server-launch config (for example `.mcp.json`'s `env` block) or the launching shell.
438
+ [CPU and GPU model routing](https://github.com/bgauryy/FreeLlama/blob/main/docs/CPU_GPU_ROUTING.md) for the complete contract.
452
439
 
453
- | Variable | Default | Affects |
454
- |---|---|---|
455
- | `FREELLAMA_OLLAMA_ENDPOINT` | `http://127.0.0.1:11434` | `doctor` and all `ollama_*` tools' default Ollama endpoint |
456
- | `FREELLAMA_SERVE_ENDPOINT` | `http://127.0.0.1:11435` | Default `endpoint` for serve-backed tools and `delegate_research` |
457
- | `FREELLAMA_MCP_DEFAULT_MODEL` | unset (routes to an installed coding model) | `delegate_research`'s default `model` |
458
- | `FREELLAMA_MCP_DEFAULT_ADAPTER` | `bash` | `delegate_research`'s adapter (`octocode` to switch) |
459
- | `FREELLAMA_MCP_MAX_TURNS` | `8` | Max agent turns for `delegate_research` |
460
- | `FREELLAMA_MCP_DELEGATE_TIMEOUT_SECONDS` | `180` | Whole-subprocess timeout for `delegate_research` |
461
- | `FREELLAMA_MCP_PULL_TIMEOUT_SECONDS` | `1200` | Default `ollama_manage` `"pull"` timeout |
462
- | `FREELLAMA_MCP_FETCH_TIMEOUT_SECONDS` | `30` | Timeout for other direct Ollama HTTP calls |
463
- | `FREELLAMA_MCP_ALLOWED_ROOTS` | checkout: this repository; published: must be set | Platform-separated allowlist of directories `delegate_research` may read (`:` on macOS/Linux, `;` on Windows) |
464
- | `FREELLAMA_MCP_MODEL_EVIDENCE` | checkout: `benchmark/evidence/model-evidence.json`; published: unset | Path to per-model research grades (see "Runtime evidence") |
465
- | `FREELLAMA_EXTERNAL_COST_MODEL` | unset | External-model label in estimated avoided-cost telemetry; set all three cost variables or none |
466
- | `FREELLAMA_EXTERNAL_COST_INPUT_USD_PER_M` | unset | External input USD per million tokens |
467
- | `FREELLAMA_EXTERNAL_COST_OUTPUT_USD_PER_M` | unset | External output USD per million tokens |
468
- | `FREELLAMA_CONTROL_TIMEOUT_SECONDS` | `30` | Decision-only serve calls; read by `../rust-core/src/napi.rs` |
469
- | `FREELLAMA_TASK_TIMEOUT_SECONDS` | `900` | Generation calls; read by `../rust-core/src/napi.rs` |
470
- | `FREELLAMA_AUTH_TOKEN_FILE` | unset | Bearer-token file used by the native client and research adapters for all serve routes |
471
- | `FREELLAMA_AGENT_TOKEN_CALIBRATION_DIR` | platform data directory | Prompt-free, model-specific token-estimator calibration shared across adapter processes |
472
- | `FREELLAMA_MCP_AUTOSTART_SERVE` | `1` | When the default loopback serve endpoint does not answer, start `freellama serve` as a child of the MCP server (stopped with it). `0` disables |
473
- | `FREELLAMA_SERVE_BINARY` | checkout `target/release`/`debug`, then the platform package | Binary used for serve autostart |
474
- | `FREELLAMA_AGENT_OS_SANDBOX` | `auto` | Bash adapter OS confinement: `bwrap` on Linux, `sandbox-exec` on macOS, when present. `off` keeps only the restricted shell |
475
- | `FREELLAMA_AGENT_OCTOCODE_PACKAGE` | `octocode@19.1.0` | Pinned npm spec the Octocode adapter runs through `npx` |
476
-
477
- Serve-side placement settings (read by `freellama serve`, not the MCP process):
478
-
479
- | Variable | Default | Affects |
480
- |---|---|---|
481
- | `FREELLAMA_EVICT_IDLE_MODELS` | on | Unload idle, unpinned models using reuse and load costs when a cold load needs room. `0` turns eviction off |
482
- | `FREELLAMA_CPU_NUM_THREAD` | half the logical cores (not set on macOS) | `num_thread` for CPU-placed tasks only; GPU tasks leave it to Ollama |
483
- | `FREELLAMA_MAX_QUEUE_WAIT_SECONDS` | `120` | How long a managed task queues for a slot or memory |
484
- | `OLLAMA_NUM_PARALLEL`, `OLLAMA_KV_CACHE_TYPE`, `OLLAMA_FLASH_ATTENTION` | Ollama's | Read as hints for the memory estimate: parallel slots multiply the KV cache, and `q8_0`/`q4_0` shrink it only with flash attention. Set them for serve the same way as for Ollama |
485
-
486
- Research-adapter settings are deployment defaults. The optional `delegate_research.agent` object
487
- overrides the per-call budget (`maxTurns`, `contextTokens`, `outputTokens`, `temperature`, `seed`,
488
- `think`, `keepAlive`, `requestTimeoutSeconds`, `toolTimeoutSeconds`); explicit per-call fields win.
489
- The research subprocess receives only `FREELLAMA_*`, locale, temp, and proxy/CA variables from the
490
- server environment.
491
-
492
- | Variable | Default | Affects |
493
- |---|---:|---|
494
- | `FREELLAMA_AGENT_NUM_CTX` | `8192` | Ollama context window |
495
- | `FREELLAMA_AGENT_EXECUTION_PREFERENCE` | `auto` | Managed coding-agent backend hint |
496
- | `FREELLAMA_AGENT_MIN_PLACEMENT_EVIDENCE` | `configured` | Set `observed` to fail closed on cold/mismatched placement |
497
- | `FREELLAMA_AGENT_NUM_PREDICT` | `512` | Reserved output budget |
498
- | `FREELLAMA_AGENT_TEMPERATURE` / `FREELLAMA_AGENT_SEED` | `0` / `42` | Repeatable decoding |
499
- | `FREELLAMA_AGENT_THINK` / `FREELLAMA_AGENT_KEEP_ALIVE` | `false` / `5m` | Ollama reasoning and residency |
500
- | `FREELLAMA_AGENT_REQUEST_TIMEOUT_SECONDS` | `600` | Each Ollama chat attempt |
501
- | `FREELLAMA_AGENT_TOOL_TIMEOUT_SECONDS` | Bash `30`, Octocode `45` | Each local tool call |
502
- | `FREELLAMA_AGENT_RETRY_ATTEMPTS` / `FREELLAMA_AGENT_RETRY_BACKOFF_SECONDS` | `2` / `5` | Conversation-level retry |
503
- | `FREELLAMA_AGENT_MAX_PARSE_REPAIRS` / `FREELLAMA_AGENT_PARSE_REPAIR_ECHO_CHARS` | `2` / `500` | Invalid JSON correction limit and retained reply text |
504
- | `FREELLAMA_AGENT_CHARS_PER_TOKEN` | `4` | First-call token estimate; later calibrated from Ollama |
505
- | `FREELLAMA_AGENT_SAFETY_MARGIN_TOKENS` | `256` | Input headroom beyond `num_predict` |
506
- | `FREELLAMA_AGENT_IMAGE_TOKEN_ESTIMATE` | `1024` | Bounded charge per image |
507
- | `FREELLAMA_AGENT_KEEP_RECENT` | `2` | Recent observations preserved verbatim |
508
- | `FREELLAMA_AGENT_COMPACT_PREVIEW_CHARS` | `180` | Old-observation breadcrumb size |
509
- | `FREELLAMA_AGENT_COMPACT_RETAIN_RATIO` | `0.8` | Current payload retained per emergency pass |
510
- | `FREELLAMA_AGENT_CLIP_HEAD_RATIO` | `0.667` | Head share when an emergency clip preserves both ends |
511
- | `FREELLAMA_AGENT_OBSERVATION_PAGE_CHARS` | `3000` | Lossless observation page target |
512
- | `FREELLAMA_AGENT_PINNED_OVERFLOW` | `error` | Preserve system/task bytes; `clip` is explicit opt-in |
513
-
514
- Invalid values fail before an Ollama request. Each successful result returns
515
- `contextManagement` with the resolved policy, calibration source/scale, estimated input budget,
516
- and compaction count. Ollama has no stable preflight tokenizer endpoint, so “exact before the first
517
- call” is not claimed. Model-specific calibration persists after successful calls, so later
518
- processes start conservatively from prior `prompt_eval_count` evidence without sharing estimates
519
- between model templates.
520
-
521
- **Security:** `delegate_research` grants a local model read access to `workspacePath`. The path is
522
- confined to `FREELLAMA_MCP_ALLOWED_ROOTS` (default: this repository in a checkout; unset in a published
523
- install until you set it), resolved through symlinks so a link inside an allowed root can't escape
524
- it. The default `bash` adapter runs an allowlist of read-only tools in a restricted shell with a
525
- scrubbed environment and, where available, an OS sandbox; it also rejects command substitution,
526
- home-directory paths, `..`, and absolute paths outside that workspace. Production deployments should generate a permission-restricted token with
527
- `freellama auth-token`, start `serve` with `--auth-token-file`, and set
528
- `FREELLAMA_AUTH_TOKEN_FILE` for MCP. Authentication covers managed and raw passthrough routes; use
529
- an external TLS and authorization layer for untrusted or multi-tenant networks.
530
-
531
- ### Runtime evidence
532
-
533
- Admission weights can be set by task kind in the server runtime file's `[task_costs]` table.
534
- Inspect `doctor {view:"full"}` at `platform_health.admission.costs.base_by_task` for effective
535
- weights and `run_task {preview:true}` for current cost and capacity advice. The table changes
536
- managed admission; it does not create Ollama
537
- slots or relax memory guards. Existing queued work keeps its captured cost. See
538
- [monitoring controls](../../docs/MONITORING.md#adaptive-concurrency).
539
-
540
- **No measurements are compiled in.** In a repository checkout, per-model research grades load from
541
- `benchmark/evidence/model-evidence.json`. A published package does not include that repository
542
- file, so its evidence table is empty unless you set `FREELLAMA_MCP_MODEL_EVIDENCE`. An unmeasured
543
- model yields a `verify` verdict. Tool descriptions state the rules; measurement details live in
544
- `skills/freellama/references/` and `.octocode/evals/`.
545
-
546
- ## Platform support
547
-
548
- The native addon is named by target triple (`freellama.<platform>-<arch>[-<abi>].node`). The base
549
- package has eight npm optional dependencies, one each for macOS arm64/x64, Linux arm64/x64 with
550
- glibc or musl, and Windows arm64/x64 with MSVC. `native/index.js` tries the checkout artifact first,
551
- then the host's optional package. A release is supported only when all eight artifact packages pass
552
- the publish verifier; an installation made with `--omit=optional` cannot load the addon. `engines`
553
- requires Node >= 20.
554
-
555
- Machine discovery distinguishes total host memory (`memory_bytes`) from known unified memory
556
- (`unified_memory_bytes`). Library-tag `fitsInMemory` is a conservative host-memory preflight and
557
- includes `fitScope: "host_memory_budget_only"`; inspect `/api/ps` for actual accelerator placement.
558
-
559
- Start the serve-backed tools' dependency from the repository root:
560
-
561
- ```bash
562
- cargo run --release -- serve --recommendation-catalog recommendations.example.toml
563
- ```
564
-
565
- See `skills/freellama/references/proxy-vs-serve.md` for the `proxy` vs `serve` distinction (only
566
- `serve` has the `/_freellama/v1/*` routes these tools call).
567
-
568
- ## Publish
569
-
570
- `packages/mcp/` is the portable JavaScript package. Its `package.json` lists the platform packages
571
- as exact-version optional dependencies; it intentionally does not embed a `.node` binary. Publish
572
- the eight `packages/native/*` packages first, then publish `@octocodeai/freellama` (`npx @octocodeai/freellama`) and `@octocodeai/freellama-mcp-server` (`npx @octocodeai/freellama-mcp-server`)
573
- at the same version. `yarn release:verify:publish` refuses a release if any of the ten packages
574
- omits `assets/logo.jpg`, or if any platform package has a missing, empty, or unpacked
575
- executable/addon pair.
576
-
577
- ```bash
578
- cd packages/mcp
579
- npm pack --dry-run # confirm exactly what a publish would ship
580
- ```
440
+ ## More
581
441
 
582
- Treat `npm publish` as a public release action. Follow the repository
583
- [release procedure](../../RELEASE.md) and obtain the repository owner's release authorization first.
584
-
585
- ## Why native bindings
586
-
587
- - **No reimplementation.** `run_task`, `route`/`preview`, and the installed-model list are HTTP
588
- calls into a running `freellama serve`, matching `../cli/src/main.rs`. `doctor` talks to Ollama
589
- and the host's portable machine-discovery layer directly. `ollama_manage` / `ollama_delete` hit Ollama's HTTP API. `delegate_research`
590
- is a subprocess. Routing logic still lives in exactly one place — the Rust core.
591
- - **One connection pool.** `../rust-core/src/napi.rs` holds a single `reqwest::Client` in a
592
- `OnceLock` and clones the handle per request, matching the server side.
593
- - **`unsafe_code` stays isolated.** The crate is `deny(unsafe_code)` except `napi.rs`, which
594
- carries an explicit `#[allow(unsafe_code)]` for napi-derive's FFI glue.
595
- - **The napi build is off by default** (`cargo build` never touches it); the addon is built with
596
- `napi build --features napi` from the repo root.
442
+ - [Configuration](CONFIGURATION.md): environment variables, research-adapter settings, security,
443
+ and runtime evidence.
444
+ - [Developing](DEVELOPING.md): build, test tiers, platform packages, publishing, and why the server
445
+ uses native bindings.