@octocodeai/freellama-mcp-server 0.6.0 → 0.6.2
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/CONFIGURATION.md +5 -7
- package/DEVELOPING.md +18 -15
- package/LICENSE-MIT +1 -1
- package/README.md +10 -9
- package/dist/index.js +252 -39
- package/docs/ARCHITECTURE.md +43 -30
- package/docs/CLI.md +22 -16
- package/docs/CPU_GPU_ROUTING.md +11 -11
- package/docs/MODEL_SELECTION.md +46 -4
- package/docs/MONITORING.md +8 -6
- package/docs/PRODUCTION.md +31 -19
- package/docs/README.md +2 -6
- package/docs/TESTING.md +7 -7
- package/package.json +10 -9
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -27,7 +27,7 @@ This is the canonical ownership rule; other guides link here.
|
|
|
27
27
|
| Forecast memory reservations, host-pressure holds, and requests to unload idle unpinned models | FreeLlama managed execution |
|
|
28
28
|
| Explicit per-model CPU/GPU backend assignment | FreeLlama and separate Ollama processes |
|
|
29
29
|
| Grounded research adapters, citations, and verification verdicts | FreeLlama MCP server |
|
|
30
|
-
| Bearer authentication of every route | FreeLlama; external ingress owns TLS and tenant authorization |
|
|
30
|
+
| Bearer authentication of every route except the static `/_freellama/ui` shell | FreeLlama; external ingress owns TLS and tenant authorization |
|
|
31
31
|
|
|
32
32
|
FreeLlama is a governed router, not an unrestricted hardware scheduler: a CPU preference cannot move
|
|
33
33
|
an arbitrary tag, and one managed call contains one task. Only the calling agent knows which tasks
|
|
@@ -92,9 +92,10 @@ flowchart TB
|
|
|
92
92
|
ADAPTER --> GPU
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
-
The CLI and MCP server do not reimplement routing.
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
The CLI and MCP server do not reimplement routing. CLI commands other than `serve`, `doctor`,
|
|
96
|
+
`init`, and benchmarking are HTTP clients of a running `freellama serve`. The MCP server reaches the
|
|
97
|
+
same control API through the feature-gated NAPI boundary, and unless `FREELLAMA_MCP_AUTOSTART_SERVE=0`
|
|
98
|
+
it starts the bundled `serve` in the background at launch when nothing answers on the default endpoint.
|
|
98
99
|
|
|
99
100
|
## Request classification
|
|
100
101
|
|
|
@@ -124,17 +125,21 @@ The control API exposes these endpoints:
|
|
|
124
125
|
| `POST /_freellama/v1/routes` | Deterministic route decision | No |
|
|
125
126
|
| `POST /_freellama/v1/sessions` | New model-affinity session | No |
|
|
126
127
|
| `DELETE /_freellama/v1/sessions/:session_id` | Release model-affinity session | No |
|
|
128
|
+
| `POST /_freellama/v1/sessions/:session_id/kill` | Release a session and cancel its in-flight tasks; the runner stays loaded | No new inference |
|
|
127
129
|
| `POST /_freellama/v1/scopes` | Create bounded message history | No |
|
|
128
130
|
| `GET /_freellama/v1/scopes/:id` | Scope metadata; optional explicit history inclusion | No |
|
|
129
131
|
| `POST /_freellama/v1/scopes/:id/fork` | Fork history at an expected revision | No |
|
|
130
132
|
| `DELETE /_freellama/v1/scopes/:id` | Delete retained history | No |
|
|
131
133
|
| `POST /_freellama/v1/warm` | Admitted load of an exact installed runner profile | Load only |
|
|
132
134
|
| `POST /_freellama/v1/tasks` | Managed chat, vision, tools, or embedding task (body shape under [Request shapes](#request-shapes)) | Yes |
|
|
135
|
+
| `POST /_freellama/v1/task-batches` | Caller-declared independent tasks with ordered per-item receipts | Yes |
|
|
133
136
|
| `GET /_freellama/v1/jobs` | Deferred job metadata without prompts or results | No |
|
|
134
137
|
| `GET /_freellama/v1/jobs/:id` | One deferred receipt and retained result | No |
|
|
135
138
|
| `POST /_freellama/v1/jobs/:id/cancel` | Cancel one deferred task and release its local permits | No new inference |
|
|
136
139
|
| `DELETE /_freellama/v1/jobs/:id` | Cancel active work, release local permits, and remove its retained record | No new inference |
|
|
137
140
|
|
|
141
|
+
Status, usage, metrics, and runtime-config endpoints are listed in [monitoring](MONITORING.md).
|
|
142
|
+
|
|
138
143
|
### Request shapes
|
|
139
144
|
|
|
140
145
|
The control API uses snake_case JSON. A managed task body is the routing fields plus the payload:
|
|
@@ -173,7 +178,7 @@ A batch nests whole task bodies:
|
|
|
173
178
|
`POST /sessions` with an empty object returns `session_id`; `POST /warm` takes `{"model": "<tag>"}`.
|
|
174
179
|
|
|
175
180
|
The machine profile is host-derived rather than model-name-derived. It reports total physical
|
|
176
|
-
memory on macOS (`sysctl`), Linux (`/proc`), and Windows (
|
|
181
|
+
memory on macOS (`sysctl`), Linux (`/proc`), and Windows (CIM through PowerShell), along with CPU, OS,
|
|
177
182
|
architecture, and disk. `memory_bytes` is portable host RAM. `unified_memory_bytes` is populated
|
|
178
183
|
only when host and accelerator memory are known to share a pool; it must not be treated as discrete
|
|
179
184
|
GPU VRAM. Ollama's `/api/ps` remains the placement authority.
|
|
@@ -208,7 +213,7 @@ Every field comes from the model's own metadata and from what FreeLlama observed
|
|
|
208
213
|
name. `GET /_freellama/v1/models` adds, per model:
|
|
209
214
|
|
|
210
215
|
- `context_default`: the context Ollama gives a request that leaves `num_ctx` unset (`source` is
|
|
211
|
-
`modelfile`, `config`, `ollama_context_length`, `vram_tier`, or `
|
|
216
|
+
`modelfile`, `config`, `ollama_context_length`, `vram_tier`, `resident_runner`, or `unknown`). A managed
|
|
212
217
|
task that sends a different `num_ctx` reloads the runner.
|
|
213
218
|
- `resident_context`: the `context_length` of the loaded runner from `/api/ps`.
|
|
214
219
|
- `observed_loops`: per task kind, managed runs since start and how many ended in a repetition
|
|
@@ -243,7 +248,7 @@ flowchart TD
|
|
|
243
248
|
F --> X{"Explicit model?"}
|
|
244
249
|
X -->|"Yes"| E["Use exact model or refuse"]
|
|
245
250
|
X -->|"No"| O{"Objective"}
|
|
246
|
-
O -->|"fastest"| S["Rank local
|
|
251
|
+
O -->|"fastest"| S["Rank local benchmark,<br/>smaller size, and deterministic ties"]
|
|
247
252
|
O -->|"balanced"| B["Prefer policy-qualified candidates;<br/>otherwise use eligible models with low confidence"]
|
|
248
253
|
O -->|"quality"| Q["Require policy-qualified candidates,<br/>then prefer policy order"]
|
|
249
254
|
E --> H["Grade advertised-context compatibility and evidence"]
|
|
@@ -264,8 +269,9 @@ Routing never ranks by a model's name or architecture. Automatic selection (fall
|
|
|
264
269
|
session affinity) ranks a model last for a task kind when it has looped on that kind at least twice
|
|
265
270
|
in at most twice as many managed runs; the decision then carries
|
|
266
271
|
`repeats_on_this_task_last_resort`. An operator policy naming the model for the task, or an explicit
|
|
267
|
-
`model`, always wins. No request option is
|
|
268
|
-
and decoding settings belong to
|
|
272
|
+
`model`, always wins. No request option is hard-coded for a model: apart from an operator policy's
|
|
273
|
+
per-model `model_options` (`think`, `num_predict`), stop sequences and decoding settings belong to
|
|
274
|
+
the caller.
|
|
269
275
|
|
|
270
276
|
`context_window_fit` means only that requested `num_ctx` fits the model's advertised context
|
|
271
277
|
window. It is not a live-memory, free-VRAM, K/V-cache, thermal, or runner-admission verdict.
|
|
@@ -306,7 +312,7 @@ flowchart TD
|
|
|
306
312
|
T["POST /tasks or /task-batches"] --> R["Select eligible model + backend"]
|
|
307
313
|
R --> K["Estimate metadata-backed F16 K/V<br/>(or report unknown)"]
|
|
308
314
|
K --> A{"Acquire selected backend's<br/>3:2:1 fair weighted budget"}
|
|
309
|
-
A -->|"No"| E503["503
|
|
315
|
+
A -->|"No"| E503["429 queue full or<br/>503 wait timeout"]
|
|
310
316
|
A -->|"Yes"| B{"Execution backend"}
|
|
311
317
|
B -->|"Primary"| GL{"GPU model resident<br/>under transition lock?"}
|
|
312
318
|
B -->|"CPU assignment"| CO["Add num_gpu: 0"]
|
|
@@ -334,8 +340,8 @@ falling back to two. The optional CPU pool defaults to one. A saturated GPU burs
|
|
|
334
340
|
consume the permit held for a small CPU helper. With one parallel slot, those values represent one
|
|
335
341
|
ordinary chat and one embedding. Operators can tune both budgets from queue-wait and resident-memory evidence.
|
|
336
342
|
After FreeLlama admission, each Ollama process applies its own `OLLAMA_MAX_QUEUE`, scheduler,
|
|
337
|
-
`OLLAMA_NUM_PARALLEL`, and loaded-model limit. Raw proxy requests bypass weighted
|
|
338
|
-
still pass the raw concurrency cap, backend exclusion, and host-pressure gate.
|
|
343
|
+
`OLLAMA_NUM_PARALLEL`, and loaded-model limit. Raw proxy generation requests bypass weighted
|
|
344
|
+
admission but still pass the raw concurrency cap, backend exclusion, and host-pressure gate.
|
|
339
345
|
|
|
340
346
|
| Task | Default cost |
|
|
341
347
|
|---|---:|
|
|
@@ -375,9 +381,10 @@ stable ID and `independent:true`; dependent workflow execution is rejected befor
|
|
|
375
381
|
It bounds local dispatch and returns ordered per-item success/error receipts. Every child still
|
|
376
382
|
passes the same global admission and transition path above.
|
|
377
383
|
|
|
378
|
-
The K/V preflight derives single-sequence F16 K+V bytes-per-token
|
|
379
|
-
|
|
380
|
-
|
|
384
|
+
The K/V preflight derives single-sequence F16 K+V bytes-per-token for any architecture whose
|
|
385
|
+
metadata declares the block count and head counts. Explicit key/value dimensions take precedence
|
|
386
|
+
over embedding length divided by heads; sliding-window, shared-KV, recurrent, cross-attention, and
|
|
387
|
+
unknown layouts report unknown. F16 is advisory because quantized KV can
|
|
381
388
|
use less memory. The coarse model-file budget refuses files over 80% of local CPU/unified RAM only
|
|
382
389
|
for loopback backends. Forecasts use each backend's independently attributed parallelism and KV
|
|
383
390
|
cache settings where process inspection is available, with explicit fallback sources otherwise.
|
|
@@ -388,14 +395,17 @@ authority. Configured settings alone do not prove physical processor placement.
|
|
|
388
395
|
The shared [resource governor](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/src/platform/resources/mod.rs) samples local
|
|
389
396
|
available-memory estimates, load per logical CPU, OS memory pressure, active swap-out growth, and
|
|
390
397
|
thermal throttling when reported. OS memory pressure holds every local demand; active swap-out
|
|
391
|
-
growth holds new loads; CPU-load
|
|
392
|
-
|
|
393
|
-
|
|
398
|
+
growth holds new loads; the CPU-load hold applies only to CPU-assigned work (saturated cores slow
|
|
399
|
+
nothing on the GPU, so raw passthrough, which cannot know residency, is not refused for it), and to
|
|
400
|
+
all work on a host whose sampler sees no accelerator; the
|
|
401
|
+
thermal hold applies to CPU-assigned work and to cold loads (a new heat source) but not to a bounded
|
|
402
|
+
request on a runner already resident on the GPU (`ResourceDemand::is_held_by`; the assessment's
|
|
394
403
|
`held_by` lists the holds that applied). Low available RAM (below the larger of 15% or 1 GiB, clearing after two
|
|
395
404
|
healthy samples above the larger of 20% or 2 GiB) depends on the platform (`ResourcePolicy::low_memory`).
|
|
405
|
+
A new load must leave that reserve free, but never more than its own size above the 1 GiB floor.
|
|
396
406
|
On macOS (`advisory`) the estimate undercounts what the OS can reclaim, so a load that does not cover
|
|
397
|
-
it first unloads idle runners and then dispatches with a `memory_advisory`. On Linux
|
|
398
|
-
|
|
407
|
+
it first unloads idle runners and then dispatches with a `memory_advisory`. On Linux and other
|
|
408
|
+
platforms (`refuse`) a new load that does not fit first unloads idle runners and then waits
|
|
399
409
|
with `held_insufficient_capacity` until a permit release or a fresh sample frees capacity, or refuses
|
|
400
410
|
with 503 at its deadline: Linux `MemAvailable` already includes reclaimable cache and is the hard cap
|
|
401
411
|
in a container, so over-admitting invites the OOM killer. Already-resident runners add no memory and
|
|
@@ -406,8 +416,10 @@ seconds; unavailable signals stay unknown. Remote backends bypass this host gate
|
|
|
406
416
|
Each pressure signal recovers independently after two fresh samples that meet its recovery
|
|
407
417
|
threshold. A recovered CPU-load signal therefore clears even while RAM remains low.
|
|
408
418
|
|
|
409
|
-
|
|
410
|
-
even when a raw request has no model-footprint estimate.
|
|
419
|
+
On Linux and macOS the default `require_memory` telemetry policy holds local inference when
|
|
420
|
+
available RAM is missing, even when a raw request has no model-footprint estimate. Windows and other
|
|
421
|
+
platforms have no host collector, so they default to `best_effort` and admit with
|
|
422
|
+
`admitted_telemetry_unknown`; elsewhere `best_effort` is an explicit opt-in;
|
|
411
423
|
`require_all` additionally requires the collector's applicable load, OS-pressure, and thermal signals.
|
|
412
424
|
Unsupported Linux collector signals remain explicitly unavailable rather than being fabricated.
|
|
413
425
|
The pure `ResourceSnapshot::assess_capacity` calculation is shared by admission and previews.
|
|
@@ -442,11 +454,11 @@ Resident tasks share a backend lock. Nonresident tasks take that backend's exclu
|
|
|
442
454
|
load cannot race another managed task on the same server. CPU and GPU backends have separate locks
|
|
443
455
|
and admission pools, so they can progress independently.
|
|
444
456
|
|
|
445
|
-
In `serve`,
|
|
446
|
-
returning 503 when busy. The response body holds this guard through
|
|
447
|
-
GET/HEAD
|
|
448
|
-
|
|
449
|
-
pressure
|
|
457
|
+
In `serve`, raw generation requests also take the primary backend's exclusive transition lock,
|
|
458
|
+
returning 503 when it stays busy past the raw queue wait. The response body holds this guard through
|
|
459
|
+
EOF or disconnect. Metadata GET/HEAD, `/api/show`, model-store calls (pull, push, copy, delete, and
|
|
460
|
+
blob uploads), and empty `keep_alive:0` unload requests take no lock and bypass pressure. Raw
|
|
461
|
+
inference waits at most two seconds for host pressure to clear, then returns 503 with `Retry-After`. Raw request-body collection has the configured request deadline too; an incomplete upload
|
|
450
462
|
returns HTTP 408 and releases its guards without contacting Ollama. Admission receipts report
|
|
451
463
|
`queue_wait_ms`, `resource_wait_ms`, `transition_wait_ms`, and
|
|
452
464
|
their sum as `total_wait_ms`. Health and route receipts expose sampled pressure and reservations.
|
|
@@ -599,7 +611,7 @@ expected revision. Warming uses ordinary admission and fit checks; omitted resid
|
|
|
599
611
|
a finite measured policy. See [Scope history and model warming](SCOPES_AND_WARMING.md) for the
|
|
600
612
|
public contract and configured limits.
|
|
601
613
|
|
|
602
|
-
In `serve`,
|
|
614
|
+
In `serve`, raw generation traffic shares the primary transition lock and receives
|
|
603
615
|
host-pressure gating, while managed tasks also reserve forecast memory. Direct Ollama callers bypass
|
|
604
616
|
these controls. FreeLlama cannot preempt inference or constrain other processes. A configured but
|
|
605
617
|
unreachable CPU backend makes managed catalog discovery fail closed; raw primary passthrough remains
|
|
@@ -614,8 +626,9 @@ explicit model that is not installed, or a task that exceeds the advertised cont
|
|
|
614
626
|
## Product boundary
|
|
615
627
|
|
|
616
628
|
FreeLlama is not an inference engine, remote provider marketplace, billing layer, hosted model
|
|
617
|
-
registry, general agent runtime, or A2A coordinator. It can authenticate every route
|
|
618
|
-
operator-managed bearer token and refuses unauthenticated nonloopback
|
|
629
|
+
registry, general agent runtime, or A2A coordinator. It can authenticate every route except the
|
|
630
|
+
static UI shell with one operator-managed bearer token and refuses unauthenticated nonloopback
|
|
631
|
+
listeners. An external layer
|
|
619
632
|
must still provide TLS, tenant authorization, tenant-specific limits, and isolation.
|
|
620
633
|
|
|
621
634
|
Use Ollama directly when a caller only needs raw speed from one exact model. Use FreeLlama when the
|
package/docs/CLI.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The `freellama` command starts and inspects the local management layer that agents use to offload
|
|
4
4
|
work. It exposes diagnostics, model routing, managed execution, resource controls, benchmarking,
|
|
5
|
-
and Ollama-compatible passthrough. Use the [README CLI section](https://github.com/bgauryy/FreeLlama/blob/main/README.md#
|
|
5
|
+
and Ollama-compatible passthrough. Use the [README CLI section](https://github.com/bgauryy/FreeLlama/blob/main/README.md#from-the-terminal) for first
|
|
6
6
|
use and this reference to look up commands and controls.
|
|
7
7
|
|
|
8
8
|
## Choose a command
|
|
@@ -78,8 +78,9 @@ npx @octocodeai/freellama serve \
|
|
|
78
78
|
--cpu-model nomic-embed-text:latest
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
FreeLlama rejects a CPU upstream with no assignments,
|
|
82
|
-
|
|
81
|
+
FreeLlama rejects a CPU upstream with no assignments, `--cpu-model` without `--cpu-upstream`, and a
|
|
82
|
+
CPU upstream that is the same Ollama endpoint as `--upstream`, including loopback aliases on one port.
|
|
83
|
+
It also sets `options.num_gpu=0` on CPU-assigned managed requests.
|
|
83
84
|
Read [CPU and GPU model routing](CPU_GPU_ROUTING.md) before deploying this layout.
|
|
84
85
|
|
|
85
86
|
After startup, require `contracts.placement_observation` and `placement_evidence_gate`, then inspect
|
|
@@ -145,20 +146,27 @@ FreeLlama first unloads idle unpinned runners, then dispatches anyway: the recei
|
|
|
145
146
|
load fits. On Linux, Windows, and other platforms, where available RAM already counts reclaimable
|
|
146
147
|
cache (and is the hard cap in a container), the same shortfall unloads idle runners and then holds the
|
|
147
148
|
new load with `held_insufficient_capacity` until capacity returns, refusing with 503 at its deadline.
|
|
148
|
-
OS memory pressure holds work
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
OS memory pressure holds all work where the OS reports it (macOS, and Linux when the kernel
|
|
150
|
+
exposes `/proc/pressure/memory`; Windows has no host collector yet). Active swapping and low RAM hold new loads only:
|
|
151
|
+
an already-resident runner adds no memory and stays admitted. The CPU-load hold (one-minute load at
|
|
152
|
+
or above 1.5 per logical CPU) applies only to CPU-assigned work, which decodes on those cores; GPU
|
|
153
|
+
work, loaded or not, proceeds, so another program's build never blocks a GPU model. On a host where
|
|
154
|
+
the sampler sees no accelerator (no GPU device or GPU memory), every model runs on the CPU, so the
|
|
155
|
+
hold applies to all work there. The
|
|
156
|
+
thermal-throttling hold applies to CPU-assigned work and to cold loads, a new heat source; a bounded
|
|
157
|
+
request on a runner already resident on the GPU proceeds. The receipt's `resource_admission.assessment.held_by`
|
|
153
158
|
lists the holds that applied to the request.
|
|
154
159
|
Both `serve` and `proxy` accept `--resource-telemetry-policy`:
|
|
155
160
|
|
|
156
|
-
- `require-memory` (default): wait or refuse local inference when available RAM is
|
|
157
|
-
raw requests with zero forecast bytes. Missing thermal data alone does not block
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
- `require-memory` (default on Linux and macOS): wait or refuse local inference when available RAM is
|
|
162
|
+
unknown, including raw requests with zero forecast bytes. Missing thermal data alone does not block
|
|
163
|
+
this policy.
|
|
164
|
+
- `require-all`: require all signals applicable to the collector. The built-in Linux collector reads
|
|
165
|
+
OS memory pressure from `/proc/pressure/memory` when the kernel provides it, but has no thermal
|
|
166
|
+
signal and marks it as unsupported; custom collectors must provide it. Unsupported signals are not
|
|
167
|
+
evidence of healthy hardware.
|
|
168
|
+
- `best-effort`: explicitly permit unknown telemetry unless an observed pressure hold is active. This
|
|
169
|
+
is the default on Windows, which has no built-in memory collector.
|
|
162
170
|
|
|
163
171
|
Remote upstreams bypass local host policy. Raw metadata and empty unload requests remain available
|
|
164
172
|
during a hold. Route receipts separate `queue_readiness` from `resource_readiness`, and include
|
|
@@ -320,8 +328,6 @@ The MCP server autostarts `serve` with its own environment and an arbitrary work
|
|
|
320
328
|
put a machine-wide policy in the config directory or set the variables in the MCP client's `env`.
|
|
321
329
|
`serve` prints each file it picked up.
|
|
322
330
|
|
|
323
|
-
Replace `MODEL` with the directory containing your completed quality-evaluation aggregate.
|
|
324
|
-
|
|
325
331
|
`policy from-eval` reads `pass_at_1`, not the throughput produced by `bench-all`. It refuses
|
|
326
332
|
expired aggregates and fewer than three trials unless `--allow-smoke` is explicit, and it skips
|
|
327
333
|
models that are not installed on `--ollama-endpoint` (default `FREELLAMA_OLLAMA_ENDPOINT`, then
|
package/docs/CPU_GPU_ROUTING.md
CHANGED
|
@@ -56,7 +56,7 @@ flowchart TB
|
|
|
56
56
|
CP --> CPU["CPU runner"]
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
FreeLlama does not
|
|
59
|
+
FreeLlama does not rewrite raw passthrough request bodies or route them by model. A direct Ollama client that
|
|
60
60
|
needs model-aware CPU placement must use the managed task endpoint instead.
|
|
61
61
|
|
|
62
62
|
## Start the backends
|
|
@@ -117,7 +117,7 @@ unsafe or ambiguous configurations:
|
|
|
117
117
|
- A CPU model assignment without `--cpu-upstream`
|
|
118
118
|
- Empty model names
|
|
119
119
|
- The same socket expressed through aliases such as `localhost:11434` and `127.0.0.1:11434`
|
|
120
|
-
-
|
|
120
|
+
- An upstream that points back to the FreeLlama listener, or an unspecified host such as `0.0.0.0`
|
|
121
121
|
|
|
122
122
|
A nonloopback FreeLlama listener requires `--allow-remote` and bearer-token authentication.
|
|
123
123
|
See the [production runbook](PRODUCTION.md) for remote ingress requirements.
|
|
@@ -216,7 +216,7 @@ curl --silent http://127.0.0.1:11436/api/ps | jq '.models[] | {name, size, size_
|
|
|
216
216
|
A fully CPU-loaded model reports `size_vram:0`; a fully GPU-loaded model reports positive VRAM
|
|
217
217
|
covering its resident `size`. Compare both values from the same `/api/ps` entry. Installed `/api/tags`
|
|
218
218
|
file bytes can differ from resident memory and cannot prove a mixed placement. Positive VRAM without
|
|
219
|
-
total resident size stays unknown. `observation.status` is `verified`, `mismatch`, or unavailable
|
|
219
|
+
total resident size stays unknown. `observation.status` is `verified`, `mismatch`, `not_resident`, or `unavailable`. Unknown, mixed, and mismatched
|
|
220
220
|
samples are reported but excluded from adaptive feedback.
|
|
221
221
|
|
|
222
222
|
## Understand concurrency
|
|
@@ -252,17 +252,18 @@ FreeLlama can overlap requests across the two servers even when each Ollama proc
|
|
|
252
252
|
`OLLAMA_NUM_PARALLEL=1`. Raising `OLLAMA_NUM_PARALLEL` affects parallel requests within one server
|
|
253
253
|
and multiplies K/V-cache memory; it is a separate tuning decision. `OLLAMA_MAX_QUEUE` likewise
|
|
254
254
|
bounds each Ollama process after FreeLlama admission. It does not replace either backend's weighted
|
|
255
|
-
FreeLlama budget, bounded waiter count, or queue-wait deadline. Raw passthrough uses a
|
|
256
|
-
one-stream default cap in `serve`; its permit is held until the streamed response ends or is dropped.
|
|
255
|
+
FreeLlama budget, bounded waiter count, or queue-wait deadline. Raw generation passthrough uses a
|
|
256
|
+
separate one-stream default cap in `serve`; its permit is held until the streamed response ends or is dropped.
|
|
257
257
|
|
|
258
258
|
The runtime file's `[task_costs]` table can tune individual task-kind weights without increasing
|
|
259
259
|
the entire pool's ceiling. Default vision weight four can serialize two vision requests under a
|
|
260
260
|
four-unit budget even when Ollama has two slots. A lower weight requires a qualified workload;
|
|
261
261
|
it does not add engine slots or relax memory checks. See
|
|
262
262
|
[monitoring controls](MONITORING.md#adaptive-concurrency).
|
|
263
|
-
|
|
264
|
-
lock and receive 503
|
|
265
|
-
|
|
263
|
+
Raw generation requests also require exclusive access to the primary backend's managed transition
|
|
264
|
+
lock and receive 503 if it stays busy past the raw queue wait. Metadata GET/HEAD, `/api/show`,
|
|
265
|
+
model-store calls (pull, push, copy, delete), and empty `keep_alive:0` unloads remain available.
|
|
266
|
+
This prevents raw inference from overlapping a managed generation on that backend.
|
|
266
267
|
|
|
267
268
|
## Understand automatic feedback
|
|
268
269
|
|
|
@@ -382,9 +383,8 @@ A configured but unreachable CPU backend causes model discovery to fail closed.
|
|
|
382
383
|
can also be unavailable until the secondary server returns. Raw passthrough to the primary server
|
|
383
384
|
continues to work because it does not depend on catalog discovery.
|
|
384
385
|
|
|
385
|
-
For the surrounding
|
|
386
|
-
|
|
387
|
-
[CLI reference](CLI.md).
|
|
386
|
+
For the surrounding Ollama settings, see [Production](PRODUCTION.md#configure-ollama-explicitly). For
|
|
387
|
+
all `serve` flags, see the [CLI reference](CLI.md).
|
|
388
388
|
|
|
389
389
|
## Upstream sources
|
|
390
390
|
|
package/docs/MODEL_SELECTION.md
CHANGED
|
@@ -4,8 +4,9 @@ To offload a task, select an installed model with the required capabilities and
|
|
|
4
4
|
then check its memory fit under the intended concurrency. FreeLlama applies model eligibility
|
|
5
5
|
and admission; the calling agent still verifies the output.
|
|
6
6
|
|
|
7
|
-
The measurements in this guide come from
|
|
8
|
-
|
|
7
|
+
The measurements in this guide come from single machines and are not compiled into routing:
|
|
8
|
+
[Recommended starting points](#recommended-starting-points-by-form) from an Apple M2 Pro with 32 GB,
|
|
9
|
+
the sections after it from an Apple M4 Pro with 48 GB unified memory. Re-run
|
|
9
10
|
`npx @octocodeai/freellama doctor`, `models`, `bench-all`, and your quality suite on the target hardware.
|
|
10
11
|
`doctor.machine.memory_bytes` is host RAM; a discrete GPU's usable VRAM must be observed separately.
|
|
11
12
|
|
|
@@ -26,14 +27,55 @@ flowchart TD
|
|
|
26
27
|
M -->|"Yes"| B["Benchmark locally and add policy evidence"]
|
|
27
28
|
```
|
|
28
29
|
|
|
30
|
+
## Recommended starting points by form
|
|
31
|
+
|
|
32
|
+
Measured on an Apple M2 Pro with 32 GB, Ollama 0.40.8 and FreeLlama 0.6.1 on 2026-10-30, while
|
|
33
|
+
other builds kept the one-minute load near 14 on 12 cores. Every check had a known answer; the
|
|
34
|
+
batteries are small, so treat these as first picks to re-check on your machine, not rankings.
|
|
35
|
+
|
|
36
|
+
| Form | Model (download) | Measured | Speed (warm) | How an agent calls it |
|
|
37
|
+
|---|---|---|---|---|
|
|
38
|
+
| Text, tools, JSON, reasoning | `gpt-oss:20b` (13.8 GB) | 7/7: exact output, arithmetic, bat-and-ball, code reading, JSON extraction, tool call, 9/9 ticket routing | 1.4 s per routed ticket | `run_task {model:"gpt-oss:20b", prompt, think:"low"}`; add `tools` or `format:"json"` |
|
|
39
|
+
| Embeddings | `nomic-embed-text:v1.5` (274 MB) | Retrieval 4/4 top-1; ticket routing 9/9 from two examples per team | 51 ms per item, batched | `run_task {task:"embedding", input:[...], returnEmbeddings:true}` |
|
|
40
|
+
| Decisions (classify, route, score) | `strands-decider:2b-nvfp4` (1.3 GB) | Ticket routing 9/9, return-policy yes/no 3/3, damage rubric 2/3 | 0.17 s per question | `POST <serve>/v1/systemone {model, state, questions}`: passthrough, no MCP tool yet |
|
|
41
|
+
| OCR | `glm-ocr:latest` (2.2 GB) | 4/4 phrases from a dense report strip; 0/7 on text tasks | 11 s per strip at a 400-token cap | `run_task {task:"vision", model:"glm-ocr", prompt:"Text Recognition:", images:[...], stopOnRepetition:true}` |
|
|
42
|
+
|
|
43
|
+
`gpt-oss:20b` reasons before answering; the battery ran it with `think:"low"` and a 2,048-token
|
|
44
|
+
output cap, so leave room for the reasoning when you set `num_predict`. `glm-ocr` reads text from images only and keeps generating
|
|
45
|
+
after the visible text ends, so cap its output or set `stopOnRepetition`. The decision model needs
|
|
46
|
+
Apple silicon and answers only through Ollama's decision API; reach it through `serve` so the call
|
|
47
|
+
still passes FreeLlama's memory checks and stream cap (from 0.6.2 a busy CPU no longer refuses it).
|
|
48
|
+
|
|
49
|
+
### Classify text three ways
|
|
50
|
+
|
|
51
|
+
The same nine support tickets, routed to billing, technical or returns:
|
|
52
|
+
|
|
53
|
+
| Approach | Model | Correct | Per item | Use when |
|
|
54
|
+
|---|---|---:|---:|---|
|
|
55
|
+
| Embeddings and per-class centroids | `nomic-embed-text:v1.5` | 9/9 | 51 ms | Many items, stable classes, a few labeled examples per class |
|
|
56
|
+
| Decision model | `strands-decider:2b-nvfp4` | 9/9 | 0.5 s (first call includes the load) | You need probabilities, yes/no policy checks or rubric scores |
|
|
57
|
+
| Instruction model with JSON output | `gpt-oss:20b` | 9/9 | 1.4 s | Classes change per request or need explanation |
|
|
58
|
+
|
|
59
|
+
A decision API request names its questions; each answer comes back under the same name:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
curl -s http://127.0.0.1:11435/v1/systemone -H 'content-type: application/json' -d '{
|
|
63
|
+
"model": "strands-decider:2b-nvfp4",
|
|
64
|
+
"state": "Why did my credit card get billed two times?",
|
|
65
|
+
"questions": {"team": {"type": "choice", "instructions": "Which team handles this ticket?",
|
|
66
|
+
"criteria": {"billing": "Charges and invoices", "technical": "App errors", "returns": "Returns and refunds"}}}
|
|
67
|
+
}'
|
|
68
|
+
```
|
|
69
|
+
|
|
29
70
|
## Text, code, and vision
|
|
30
71
|
|
|
31
72
|
`qwen3.8:27b-mlx` was the strongest general model in the local evaluations. It handled coding,
|
|
32
73
|
grounded research, image description, OCR, and summarization. Using one large multimodal model also
|
|
33
74
|
avoided contention between separate heavy text and vision runners.
|
|
34
75
|
|
|
35
|
-
|
|
36
|
-
and
|
|
76
|
+
In those evaluations it was strong at grounded lookup, long-context retrieval and strict instruction
|
|
77
|
+
following, needed `think:true` and a generous output budget for multi-step reasoning, and about a
|
|
78
|
+
third of its unsupervised code-review findings were false or context-limited.
|
|
37
79
|
These examples do not establish that a tag is installed or suitable on your host.
|
|
38
80
|
|
|
39
81
|
Dedicated OCR models answer best to the prompts their model card documents; send them with base64
|
package/docs/MONITORING.md
CHANGED
|
@@ -118,8 +118,9 @@ The ledger lives next to the feedback file in the platform data directory. Choos
|
|
|
118
118
|
`/metrics` exposes counters (`freellama_tasks_total`, `freellama_prompt_tokens_total`,
|
|
119
119
|
`freellama_output_tokens_total`, `freellama_task_seconds_total`, `freellama_queue_wait_seconds_total`,
|
|
120
120
|
`freellama_load_seconds_total`, `freellama_raw_requests_total`, `freellama_evictions_total`,
|
|
121
|
-
`freellama_circuit_open_total`, `freellama_concurrency_limit_changes_total`)
|
|
122
|
-
backend, task, and outcome,
|
|
121
|
+
`freellama_circuit_open_total`, `freellama_concurrency_limit_changes_total`); task counters are
|
|
122
|
+
labelled by model, backend, task, and outcome, raw requests by kind and outcome, and the rest by
|
|
123
|
+
backend. Gauges cover admission, queues, the raw proxy, host and GPU memory,
|
|
123
124
|
loaded models, and `freellama_ollama_num_parallel`. Point Prometheus, Grafana Agent, or any
|
|
124
125
|
OpenMetrics-compatible scraper at it.
|
|
125
126
|
|
|
@@ -132,7 +133,7 @@ FreeLlama waits for safe capacity within a deadline and bounds the retained back
|
|
|
132
133
|
| Managed queue full | `429` | `admission_queue_full` |
|
|
133
134
|
| Raw proxy over its cap after `raw_queue_wait_seconds` | `429` | |
|
|
134
135
|
| Managed wait exceeded `max_queue_wait_seconds` (or the task's `max_wait_seconds`) | `503` | `admission_timeout` |
|
|
135
|
-
| OS pressure, swapping, CPU, thermal, or required telemetry still holds when the waiting budget expires (low available RAM alone only warns; low RAM and swapping never hold an already-resident runner) | `503` | `resource_admission_unavailable` |
|
|
136
|
+
| OS pressure, swapping, CPU, thermal, or required telemetry still holds when the waiting budget expires (low available RAM alone only warns on macOS; low RAM and swapping never hold an already-resident runner, and CPU load and thermal never hold one on the GPU) | `503` | `resource_admission_unavailable` |
|
|
136
137
|
| Backend circuit open | `503` | `upstream_circuit_open` |
|
|
137
138
|
|
|
138
139
|
These capacity refusals carry a `Retry-After` header and `retry_after_seconds` in the body. For a queue it
|
|
@@ -267,9 +268,10 @@ out-of-memory shrink-and-retry only applies when the context was not requested e
|
|
|
267
268
|
|
|
268
269
|
With `context_mode = "ollama_default"` (the default), FreeLlama sizes the context as before but
|
|
269
270
|
omits `num_ctx` when Ollama's own default for the model is known, covers the request, and is at most
|
|
270
|
-
`auto_context_max` (32768). The default is
|
|
271
|
-
then `OLLAMA_CONTEXT_LENGTH`, then (
|
|
272
|
-
|
|
271
|
+
`auto_context_max` (32768). The default is the Modelfile's `num_ctx`, then the
|
|
272
|
+
runtime file's `ollama_default_context`, then `OLLAMA_CONTEXT_LENGTH`, then (primary backend
|
|
273
|
+
on a discrete GPU only) Ollama's VRAM tier, from total VRAM minus `OLLAMA_GPU_OVERHEAD` — 4096 below
|
|
274
|
+
23 GiB, 32768 below 47 GiB, 262144 from 47 GiB. Receipts show `context_sizing.num_ctx_sent` and the default used.
|
|
273
275
|
Memory estimates always use the context Ollama can allocate. Use `"explicit"` to always
|
|
274
276
|
send `num_ctx`.
|
|
275
277
|
|
package/docs/PRODUCTION.md
CHANGED
|
@@ -34,17 +34,18 @@ published tag:
|
|
|
34
34
|
powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1 -Version VERSION
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
The repository has no CI or release workflows; they were removed (see git history).
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
The repository has no CI or release workflows; they were removed (see git history). Release from a
|
|
38
|
+
clean checkout: `yarn release:version <version>`, `yarn release:build` (builds each target's
|
|
39
|
+
executable and addon into `release-artifacts/<target>/`), `node scripts/assemble-release.mjs
|
|
40
|
+
release-artifacts release`, then `yarn release:verify:publish`. The publish verifier checks that
|
|
41
|
+
`FREELLAMA_RELEASE_TAG`, when set, matches the workspace version.
|
|
40
42
|
Live E2E and hardware qualification remain separate operator checks; verify those receipts before tagging.
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`
|
|
46
|
-
|
|
47
|
-
registry credentials in the release environment; never store them in the repository.
|
|
44
|
+
Attach `release/SHA256SUMS` and binaries to the release. Publish the eight `@octocodeai/freellama-native-*` packages
|
|
45
|
+
first, followed by the exact-version `@octocodeai/freellama` and `@octocodeai/freellama-mcp-server` packages. Publish
|
|
46
|
+
the Rust crates from the same commit with `cargo publish --workspace` (it uploads `freellama-core`
|
|
47
|
+
before `freellama-cli`; run it with `--dry-run` first). Configure registry credentials (`npm login`,
|
|
48
|
+
`cargo login`) in the release environment; never store them in the repository.
|
|
48
49
|
|
|
49
50
|
## Configure Ollama explicitly
|
|
50
51
|
|
|
@@ -82,7 +83,7 @@ FreeLlama and Ollama have separate queues. FreeLlama caps retained managed waite
|
|
|
82
83
|
`--max-queued-tasks`/`--cpu-max-queued-tasks`, then waits for at most
|
|
83
84
|
`--max-queue-wait-seconds`. An admitted request can then enter Ollama's internal queue,
|
|
84
85
|
which is bounded by `OLLAMA_MAX_QUEUE`. Raw compatibility traffic bypasses weighted managed
|
|
85
|
-
admission and enters the primary Ollama queue through a separate one-stream default cap in `serve`.
|
|
86
|
+
admission and, for generation, enters the primary Ollama queue through a separate one-stream default cap in `serve`.
|
|
86
87
|
Set all limits from observed latency and overload behavior; changing one does not configure the
|
|
87
88
|
others.
|
|
88
89
|
|
|
@@ -91,7 +92,7 @@ The following flow shows where each production setting applies:
|
|
|
91
92
|
```mermaid
|
|
92
93
|
flowchart LR
|
|
93
94
|
C["Client"] --> FQ["FreeLlama admission<br/>weighted budget + wait deadline"]
|
|
94
|
-
FQ -->|"refused"| E503["503 server busy"]
|
|
95
|
+
FQ -->|"refused"| E503["429 or 503 server busy"]
|
|
95
96
|
FQ -->|"admitted"| OQ["Ollama queue<br/>OLLAMA_MAX_QUEUE"]
|
|
96
97
|
RAW["Raw /api/* or /v1/*"] --> RC["Raw stream cap<br/>default 1 in serve"]
|
|
97
98
|
RC -->|"refused"| E503
|
|
@@ -102,14 +103,24 @@ flowchart LR
|
|
|
102
103
|
|
|
103
104
|
These values are conservative starting points, not universal constants. NVIDIA, AMD, Apple, and
|
|
104
105
|
CPU-only hosts must pass hardware validation before promotion. See
|
|
105
|
-
[Ollama and FreeLlama optimization](dev/OLLAMA_SYSTEM_OPTIMIZATION.md) for the ownership boundary and
|
|
106
106
|
[Run models on CPU and GPU](CPU_GPU_ROUTING.md) for device-specific controls.
|
|
107
107
|
|
|
108
|
+
Ollama already picks the accelerator, fits the model to device memory, splits layers between CPU
|
|
109
|
+
and GPU, and schedules requests; FreeLlama decides which tasks reach it. These changes do not help:
|
|
110
|
+
|
|
111
|
+
- Forcing one model's layers between CPU and GPU: partial CPU offload usually lowers decode speed.
|
|
112
|
+
Run a separate CPU-only Ollama process for a second model instead.
|
|
113
|
+
- Running Ollama in Docker on macOS: Docker Desktop gives it no GPU acceleration there.
|
|
114
|
+
- Raising context globally: K/V memory grows with context; size `num_ctx` per request.
|
|
115
|
+
- Pinning several large models in one process without the memory arithmetic: weights, runtime
|
|
116
|
+
buffers and every active context must fit together.
|
|
117
|
+
- `q4_0` K/V cache as a default: it trades more quality than `q8_0` for the memory it saves.
|
|
118
|
+
|
|
108
119
|
Put the values in the service manager that owns each Ollama process: launchd on macOS, systemd or
|
|
109
120
|
the container definition on Linux, and the Windows service wrapper. Shell exports and
|
|
110
121
|
`launchctl setenv` are useful diagnostics but are login-session state, not a reboot-persistent
|
|
111
|
-
production configuration. After a real service restart, rerun `doctor` and `
|
|
112
|
-
require the same visible values before admitting work.
|
|
122
|
+
production configuration. After a real service restart, rerun `freellama doctor` and `freellama status`
|
|
123
|
+
and require the same visible values before admitting work.
|
|
113
124
|
|
|
114
125
|
## Create the security and state files
|
|
115
126
|
|
|
@@ -170,7 +181,8 @@ only model identifiers, scale, and sample count; they contain no prompts.
|
|
|
170
181
|
Keep adapter context settings distinct from Ollama server context. `FREELLAMA_AGENT_NUM_CTX`
|
|
171
182
|
budgets the adapter conversation; older tool observations are compacted inside that budget while
|
|
172
183
|
the system prompt and original question remain pinned by default. `OLLAMA_CONTEXT_LENGTH` controls
|
|
173
|
-
direct Ollama requests
|
|
184
|
+
direct Ollama requests; managed FreeLlama tasks size their own context and send `num_ctx` unless
|
|
185
|
+
Ollama's known default covers it.
|
|
174
186
|
|
|
175
187
|
## Verify lifecycle and placement
|
|
176
188
|
|
|
@@ -187,10 +199,10 @@ Require these health contracts before admitting traffic:
|
|
|
187
199
|
- `placement_observation: ollama_api_ps_after_execution`
|
|
188
200
|
- `placement_evidence_gate: configured_or_observed`
|
|
189
201
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
backend topology,
|
|
193
|
-
the Ollama process does not expose to FreeLlama.
|
|
202
|
+
With `FREELLAMA_AUTH_TOKEN_FILE` set, run `freellama doctor` (Ollama and CLI versions, visible Ollama
|
|
203
|
+
settings, machine) and read `/_freellama/v1/health` (FreeLlama version, `security`, `feedback.persistence`,
|
|
204
|
+
`backends`) and `freellama status` (backend topology, loaded models, admission). Also inspect the
|
|
205
|
+
service definition for any setting that the Ollama process does not expose to FreeLlama.
|
|
194
206
|
|
|
195
207
|
## Validate every hardware class
|
|
196
208
|
|
package/docs/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
FreeLlama helps agents offload bounded work to local models through Ollama. The calling agent owns
|
|
4
4
|
the task and verifies the answer; FreeLlama manages model selection and resources around execution.
|
|
5
|
-
Start with the [repository MCP setup](https://github.com/bgauryy/FreeLlama/blob/main/README.md#
|
|
5
|
+
Start with the [repository MCP setup](https://github.com/bgauryy/FreeLlama/blob/main/README.md#mcp-server) to run one managed task.
|
|
6
6
|
|
|
7
7
|
## Choose a guide
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ Start with the [repository MCP setup](https://github.com/bgauryy/FreeLlama/blob/
|
|
|
19
19
|
| Understand raw Ollama compatibility | [Ollama sidecar](ARCHITECTURE.md#ollama-sidecar) |
|
|
20
20
|
| Evaluate context offload and its cost | [Token economics](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#token-economics) |
|
|
21
21
|
| Deploy the management layer | [Production runbook](PRODUCTION.md) |
|
|
22
|
-
| Run development and release checks | [Testing](TESTING.md), [release
|
|
22
|
+
| Run development and release checks | [Testing](TESTING.md), [release packages](TESTING.md#verify-release-packages) |
|
|
23
23
|
| Embed the routing core | [Rust core](https://github.com/bgauryy/FreeLlama/blob/main/packages/rust-core/README.md) |
|
|
24
24
|
| Use the read-only status page | `/_freellama/ui` on a running `serve` (see [Monitoring](MONITORING.md)) |
|
|
25
25
|
|
|
@@ -27,10 +27,6 @@ Start with the [repository MCP setup](https://github.com/bgauryy/FreeLlama/blob/
|
|
|
27
27
|
|
|
28
28
|
| Goal | Source |
|
|
29
29
|
|---|---|
|
|
30
|
-
| Review dated findings and project comparisons | [Findings report](dev/FINDINGS_AND_POSITIONING.md) |
|
|
31
|
-
| Measure inference, device activity, and thermal behavior | [Local performance testing](dev/LOCAL_PERFORMANCE_TESTING.md) |
|
|
32
|
-
| Separate management controls from inference tuning | [Ollama optimization boundary](dev/OLLAMA_SYSTEM_OPTIMIZATION.md) |
|
|
33
|
-
| Understand backend selection decisions | [Resource-routing ADR](dev/ADR_RESOURCE_AWARE_BACKEND_ROUTING.md) |
|
|
34
30
|
|
|
35
31
|
Historical measurements describe one model, machine, and workload. Inspect current state and
|
|
36
32
|
repeat the relevant checks before using them to select models or set resource limits.
|
package/docs/TESTING.md
CHANGED
|
@@ -24,8 +24,8 @@ yarn install
|
|
|
24
24
|
yarn build
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
The root build compiles the host Rust release binary, NAPI addon, and
|
|
28
|
-
|
|
27
|
+
The root build compiles the host Rust release binary, NAPI addon, and MCP JavaScript bundles
|
|
28
|
+
(server and research adapters). The native `.node` addon remains external to the JavaScript bundle because it is selected
|
|
29
29
|
by platform triple at runtime. Published packages resolve it from an OS/CPU/libc-specific optional
|
|
30
30
|
dependency rather than compiling Rust during installation.
|
|
31
31
|
|
|
@@ -40,7 +40,6 @@ Yarn. Use the `:js` or `:rust` variants to run one side only.
|
|
|
40
40
|
| All package unit tests (JS + Rust) | `yarn test` | Rust toolchain |
|
|
41
41
|
| JavaScript unit | `yarn test:js` | None |
|
|
42
42
|
| Rust contracts | `yarn test:rust` | Rust toolchain |
|
|
43
|
-
| Local-agent contracts | `yarn test:agents` | None after install; builds the MCP package |
|
|
44
43
|
| TypeScript | `yarn typecheck` | None after install |
|
|
45
44
|
| MCP integration | `yarn test:integration` | Ollama at `FREELLAMA_OLLAMA_ENDPOINT` (default `127.0.0.1:11434`) |
|
|
46
45
|
| MCP end to end | `yarn test:e2e` | Ollama, `freellama serve`, and required models |
|
|
@@ -137,11 +136,11 @@ Usage-ledger unit contracts cover ordered writes, bounded queue overflow, failed
|
|
|
137
136
|
validation, replay, and flush behavior. `monitoring_contract` also checks that a blocked ledger path
|
|
138
137
|
does not hold task completion. Persistence remains best effort, not a zero-loss promise.
|
|
139
138
|
|
|
140
|
-
MCP `serve.test.ts` checks startup permission failure, retry,
|
|
139
|
+
MCP `serve.test.ts` checks startup permission failure, retry, child-lifecycle isolation, and the
|
|
140
|
+
background start at launch. The
|
|
141
141
|
protocol integration contracts verify that spawn failure leaves the MCP connection usable and that
|
|
142
142
|
fixture-backed library requests fail on unexpected product errors. External catalog availability
|
|
143
|
-
is separate from these deterministic checks.
|
|
144
|
-
Windows static paths alongside traversal refusal.
|
|
143
|
+
is separate from these deterministic checks.
|
|
145
144
|
|
|
146
145
|
Launcher fixtures use `process.execPath` to avoid an extra PATH-resolved shell wrapper. After the
|
|
147
146
|
MCP fixture's real executable-permission refusal, a test-only transport launches that exact fixture
|
|
@@ -211,7 +210,8 @@ yarn release:verify:publish
|
|
|
211
210
|
Build every claimed CLI/native target in a clean environment, assemble `SHA256SUMS`, run the full
|
|
212
211
|
deterministic suite, and inspect every platform package dry run before publishing explicitly.
|
|
213
212
|
Publish the eight `@octocodeai/freellama-native-*` packages before `@octocodeai/freellama` and `@octocodeai/freellama-mcp-server`, all
|
|
214
|
-
at the exact same version
|
|
213
|
+
at the exact same version, then the crates with `cargo publish --workspace` (`--dry-run` first packages
|
|
214
|
+
and compiles both crates from their published sources). A successful local pack dry run proves package contents; it does not
|
|
215
215
|
prove registry publication or another hardware class.
|
|
216
216
|
|
|
217
217
|
## Test one layer while iterating
|