@octocodeai/freellama-mcp-server 0.1.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.
package/README.md CHANGED
@@ -1,59 +1,57 @@
1
1
  # FreeLlama MCP server
2
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:
3
+ ![A brown cartoon llama stands on a pastel cloud background.](assets/logo.jpg)
23
4
 
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
- ```
5
+ This package exposes FreeLlama's management layer as Model Context Protocol (MCP) tools.
6
+ Agents offload bounded tasks to local Ollama models; FreeLlama handles model selection, resource
7
+ admission, memory checks, and routing to configured CPU/GPU backends. Results include execution
8
+ evidence for the calling agent to inspect.
36
9
 
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. |
10
+ The agent owns prompts, task dependencies, and answer verification. The operator configures
11
+ Ollama and model lifecycle permissions; Ollama performs inference. See
12
+ [architecture](https://github.com/bgauryy/FreeLlama/blob/main/docs/ARCHITECTURE.md) for the full ownership boundary.
13
+ The server uses the official [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk).
14
+
15
+ ## Understand the tools
16
+
17
+ `doctor`, `models`, `run_task`, and `task_jobs` 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.
26
+
27
+ Use the smallest tool that owns the operation; the canonical per-tool table is [Tools](#tools).
47
28
 
48
29
  ## Follow the agent workflow
49
30
 
50
- The server sends this workflow to every MCP client in its initialization instructions:
31
+ The task lifecycle uses the UUID returned as `job.id` by `run_task {defer:true}`. A job is one
32
+ submitted task; pass that UUID as `jobId` for every subsequent operation.
33
+
34
+ | Operation | MCP call |
35
+ |---|---|
36
+ | List models | `models {view:"installed"}` |
37
+ | Submit a task and receive its ID | `run_task {prompt:"Explain this code", defer:true}` |
38
+ | List tasks with their states | `task_jobs {action:"list"}` |
39
+ | Get one task's state, result, or error | `task_jobs {action:"get", jobId:"<returned UUID>"}` |
40
+ | Stop one task and retain its record | `task_jobs {action:"cancel", jobId:"<returned UUID>"}` |
41
+ | Stop one task and remove its record | `task_jobs {action:"remove", jobId:"<returned UUID>"}` |
42
+
43
+ Removal waits for local permits to be released before deleting the record. It returns the ID and
44
+ terminal status; subsequent lookup returns `404`. It does not unload a shared Ollama model or
45
+ prove that physical computation has stopped. Receipts are bounded and lost on server restart;
46
+ see [retention and task states](https://github.com/bgauryy/FreeLlama/blob/main/docs/MONITORING.md#read-the-live-status).
47
+
48
+ Follow this workflow. The server's initialization instructions carry a compressed form of the
49
+ same contract (inventory first, preview semantics, evidence levels, ownership, and pull approval):
51
50
 
52
51
  1. Start with `models {view:"installed"}`, then `models {view:"resident"}`. This gives a routing
53
52
  agent the smallest current inventory first.
54
53
  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.
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.
57
55
  3. Classify the task. Offload embeddings, OCR/vision, bulk transforms, and sufficiently large
58
56
  grounded lookups; retain small lookups and high-stakes judgment in the calling agent.
59
57
  4. Prefer a qualified installed model and preview consequential work.
@@ -89,7 +87,7 @@ Use this economical sequence:
89
87
  For a delegated agent, estimated usable input is `contextTokens - outputTokens - safetyMarginTokens`
90
88
  (the default margin is 256). The adapter pins the system instruction and question, preserves the
91
89
  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
90
+ by default. `FREELLAMA_AGENT_PINNED_OVERFLOW=clip` is a deliberate quality-risk override. Initial token counting
93
91
  is conservative; successful Ollama calls calibrate later estimates.
94
92
 
95
93
  Do not confuse operational evidence with answer quality. A receipt can prove admission, token
@@ -97,7 +95,41 @@ counts, placement, or unloading. It cannot prove research correctness, coding ju
97
95
  throughput, or fairness from one run. Check the returned confidence, policy evidence, and benchmark
98
96
  evidence before accepting a consequential answer.
99
97
 
100
- ### 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
101
133
 
102
134
  Every successful `run_task`, batch item, and `delegate_research` result includes `telemetry.local`
103
135
  when Ollama reports input/output token counts. To add `telemetry.externalEquivalent`, configure one
@@ -115,13 +147,28 @@ excludes provider caching and reasoning-token differences, retries, local electr
115
147
  amortization; it is not a provider bill or net-profit calculation. Partial or invalid rate-card
116
148
  configuration stops the MCP server at startup instead of emitting a misleading estimate.
117
149
 
118
- ### Route images and OCR
150
+ ### Route images
119
151
 
120
152
  Use `run_task` for supplied image bytes, not `delegate_research`. Preview
121
153
  `{task:"vision", requiredCapabilities:["vision"], preview:true}` before a consequential image
122
154
  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.
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.
125
172
 
126
173
  FreeLlama can prove that it routed and ran a request. It cannot infer OCR or visual-reasoning
127
174
  quality from a capability tag, a model name, or GPU placement. Quality depends on the exact
@@ -129,15 +176,14 @@ installed model build, prompt and decoding settings, context/output budget, and
129
176
  memory and accelerator performance. Validate representative held-out images on the target machine
130
177
  and supply policy/benchmark evidence before automatically accepting a quality-sensitive result.
131
178
 
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.
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).
135
181
 
136
182
  ## Follow the architecture
137
183
 
138
184
  ```mermaid
