@octocodeai/freellama-mcp-server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,426 @@
1
+ # FreeLlama MCP server
2
+
3
+ Exposes FreeLlama's local-LLM control plane, and Ollama's lifecycle, as
4
+ [MCP](https://modelcontextprotocol.io) tools, built on the official
5
+ [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk).
6
+
7
+ ## Understand the eight tools
8
+
9
+ - `doctor`, `models`, `run_task`, `run_task_batch` — thin wrappers over the native NAPI bindings into the
10
+ Rust core (`../rust-core/src/napi.rs`); no CLI subprocess, no reimplemented routing logic.
11
+ `run_task { preview: true }` is the free decision-only form (the former `route` tool).
12
+ Preview and execution are separate calls: preview accepts routing fields only and rejects task
13
+ payloads or runtime controls instead of silently ignoring them.
14
+ `models { view: "library" }` queries the public `ollama.com` library (the former `search_models` tool).
15
+ - `session` — creates and releases a bounded, idle-expiring model-affinity handle for related
16
+ route/task calls. It does not store messages, prompt history, or Ollama's runner KV cache.
17
+ - `ollama_manage`, `ollama_delete` — Ollama's HTTP API for lifecycle operations the routing layer
18
+ doesn't cover.
19
+ - `delegate_research` — offloads a grounded code-research question to a local model and returns a
20
+ verdict computed from what the run did.
21
+
22
+ Use the smallest tool that owns the operation:
23
+
24
+ ```mermaid
25
+ flowchart TD
26
+ Q{"What does the client need?"}
27
+ Q -->|"Diagnose the local runtime"| D["doctor"]
28
+ Q -->|"Inspect installed, resident, detailed, raw, or online models"| M["models"]
29
+ Q -->|"Choose or execute one task"| R["run_task"]
30
+ Q -->|"Fan out independent tasks"| B["run_task_batch"]
31
+ Q -->|"Keep/release related-task model affinity"| S["session"]
32
+ Q -->|"Pull or stop a model"| O["ollama_manage"]
33
+ Q -->|"Permanently remove a named model"| X["ollama_delete"]
34
+ Q -->|"Ground an answer in workspace files"| G["delegate_research"]
35
+ ```
36
+
37
+ | Tool | Why it exists |
38
+ |---|---|
39
+ | `doctor` | Makes runtime, version, memory, and configuration drift visible before work starts. |
40
+ | `models` | Separates installed, resident, detailed, raw, and public-library questions instead of guessing from model names. |
41
+ | `run_task` | Applies the same deterministic routing, confidence, admission, and execution contract as the Rust control plane. |
42
+ | `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. |
43
+ | `session` | Lets an agent explicitly own the lifetime of a bounded affinity handle without misrepresenting it as conversation or KV storage. |
44
+ | `ollama_manage` | Exposes additive lifecycle operations that FreeLlama routing intentionally does not perform. |
45
+ | `ollama_delete` | Keeps irreversible deletion separate and explicit so a client can guard it. |
46
+ | `delegate_research` | Gives a local model bounded read-only tools and returns citations plus an independently computed verification verdict. |
47
+
48
+ ## Follow the agent workflow
49
+
50
+ The server sends this workflow to every MCP client in its initialization instructions:
51
+
52
+ 1. Start with `models {view:"installed"}`, then `models {view:"resident"}`. This gives a routing
53
+ agent the smallest current inventory first.
54
+ 2. Call `doctor` only for runtime or configuration diagnosis. It returns `summary` by default;
55
+ use `view:"scheduler"` for configured/snapshot scheduling evidence or `view:"full"` for the
56
+ complete diagnostic. If Ollama is missing or unreachable, ask the operator to install or start it.
57
+ 3. Classify the task. Offload embeddings, OCR/vision, bulk transforms, and sufficiently large
58
+ grounded lookups; retain small lookups and high-stakes judgment in the calling agent.
59
+ 4. Prefer a qualified installed model and preview consequential work.
60
+ 5. If none fits, collect the operator's modality, quality, context, latency, privacy, disk/download,
61
+ and memory constraints. Search the Ollama library, inspect exact tags and host-memory fit, and
62
+ present at most two candidates.
63
+ 6. Ask the operator to approve one exact tag and its reported size before calling
64
+ `ollama_manage {action:"pull"}`. Searching or recommending never authorizes a download.
65
+ 7. Execute, inspect the route/execution/admission receipt, and verify the result at the returned
66
+ confidence level.
67
+
68
+ ### Use context and delegation deliberately
69
+
70
+ FreeLlama reduces the **calling agent's context burden**. It does not make an Ollama response more
71
+ accurate or eliminate the local model tokens needed to produce it. Its compact text cue avoids a
72
+ second serialized copy of the canonical `structuredContent`; its delegated adapter keeps full tool
73
+ observations on disk and presents them in pages when requested.
74
+
75
+ Use this economical sequence:
76
+
77
+ 1. Request `models {view:"installed"}` before `doctor`; inventory is normally the smaller and
78
+ more relevant first decision.
79
+ 2. Preview consequential generation with `run_task {preview:true}`. Preview is decision-only: it
80
+ neither generates nor reserves capacity.
81
+ 3. Execute in a separate `run_task` call. Set `contextTokens` for the complete Ollama window and
82
+ `options.num_predict` for its output cap. A lower cap or window can lower cost **and** damage a
83
+ difficult answer, so choose it from the task rather than a global default.
84
+ 4. Use `delegate_research` only for a self-contained question requiring files under
85
+ `workspacePath`. Bound `agent.maxTurns`, `agent.contextTokens`, and `agent.outputTokens`.
86
+ 5. Keep the compact text cue in the active conversation; inspect `structuredContent`, a paged tool
87
+ result, or a bundled documentation resource only when its detail changes the next action.
88
+
89
+ For a delegated agent, estimated usable input is `contextTokens - outputTokens - safetyMarginTokens`
90
+ (the default margin is 256). The adapter pins the system instruction and question, preserves the
91
+ newest observations, compacts older observations into breadcrumbs, and refuses a pinned overflow
92
+ by default. `pinnedOverflow:"clip"` is a deliberate quality-risk override. Initial token counting
93
+ is conservative; successful Ollama calls calibrate later estimates.
94
+
95
+ Do not confuse operational evidence with answer quality. A receipt can prove admission, token
96
+ counts, placement, or unloading. It cannot prove research correctness, coding judgment, sustained
97
+ throughput, or fairness from one run. Check the returned confidence, policy evidence, and benchmark
98
+ evidence before accepting a consequential answer.
99
+
100
+ ### Measure avoided external cost
101
+
102
+ Every successful `run_task`, batch item, and `delegate_research` result includes `telemetry.local`
103
+ when Ollama reports input/output token counts. To add `telemetry.externalEquivalent`, configure one
104
+ operator-owned rate card when starting the MCP server:
105
+
106
+ ```text
107
+ FREELLAMA_EXTERNAL_COST_MODEL=EXTERNAL_MODEL_LABEL
108
+ FREELLAMA_EXTERNAL_COST_INPUT_USD_PER_M=INPUT_USD_PER_MILLION
109
+ FREELLAMA_EXTERNAL_COST_OUTPUT_USD_PER_M=OUTPUT_USD_PER_MILLION
110
+ ```
111
+
112
+ The receipt multiplies observed local input/output counts by those configured rates. It is an
113
+ equivalent avoided-API-cost estimate only when the local result replaces an external call. It
114
+ excludes provider caching and reasoning-token differences, retries, local electricity, and hardware
115
+ amortization; it is not a provider bill or net-profit calculation. Partial or invalid rate-card
116
+ configuration stops the MCP server at startup instead of emitting a misleading estimate.
117
+
118
+ ### Route images and OCR
119
+
120
+ Use `run_task` for supplied image bytes, not `delegate_research`. Preview
121
+ `{task:"vision", requiredCapabilities:["vision"], preview:true}` before a consequential image
122
+ task. Execute separately with a prompt and base64 `images` values without data-URI prefixes. The
123
+ `images` field requires an explicitly trialed vision model; inspect the execution receipt for
124
+ admission and observed placement.
125
+
126
+ FreeLlama can prove that it routed and ran a request. It cannot infer OCR or visual-reasoning
127
+ quality from a capability tag, a model name, or GPU placement. Quality depends on the exact
128
+ installed model build, prompt and decoding settings, context/output budget, and available host
129
+ memory and accelerator performance. Validate representative held-out images on the target machine
130
+ and supply policy/benchmark evidence before automatically accepting a quality-sensitive result.
131
+
132
+ The caller owns task decomposition and concurrent submission. The operator owns endpoints, exact
133
+ CPU assignments, runtime settings, and lifecycle approval. FreeLlama owns qualification, managed
134
+ placement and admission. Ollama and the OS/driver own runner loading and physical CPU/GPU execution.
135
+
136
+ ## Follow the architecture
137
+
138
+ ```mermaid
139
+ flowchart TD
140
+ C["MCP client"] -->|"stdio JSON-RPC"| B["dist/index.js: eight tool registrations"]
141
+ B --> N["native/index.js and platform addon"]
142
+ N -->|"doctor"| L["Rust diagnostics"]
143
+ N -->|"models installed/resident; run_task"| S["freellama serve"]
144
+ S --> G["Primary Ollama"]
145
+ S --> U["Optional CPU Ollama"]
146
+ B -->|"detail, raw; manage; delete"| G
147
+ B -->|"library view"| W["ollama.com library"]
148
+ B -->|"delegate_research"| A["allowlisted local adapter subprocess"]
149
+ A --> S
150
+ C -->|"resources/read on demand"| D["packaged docs/*.md"]
151
+ ```
152
+
153
+ `doctor`, the installed/resident model views, and `run_task` use the NAPI binding instead of a CLI
154
+ subprocess. Direct lifecycle and no-serve model views use Ollama HTTP. `delegate_research` starts a
155
+ bounded adapter against an allowlisted workspace; each adapter model turn re-enters managed
156
+ `run_task` as `coding`, so it shares routing, admission, and placement evidence. Routing logic is
157
+ not duplicated in TypeScript.
158
+
159
+ ## Read packaged documentation through MCP
160
+
161
+ The published MCP package includes every Markdown file from the repository `docs/` directory. The
162
+ repository directory remains the source of truth; the package build copies it into `docs/` and
163
+ creates `docs/INDEX.md`.
164
+
165
+ MCP clients can list resources and read `freellama://docs/index`, then fetch exactly one relevant
166
+ guide such as `freellama://docs/PRODUCTION`, `freellama://docs/CLI`, or
167
+ `freellama://docs/OLLAMA_SYSTEM_OPTIMIZATION`. Resources are deliberately lazy: do not load every
168
+ guide into an agent context. The server fails on startup if the generated index is absent, and the
169
+ release verifier checks that the packed documents match the root `docs/` set.
170
+
171
+ ## Build
172
+
173
+ Build the native addon from the repository root and this package in place.
174
+
175
+ ```bash
176
+ # From the repository root (yarn workspaces — one install for every package)
177
+ yarn install
178
+ yarn build
179
+ ```
180
+
181
+ `yarn build` writes **one** MCP file, `packages/mcp/dist/index.js` (shebang, executable). During
182
+ checkout development it loads `native/freellama.<triple>.node`. Published installs resolve the
183
+ matching `@octocodeai/freellama-native-<target>` optional package instead, so the base MCP package remains
184
+ portable. Research adapters are copied into `adapters/` for packed installs.
185
+
186
+ Piecewise, if you are iterating on one layer:
187
+
188
+ ```bash
189
+ # 1. Native addon → packages/mcp/native/freellama.<triple>.node
190
+ yarn build:native
191
+
192
+ # 2. This server → dist/index.js via esbuild (then copies the research adapters into adapters/)
193
+ yarn workspace @octocodeai/freellama-mcp-server build
194
+ ```
195
+
196
+ `yarn start` needs `dist/index.js` and the compiled `.node` addon — `yarn build` from the repository
197
+ root produces both in a checkout. `dist/index.js` loads `native/index.js`, which loads a local addon
198
+ first and then a matching optional platform package. The `.node` binary is gitignored (a build
199
+ artifact); `native/index.js` and `native/index.d.ts` are hand-written and checked in.
200
+
201
+ ## Run
202
+
203
+ ```bash
204
+ node dist/index.js
205
+ ```
206
+
207
+ The server speaks MCP over stdio — launch it from an MCP client (for example, Claude Desktop's
208
+ `claude_desktop_config.json`), not interactively.
209
+
210
+ ## Test
211
+
212
+ Vitest, in three tiers (all TypeScript, under `test/`):
213
+
214
+ | Tier | Command (from this package) | Checks | Needs |
215
+ |---|---|---|---|
216
+ | `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 |
217
+ | `test/integration/` | `yarn test:integration` | the built server over the real MCP protocol: tool contract, structured content, guardrails; rebuilds `dist/` itself | live Ollama on :11434, ~5s |
218
+ | `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 |
219
+
220
+ The same commands work from the repository root (`yarn test` there also runs the CLI package's tests).
221
+ The integration/e2e tiers fail fast with a readable message when Ollama is down, and the lifecycle
222
+ test refuses to delete a model already installed on the test system.
223
+
224
+ ## Tools
225
+
226
+ | Tool | Needs `freellama serve`? | What it does |
227
+ |---|---|---|
228
+ | `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. The report distinguishes an observed same-user macOS process from configuration hints and never claims remote process visibility. |
229
+ | `models` | `installed` (default) and `resident` do; `detail`/`raw`/`library` don't | Views: `installed` (capabilities, derived `model_type`, VRAM, context, policy_rank), `resident` (loaded now + managed GPU/CPU split), `detail` (one model, real max context), paged `raw` (`GET /api/tags`), `library` (two-step ollama.com search: omit `model` for families, pass `model:"<family>"` for tags/`fitsInMemory`) |
230
+ | `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) |
231
+ | `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. |
232
+ | `ollama_manage` | No (direct to Ollama) | `action: "pull"` downloads a model; `action: "stop"` force-unloads it. Both additive and idempotent |
233
+ | `ollama_delete` | No (direct to Ollama) | **Destructive**: permanently removes a model. Call only on an explicit human instruction naming the exact model |
234
+ | `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 |
235
+
236
+ ### Preserve Ollama request controls
237
+
238
+ All eight tools declare an MCP object `outputSchema`. Schemas type the stable fields FreeLlama owns
239
+ (such as route decision, page, answer, and session identifiers) while leaving Ollama-owned nested
240
+ payloads forward-compatible. `structuredContent` is canonical; normal text is a concise cue. For
241
+ the narrow `delegate_research` legacy case, set `legacyText:true` to receive serialized JSON text.
242
+
243
+ Use `models {view:"raw", limit:20}` and continue with its opaque `page.next_cursor`; a cursor
244
+ refuses continuation if the live model list changed. Library tag responses use the same paging
245
+ shape. Do not request `doctor {view:"full"}` in an agent loop: use `summary`, `scheduler`, or
246
+ `config` for the smallest diagnostic that answers the question.
247
+
248
+ `run_task` has two deliberately exclusive request shapes:
249
+
250
+ - Preview: set `preview: true`; pass routing fields such as `task`, `objective`, `model`,
251
+ `contextTokens`, `requiredCapabilities`, and placement/confidence gates. To preview tool use,
252
+ pass `requiredCapabilities: ["tools"]` rather than function definitions.
253
+ - Execution: omit `preview` (or set it to `false`) and pass `prompt`/`messages` for generative
254
+ tasks or `input` for embeddings, plus any applicable Ollama runtime controls.
255
+
256
+ Preview rejects `prompt`, `messages`, `input`, `images`, `tools`, `keepAlive`, `format`, `think`,
257
+ `options`, `logprobs`, `topLogprobs`, and `returnEmbeddings`. This prevents a client from attaching
258
+ work to a decision-only call and mistakenly assuming it ran.
259
+
260
+ `run_task.messages` preserves Ollama message fields beyond `role` and `content`, including images,
261
+ thinking, tool calls, and tool names. Managed requests also accept `format`, `think`, `options`,
262
+ `logprobs`, and `topLogprobs`. Use `contextTokens` for `num_ctx`; placement owns `num_gpu`, so both
263
+ keys are rejected inside `options`. The raw proxy remains available when a caller needs an Ollama
264
+ endpoint or feature that the managed MCP tool does not expose, including streaming.
265
+
266
+ `model_type` is a display-oriented value derived from Ollama's additive capabilities:
267
+ `generative`, `multimodal`, `embedding_only`, or `unknown`. Routing continues to use the original
268
+ capability set, not this summary label. Unknown future Ollama capabilities are omitted from the
269
+ typed routing set instead of being treated as a known capability.
270
+
271
+ ### Use CPU assignments through MCP
272
+
273
+ `run_task` delegates to `freellama serve`, so it honors the server's `--cpu-upstream` and
274
+ `--cpu-model` configuration. Exact assigned models can execute on the CPU process while other
275
+ managed tasks execute on the primary GPU-capable process.
276
+
277
+ Set `executionPreference` on `run_task` to `auto` (default), `prefer_cpu`, or `prefer_gpu`. This is a
278
+ guarded hint: only exact operator-assigned CPU models are eligible, explicit model/session pins win,
279
+ and `preview: true` returns `execution.preference_satisfied`, placement, upstream, admission, and a
280
+ reason without generating. Automatic feedback normalizes work by tokens, waits for three successful
281
+ warm, physically verified samples per task on both backends, requires a 10% advantage, and never
282
+ steers the `quality` objective. `minPlacementEvidence:"observed"` fails closed unless resident
283
+ `/api/ps` evidence matches the configured processor; warm cold models once with `"configured"`.
284
+ `keepAlive:"0"` uses an observe-then-unload transaction: FreeLlama retains the runner long enough
285
+ to inspect `/api/ps`, accepts feedback only for verified placement, requests an explicit unload,
286
+ then reports the unload verification in `execution.lifecycle`.
287
+
288
+ `models {view: "resident"}` uses the managed catalog, so it includes resident models from both
289
+ Ollama processes and labels explicitly assigned CPU models instead of querying only the primary
290
+ server.
291
+
292
+ Before relying on that placement, query `/_freellama/v1/health` and require
293
+ `contracts.placement_observation:"ollama_api_ps_after_execution"` and
294
+ `contracts.placement_evidence_gate:"configured_or_observed"`. A missing contract means the running server
295
+ predates the dual-backend build even if the MCP package itself is current.
296
+
297
+ The direct Ollama tools do not infer that assignment. `ollama_manage`, `ollama_delete`, and the
298
+ no-serve model views target their explicit `ollamaEndpoint` or `FREELLAMA_OLLAMA_ENDPOINT`, which
299
+ defaults to the primary Ollama server. Point them at the CPU endpoint only when you intend to
300
+ inspect or modify that separate server. Read
301
+ [CPU and GPU model routing](docs/CPU_GPU_ROUTING.md) for the complete contract.
302
+
303
+ ## Configuration
304
+
305
+ Every default is overridable through an environment variable — set them in the MCP client's
306
+ server-launch config (for example `.mcp.json`'s `env` block) or the launching shell.
307
+
308
+ | Variable | Default | Affects |
309
+ |---|---|---|
310
+ | `FREELLAMA_OLLAMA_ENDPOINT` | `http://127.0.0.1:11434` | `doctor` and all `ollama_*` tools' default Ollama endpoint |
311
+ | `FREELLAMA_SERVE_ENDPOINT` | `http://127.0.0.1:11435` | Default `endpoint` for serve-backed tools and `delegate_research` |
312
+ | `FREELLAMA_MCP_DEFAULT_MODEL` | `qwen3.8:27b-mlx` | `delegate_research`'s default `model` |
313
+ | `FREELLAMA_MCP_DEFAULT_ADAPTER` | `bash` | `delegate_research`'s adapter (`octocode` to switch) |
314
+ | `FREELLAMA_MCP_MAX_TURNS` | `8` | Max agent turns for `delegate_research` |
315
+ | `FREELLAMA_MCP_DELEGATE_TIMEOUT_SECONDS` | `180` | Whole-subprocess timeout for `delegate_research` |
316
+ | `FREELLAMA_MCP_PULL_TIMEOUT_SECONDS` | `1200` | Default `ollama_manage` `"pull"` timeout |
317
+ | `FREELLAMA_MCP_FETCH_TIMEOUT_SECONDS` | `30` | Timeout for other direct Ollama HTTP calls |
318
+ | `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) |
319
+ | `FREELLAMA_MCP_MODEL_EVIDENCE` | checkout: `benchmark/evidence/model-evidence.json`; published: unset | Path to per-model research grades (see "Runtime evidence") |
320
+ | `FREELLAMA_EXTERNAL_COST_MODEL` | unset | External-model label in estimated avoided-cost telemetry; set all three cost variables or none |
321
+ | `FREELLAMA_EXTERNAL_COST_INPUT_USD_PER_M` | unset | External input USD per million tokens |
322
+ | `FREELLAMA_EXTERNAL_COST_OUTPUT_USD_PER_M` | unset | External output USD per million tokens |
323
+ | `FREELLAMA_CONTROL_TIMEOUT_SECONDS` | `30` | Decision-only serve calls; read by `../rust-core/src/napi.rs` |
324
+ | `FREELLAMA_TASK_TIMEOUT_SECONDS` | `900` | Generation calls; read by `../rust-core/src/napi.rs` |
325
+ | `FREELLAMA_AUTH_TOKEN_FILE` | unset | Bearer-token file used by the native client and research adapters for all serve routes |
326
+ | `FREELLAMA_AGENT_TOKEN_CALIBRATION_DIR` | platform data directory | Prompt-free, model-specific token-estimator calibration shared across adapter processes |
327
+
328
+ Research-adapter settings are deployment defaults. The optional `delegate_research.agent` object
329
+ exposes the same values per call using camelCase; explicit per-call fields win.
330
+
331
+ | Variable | Default | Affects |
332
+ |---|---:|---|
333
+ | `FREELLAMA_AGENT_NUM_CTX` | `8192` | Ollama context window |
334
+ | `FREELLAMA_AGENT_EXECUTION_PREFERENCE` | `auto` | Managed coding-agent backend hint |
335
+ | `FREELLAMA_AGENT_MIN_PLACEMENT_EVIDENCE` | `configured` | Set `observed` to fail closed on cold/mismatched placement |
336
+ | `FREELLAMA_AGENT_NUM_PREDICT` | `512` | Reserved output budget |
337
+ | `FREELLAMA_AGENT_TEMPERATURE` / `FREELLAMA_AGENT_SEED` | `0` / `42` | Repeatable decoding |
338
+ | `FREELLAMA_AGENT_THINK` / `FREELLAMA_AGENT_KEEP_ALIVE` | `false` / `5m` | Ollama reasoning and residency |
339
+ | `FREELLAMA_AGENT_REQUEST_TIMEOUT_SECONDS` | `600` | Each Ollama chat attempt |
340
+ | `FREELLAMA_AGENT_TOOL_TIMEOUT_SECONDS` | Bash `30`, Octocode `45` | Each local tool call |
341
+ | `FREELLAMA_AGENT_RETRY_ATTEMPTS` / `FREELLAMA_AGENT_RETRY_BACKOFF_SECONDS` | `2` / `5` | Conversation-level retry |
342
+ | `FREELLAMA_AGENT_MAX_PARSE_REPAIRS` / `FREELLAMA_AGENT_PARSE_REPAIR_ECHO_CHARS` | `2` / `500` | Invalid JSON correction limit and retained reply text |
343
+ | `FREELLAMA_AGENT_CHARS_PER_TOKEN` | `4` | First-call token estimate; later calibrated from Ollama |
344
+ | `FREELLAMA_AGENT_SAFETY_MARGIN_TOKENS` | `256` | Input headroom beyond `num_predict` |
345
+ | `FREELLAMA_AGENT_IMAGE_TOKEN_ESTIMATE` | `1024` | Bounded charge per image |
346
+ | `FREELLAMA_AGENT_KEEP_RECENT` | `2` | Recent observations preserved verbatim |
347
+ | `FREELLAMA_AGENT_COMPACT_PREVIEW_CHARS` | `180` | Old-observation breadcrumb size |
348
+ | `FREELLAMA_AGENT_COMPACT_RETAIN_RATIO` | `0.8` | Current payload retained per emergency pass |
349
+ | `FREELLAMA_AGENT_CLIP_HEAD_RATIO` | `0.667` | Head share when an emergency clip preserves both ends |
350
+ | `FREELLAMA_AGENT_OBSERVATION_PAGE_CHARS` | `3000` | Lossless observation page target |
351
+ | `FREELLAMA_AGENT_PINNED_OVERFLOW` | `error` | Preserve system/task bytes; `clip` is explicit opt-in |
352
+
353
+ Invalid values fail before an Ollama request. Each successful result returns
354
+ `contextManagement` with the resolved policy, calibration source/scale, estimated input budget,
355
+ and compaction count. Ollama has no stable preflight tokenizer endpoint, so “exact before the first
356
+ call” is not claimed. Model-specific calibration persists after successful calls, so later
357
+ processes start conservatively from prior `prompt_eval_count` evidence without sharing estimates
358
+ between model templates.
359
+
360
+ **Security:** `delegate_research` grants a local model read access to `workspacePath`. The path is
361
+ confined to `FREELLAMA_MCP_ALLOWED_ROOTS` (default: this repository in a checkout; unset in a published
362
+ install until you set it), resolved through symlinks so a link inside an allowed root can't escape
363
+ it. The default `bash` adapter also rejects home-directory paths, `..`, and absolute paths outside
364
+ that workspace. Production deployments should generate a permission-restricted token with
365
+ `freellama auth-token`, start `serve` with `--auth-token-file`, and set
366
+ `FREELLAMA_AUTH_TOKEN_FILE` for MCP. Authentication covers managed and raw passthrough routes; use
367
+ an external TLS and authorization layer for untrusted or multi-tenant networks.
368
+
369
+ ### Runtime evidence
370
+
371
+ **No measurements are compiled in.** In a repository checkout, per-model research grades load from
372
+ `benchmark/evidence/model-evidence.json`. A published package does not include that repository
373
+ file, so its evidence table is empty unless you set `FREELLAMA_MCP_MODEL_EVIDENCE`. An unmeasured
374
+ model yields a `verify` verdict. Tool descriptions state the rules; measurement details live in
375
+ `skills/freellama/references/` and `.octocode/evals/`.
376
+
377
+ ## Platform support
378
+
379
+ The native addon is named by target triple (`freellama.<platform>-<arch>[-<abi>].node`). The base
380
+ package has eight npm optional dependencies, one each for macOS arm64/x64, Linux arm64/x64 with
381
+ glibc or musl, and Windows arm64/x64 with MSVC. `native/index.js` tries the checkout artifact first,
382
+ then the host's optional package. A release is supported only when all eight artifact packages pass
383
+ the publish verifier; an installation made with `--omit=optional` cannot load the addon. `engines`
384
+ requires Node >= 20.
385
+
386
+ Machine discovery distinguishes total host memory (`memory_bytes`) from known unified memory
387
+ (`unified_memory_bytes`). Library-tag `fitsInMemory` is a conservative host-memory preflight and
388
+ includes `fitScope: "host_memory_budget_only"`; inspect `/api/ps` for actual accelerator placement.
389
+
390
+ Start the serve-backed tools' dependency from the repository root:
391
+
392
+ ```bash
393
+ cargo run --release -- serve --recommendation-catalog recommendations.example.toml
394
+ ```
395
+
396
+ See `skills/freellama/references/proxy-vs-serve.md` for the `proxy` vs `serve` distinction (only
397
+ `serve` has the `/_freellama/v1/*` routes these tools call).
398
+
399
+ ## Publish
400
+
401
+ `packages/mcp/` is the portable JavaScript package. Its `package.json` lists the platform packages
402
+ as exact-version optional dependencies; it intentionally does not embed a `.node` binary. Publish
403
+ the eight `packages/native/*` packages first, then publish `@octocodeai/freellama` and `@octocodeai/freellama-mcp-server`
404
+ at the same version. `yarn release:verify:publish` refuses a release if any platform package has a
405
+ missing, empty, or unpacked executable/addon pair.
406
+
407
+ ```bash
408
+ cd packages/mcp
409
+ npm pack --dry-run # confirm exactly what a publish would ship
410
+ ```
411
+
412
+ Version 0.1.0 is not published to a registry. Treat `npm publish` as a real, irreversible public
413
+ action, and confirm with the repository owner first.
414
+
415
+ ## Why native bindings
416
+
417
+ - **No reimplementation.** `run_task`, `route`/`preview`, and the installed-model list are HTTP
418
+ calls into a running `freellama serve`, matching `../cli/src/main.rs`. `doctor` talks to Ollama
419
+ and the host's portable machine-discovery layer directly. `ollama_manage` / `ollama_delete` hit Ollama's HTTP API. `delegate_research`
420
+ is a subprocess. Routing logic still lives in exactly one place — the Rust core.
421
+ - **One connection pool.** `../rust-core/src/napi.rs` holds a single `reqwest::Client` in a
422
+ `OnceLock` and clones the handle per request, matching the server side.
423
+ - **`unsafe_code` stays isolated.** The crate is `deny(unsafe_code)` except `napi.rs`, which
424
+ carries an explicit `#[allow(unsafe_code)]` for napi-derive's FFI glue.
425
+ - **The napi build is off by default** (`cargo build` never touches it); the addon is built with
426
+ `napi build --features napi` from the repo root.