139
185
  flowchart TD
140
- C["MCP client"] -->|"stdio JSON-RPC"| B["dist/index.js: eight tool registrations"]
186
+ C["MCP client"] -->|"stdio JSON-RPC"| B["dist/index.js: tool registrations"]
141
187
  B --> N["native/index.js and platform addon"]
142
188
  N -->|"doctor"| L["Rust diagnostics"]
143
189
  N -->|"models installed/resident; run_task"| S["freellama serve"]
@@ -153,108 +199,127 @@ flowchart TD
153
199
  `doctor`, the installed/resident model views, and `run_task` use the NAPI binding instead of a CLI
154
200
  subprocess. Direct lifecycle and no-serve model views use Ollama HTTP. `delegate_research` starts a
155
201
  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.
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.
158
205
 
159
- ## Read packaged documentation through MCP
206
+ ### What the MCP layer computes
160
207
 
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`.
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:
164
210
 
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.
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.
170
218
 
171
- ## Build
219
+ ## Read packaged documentation through MCP
172
220
 
173
- Build the native addon from the repository root and this package in place.
221
+ The published MCP package includes the top-level Markdown guides from the repository `docs/`
222
+ directory (developer notes under `docs/dev/` are not packaged). The repository directory remains the
223
+ source of truth; the package build copies it into `docs/`.
174
224
 
175
- ```bash
176
- # From the repository root (yarn workspaces — one install for every package)
177
- yarn install
178
- yarn build
179
- ```
225
+ MCP clients can list resources and read `freellama://docs/index` (the repository `docs/README.md`),
226
+ then fetch exactly one relevant guide such as `freellama://docs/PRODUCTION` or
227
+ `freellama://docs/CLI`. Resources are deliberately lazy: do not load every guide into an agent
228
+ context. The server fails on startup if the index is absent.
180
229
 
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
230
 
186
- Piecewise, if you are iterating on one layer:
231
+ ## Run
187
232
 
188
- ```bash
189
- # 1. Native addon → packages/mcp/native/freellama.<triple>.node
190
- yarn build:native
233
+ **From npm (recommended):**
191
234
 
192
- # 2. This server → dist/index.js via esbuild (then copies the research adapters into adapters/)
193
- yarn workspace @octocodeai/freellama-mcp-server build
235
+ ```bash
236
+ npx @octocodeai/freellama-mcp-server
194
237
  ```
195
238
 
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
239
+ **From the repository root after building:**
202
240
 
203
241
  ```bash
204
- node dist/index.js
242
+ node packages/mcp/dist/index.js
205
243
  ```
206
244
 
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.
245
+ The server speaks MCP over stdio — configure it in your MCP client, do not run it interactively.
209
246
 
210
- ## Test
247
+ **Claude Desktop (`claude_desktop_config.json`):**
211
248
 
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 |
249
+ ```json
250
+ {
251
+ "mcpServers": {
252
+ "freellama": {
253
+ "command": "npx",
254
+ "args": ["@octocodeai/freellama-mcp-server"]
255
+ }
256
+ }
257
+ }
258
+ ```
219
259
 
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.
260
+ **Cursor / other clients** — use the same `command`/`args` shape in their MCP server config.
223
261
 
224
262
  ## Tools
225
263
 
226
264
  | Tool | Needs `freellama serve`? | What it does |
227
265
  |---|---|---|
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 |
266
+ | `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. |
267
+ | `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. |
268
+ | `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`. |
269
+ | `scope` | Yes | Creates, inspects, forks, or deletes process-local message history; history inclusion requires `includeMessages:true`. |
270
+ | `session` | Yes | Creates, deletes, or kills model affinity without storing messages or KV; `kill` cancels the session's in-flight work. |
271
+ | `task_jobs` | Yes | Inspects, cancels, or removes a deferred task or warming operation. |
272
+ | `ollama_manage` | No (direct to Ollama) | `action: "pull"` downloads a model (additive); `action: "stop"` force-unloads it. Both are idempotent |
233
273
  | `ollama_delete` | No (direct to Ollama) | **Destructive**: permanently removes a model. Call only on an explicit human instruction naming the exact model |
234
274
  | `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
275
 
276
+ ### Inspect capabilities and intended uses
277
+
278
+ Use `models {view:"installed", includeLibrary:true}` to enrich each installed model, or
279
+ `models {view:"detail", model:"gemma3:1b", includeLibrary:true, includeReadme:true}` for one model.
280
+ Website access is optional for installed/detail views. Public guidance requires a matching exact tag
281
+ and digest prefix; local capabilities remain authoritative and benchmark/policy evidence stays separate.
282
+ Family claims have source excerpts and fetch dates, and lookup failures retain local inventory.
283
+ Search reports `cloudAvailable` (a cloud variant exists), not whether a family is cloud-only; inspect
284
+ exact tags to establish local availability.
285
+ See [Model metadata](https://github.com/bgauryy/FreeLlama/blob/main/docs/MODEL_SELECTION.md#model-metadata) for response fields, lookup states, cache bounds,
286
+ custom models, and variant limitations.
287
+
236
288
  ### Preserve Ollama request controls
237
289
 
238
- All eight tools declare an MCP object `outputSchema`. Schemas type the stable fields FreeLlama owns
290
+ The tools declare an MCP object `outputSchema`. Schemas type the stable fields FreeLlama owns
239
291
  (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.
292
+ payloads forward-compatible. `structuredContent` is canonical; normal text is a concise cue
293
+ (`run_task` and `delegate_research` return the answer text).
242
294
 
243
295
  Use `models {view:"raw", limit:20}` and continue with its opaque `page.next_cursor`; a cursor
244
296
  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.
297
+ shape. Do not request `doctor {view:"full"}` in an agent loop: use `summary`, `status`, or `usage` for
298
+ the smallest diagnostic that answers the question.
299
+
300
+ ### Preview and execution
301
+
302
+ For ordinary chat, `run_task {prompt:"Hello"}` is enough once the server and an eligible model
303
+ are available. `task` defaults to `completion`, including inside batch items. Task profiles are
304
+ optional routing presets, not restrictions on what you can ask the model.
305
+
306
+ Default `balanced` routing prefers policy-qualified candidates when available. Without an eligible
307
+ policy candidate, it falls back to capability/context-compatible models and reports low confidence,
308
+ `quality_evidence:"none"`, and `balanced_without_quality_policy`. Set `minConfidence:"medium"`
309
+ to require evidence, or `objective:"quality"` to require policy-based selection unless you pin a model.
310
+ Memory admission, authentication, and capability requirements apply in every mode.
247
311
 
248
312
  `run_task` has two deliberately exclusive request shapes:
249
313
 
250
314
  - Preview: set `preview: true`; pass routing fields such as `task`, `objective`, `model`,
251
315
  `contextTokens`, `requiredCapabilities`, and placement/confidence gates. To preview tool use,
252
316
  pass `requiredCapabilities: ["tools"]` rather than function definitions.
253
- - Execution: omit `preview` (or set it to `false`) and pass `prompt`/`messages` for generative
317
+ - Execution: omit `preview` (or set it to `false`) and pass `prompt`, `systemPrompt`, or `messages` for generative
254
318
  tasks or `input` for embeddings, plus any applicable Ollama runtime controls.
255
319
 
256
- Preview rejects `prompt`, `messages`, `input`, `images`, `tools`, `keepAlive`, `format`, `think`,
257
- `options`, `logprobs`, `topLogprobs`, and `returnEmbeddings`. This prevents a client from attaching
320
+ Preview rejects `prompt`, `systemPrompt`, `messages`, `input`, `images`, `tools`, `keepAlive`, `format`, `think`,
321
+ `options`, `logprobs`, `topLogprobs`, `returnEmbeddings`, `priority`, `maxWaitSeconds`, `timeoutSeconds`, and
322
+ `defer`, `scopeId`, and `scopeRevision`. This prevents a client from attaching
258
323
  work to a decision-only call and mistakenly assuming it ran.
259
324
 
260
325
  `run_task.messages` preserves Ollama message fields beyond `role` and `content`, including images,
@@ -263,11 +328,65 @@ thinking, tool calls, and tool names. Managed requests also accept `format`, `th
263
328
  keys are rejected inside `options`. The raw proxy remains available when a caller needs an Ollama
264
329
  endpoint or feature that the managed MCP tool does not expose, including streaming.
265
330
 
331
+ Managed execution waits for a slot and safe host capacity within the server's waiting budget
332
+ (120 seconds by default). Set `maxWaitSeconds` on `run_task` or each batch task to request a
333
+ shorter budget; the server caps it at its configured limit. Resource waiters remain counted in
334
+ the bounded queue after returning their execution slots. They resume when capacity becomes
335
+ available, and session cancellation removes pending work. A full queue or an expired deadline
336
+ returns a capacity error with retry guidance.
337
+
338
+ Set `defer:true` on `run_task` to return a job ID immediately. Use `task_jobs {action:"list"}` for
339
+ metadata, `{action:"get", jobId}` for a retained result, and `{action:"cancel", jobId}` to cancel
340
+ that task and wait for local permits to be released. `get` summarizes embedding vectors by default;
341
+ set `returnEmbeddings:true` to include them. Cancellation does not unload a shared model or confirm
342
+ physical runner shutdown. Jobs expire on restart; see [CLI controls](https://github.com/bgauryy/FreeLlama/blob/main/docs/CLI.md#execute-tasks)
343
+ for input, result, registry, and retention limits. Batch items cannot defer.
344
+
345
+ Set `timeoutSeconds` on a task or batch item for a total deadline covering discovery, queueing,
346
+ loading, and inference. The server caps it at its task timeout. The admission wait budget remains
347
+ separate; a queue refusal can happen before the total deadline. `priority` selects a fair scheduling
348
+ class without bypassing resource checks.
349
+
350
+ You own the task instructions. Pass system prompts as `messages` entries with `role:"system"`,
351
+ or use `systemPrompt` to prepend one caller-supplied system message. FreeLlama preserves existing
352
+ messages and adds no task instructions of its own. A plain `prompt` becomes one user message,
353
+ and a supplied `messages` array takes precedence over `prompt`. This also applies to
354
+ `task:"code_review"` (an alias for `coding`) and `run_task {tasks}` batches: no review wrapper, mandatory
355
+ JSON review format, or review-specific output-token minimum is added.
356
+
357
+ The separate `delegate_research` adapter retains internal protocol prompts for its own bounded job. Those prompts are not injected into `run_task`
358
+ conversations. Ollama can still apply the selected model's own template or Modelfile defaults.
359
+
266
360
  `model_type` is a display-oriented value derived from Ollama's additive capabilities:
267
361
  `generative`, `multimodal`, `embedding_only`, or `unknown`. Routing continues to use the original
268
362
  capability set, not this summary label. Unknown future Ollama capabilities are omitted from the
269
363
  typed routing set instead of being treated as a known capability.
270
364
 
365
+ ### Call the control API directly
366
+
367
+ Scripts that bypass MCP post the same fields in snake_case to `POST /_freellama/v1/tasks`:
368
+ `task`, `objective`, `model`, `session_id`, `required_capabilities`, `prompt` or `messages`,
369
+ `images`, `priority`, `keep_alive`, `max_wait_seconds`, `timeout_seconds`, `stop_on_repetition`,
370
+ and `request_options: {options, format, think, logprobs, top_logprobs}`. A batch is
371
+ `{tasks: [{id, independent: true, task: {...}}], max_parallelism}`; sessions are
372
+ `POST /_freellama/v1/sessions` with `{}`. `model` accepts a bare name (`name` resolves to
373
+ `name:latest`, or the one installed tag of that family); an ambiguous or unknown name is refused
374
+ with the installed candidates. See [Request shapes](https://github.com/bgauryy/FreeLlama/blob/main/docs/ARCHITECTURE.md#request-shapes)
375
+ for a full body and the receipt fields.
376
+
377
+ ### Retain history and warm models
378
+
379
+ Use `scope {action:"create",messages}` to retain a caller-owned prefix. Pass its returned ID and
380
+ revision as `scopeId` and `scopeRevision` with only the new input to `run_task`; successful execution
381
+ returns the next scope revision. Fork a snapshot before parallel branches. `sessionId` continues to
382
+ mean model affinity only.
383
+
384
+ Use `run_task {warm:true,model,contextTokens,keepAlive?}` for a matching runner profile. It accepts no task
385
+ payload and does not pull a model. Add `defer:true` to inspect its progress through `task_jobs`.
386
+ Explicit `keepAlive` wins over finite adaptive retention. See the canonical
387
+ [Scope history and model warming reference](https://github.com/bgauryy/FreeLlama/blob/main/docs/SCOPES_AND_WARMING.md) for schemas, limits,
388
+ concurrency, privacy, and cache boundaries.
389
+
271
390
  ### Use CPU assignments through MCP
272
391
 
273
392
  `run_task` delegates to `freellama serve`, so it honors the server's `--cpu-upstream` and
@@ -277,17 +396,34 @@ managed tasks execute on the primary GPU-capable process.
277
396
  Set `executionPreference` on `run_task` to `auto` (default), `prefer_cpu`, or `prefer_gpu`. This is a
278
397
  guarded hint: only exact operator-assigned CPU models are eligible, explicit model/session pins win,
279
398
  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
399
+ reason without generating. Automatic feedback normalizes work by tokens and requires three
400
+ comparable warm serial samples on both backends with a 10% advantage. It matches model digest,
401
+ explicit observed context, effective controls, endpoint-attributed process settings, and managed
402
+ admission class. Unknown identity, parallel intervals, and decision-only payload-free previews
403
+ use capacity and policy signals. Stored legacy totals do not qualify speed hints. Feedback does
404
+ not steer the `quality` objective. See [automatic feedback](https://github.com/bgauryy/FreeLlama/blob/main/docs/CPU_GPU_ROUTING.md#understand-automatic-feedback).
405
+ `minPlacementEvidence:"observed"` fails closed unless resident
283
406
  `/api/ps` evidence matches the configured processor; warm cold models once with `"configured"`.
284
407
  `keepAlive:"0"` uses an observe-then-unload transaction: FreeLlama retains the runner long enough
285
408
  to inspect `/api/ps`, accepts feedback only for verified placement, requests an explicit unload,
286
409
  then reports the unload verification in `execution.lifecycle`.
287
410
 
411
+ Preview `execution.agent_plan` separates `queue_readiness`, `resource_readiness`, and combined
412
+ `dispatch_readiness`. Inspect `execution.resource_assessment` for required bytes and missing telemetry;
413
+ the preview shares execution's footprint estimate but never reserves memory. Low available RAM alone
414
+ never refuses work: previews report `runnable_low_memory_estimate`, and execution dispatches with
415
+ `resource_admission.status: "admitted_low_memory_estimate"`. Local inference requires
416
+ RAM telemetry by default; configure an explicit alternative on `serve`, not in a model prompt.
417
+ Resource errors retain a human-readable `error` plus machine-readable `code` and `resource_admission`
418
+ fields in the HTTP response. MCP preserves JSON refusals in both error text and `structuredContent`,
419
+ including queue-full codes, `retry_after_seconds`, resource assessments, and unload receipts.
420
+ Agents can use those fields to back off or explain a capacity hold without parsing human prose.
421
+
288
422
  `models {view: "resident"}` uses the managed catalog, so it includes resident models from both
289
423
  Ollama processes and labels explicitly assigned CPU models instead of querying only the primary
290
- server.
424
+ server. The per-model `placement` object is derived in the MCP layer from the catalog's
425
+ `resident_size`/`resident_vram` bytes and the core's placement observation; it is a display summary,
426
+ not new placement evidence.
291
427
 
292
428
  Before relying on that placement, query `/_freellama/v1/health` and require
293
429
  `contracts.placement_observation:"ollama_api_ps_after_execution"` and
@@ -298,129 +434,11 @@ The direct Ollama tools do not infer that assignment. `ollama_manage`, `ollama_d
298
434
  no-serve model views target their explicit `ollamaEndpoint` or `FREELLAMA_OLLAMA_ENDPOINT`, which
299
435
  defaults to the primary Ollama server. Point them at the CPU endpoint only when you intend to
300
436
  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
437
+ [CPU and GPU model routing](https://github.com/bgauryy/FreeLlama/blob/main/docs/CPU_GPU_ROUTING.md) for the complete contract.
400
438
 
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
- ```
439
+ ## More
411
440
 
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.
441
+ - [Configuration](CONFIGURATION.md): environment variables, research-adapter settings, security,
442
+ and runtime evidence.
443
+ - [Developing](DEVELOPING.md): build, test tiers, platform packages, publishing, and why the server
444
+ uses native bindings.