@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.
@@ -1,10 +1,18 @@
1
1
  # Choose local models
2
2
 
3
- Choose models from local evidence, not model-card popularity. The measurements below come from one
4
- Apple M4 Pro machine with 48 GB unified memory and are not compiled into routing. Re-run
3
+ To offload a task, select an installed model with the required capabilities and measured quality,
4
+ then check its memory fit under the intended concurrency. FreeLlama applies model eligibility
5
+ and admission; the calling agent still verifies the output.
6
+
7
+ The measurements in this guide come from one Apple M4 Pro machine with 48 GB unified memory and
8
+ are not compiled into routing. Re-run
5
9
  `npx @octocodeai/freellama doctor`, `models`, `bench-all`, and your quality suite on the target hardware.
6
10
  `doctor.machine.memory_bytes` is host RAM; a discrete GPU's usable VRAM must be observed separately.
7
11
 
12
+ For supported features and sourced publisher use-case guidance, inspect
13
+ `models {view:"installed", includeLibrary:true}` through MCP. [Model metadata](#model-metadata) explains digest matching, variant capabilities,
14
+ custom-model fallbacks, and how to read family claims without treating them as quality measurements.
15
+
8
16
  ```mermaid
9
17
  flowchart TD
10
18
  T{"What must the task do?"}
@@ -24,6 +32,15 @@ flowchart TD
24
32
  grounded research, image description, OCR, and summarization. Using one large multimodal model also
25
33
  avoided contention between separate heavy text and vision runners.
26
34
 
35
+ Read the [retained model profile](https://github.com/bgauryy/FreeLlama/blob/main/skills/freellama/references/model-profile-qwen3.8-27b-mlx.md)
36
+ and [delegation measurements](https://github.com/bgauryy/FreeLlama/blob/main/skills/freellama/references/task-delegation.md) for scope and limits.
37
+ These examples do not establish that a tag is installed or suitable on your host.
38
+
39
+ Dedicated OCR models answer best to the prompts their model card documents; send them with base64
40
+ `images` in `run_task`. A model that repeats its answer until the output cap can run with
41
+ `stopOnRepetition:true`. See [Route images](https://github.com/bgauryy/FreeLlama/blob/main/packages/mcp/README.md#route-images)
42
+ for the early stop and the `output_check` receipt.
43
+
27
44
  `muse-glimmer:30b-mlx` was a credible alternative and answered 29 of 30 questions correctly
28
45
  (96.7%) with the Bash adapter, but it was slower and did not add a required capability in this
29
46
  workload.
@@ -48,7 +65,7 @@ keywords, repository search was both faster and more accurate in the measured sa
48
65
 
49
66
  ## Place helper models on CPU when useful
50
67
 
51
- A small embedding or intent model can be assigned to a second CPU Ollama process while a large
68
+ A small embedding or helper model can be assigned to a second CPU Ollama process while a large
52
69
  generation model remains resident on the primary GPU-capable process. This can overlap independent
53
70
  work, but it does not make CPU inference fast. Apple silicon shares memory bandwidth; discrete-GPU
54
71
  systems have different transfer and contention costs and need their own benchmark.
@@ -63,3 +80,109 @@ this machine and workload, not a universal model-placement rule. Follow
63
80
  `bench-all` measures local performance. A quality benchmark measures correctness. FreeLlama needs
64
81
  both the generated task policy and local benchmark data before grading a route medium confidence.
65
82
  See the [CLI reference](CLI.md#earn-medium-routing-confidence) for the commands.
83
+
84
+ ## Model metadata
85
+
86
+ The MCP `models` tool reads your Ollama instance and can enrich results with Ollama's public model
87
+ library. Supported features and advertised use cases are metadata: they do not change routing
88
+ confidence, and exact-model benchmarks and policy remain the quality evidence. The CLI's `models`
89
+ command reports the core catalog and does not expose these enrichment flags.
90
+
91
+ | Request | Result | External access |
92
+ |---|---|---|
93
+ | `models {view:"installed"}` | Managed inventory with a `knowledge` object for each model | Local backend data only |
94
+ | `models {view:"installed", includeLibrary:true}` | Inventory enriched with public guidance for verified local tags | Fetches model family and tag pages from ollama.com |
95
+ | `models {view:"detail", model:"gemma3:1b"}` | Ollama details, maximum context, and supported-use explanations | Selected Ollama endpoint only |
96
+ | `models {view:"detail", model:"gemma3:1b", includeLibrary:true}` | Details plus public guidance after a tag and digest check | Selected Ollama endpoint and ollama.com |
97
+ | `models {view:"library", query:"coding"}` | Public family search with descriptions and advertised feature chips | ollama.com and optional local inventory/profile reads |
98
+ | `models {view:"library", model:"gemma3"}` | All public tags with size, digest prefix, context, modalities, and cloud status | ollama.com and optional local inventory/profile reads |
99
+
100
+
101
+ | Option | Valid views | Default | Meaning |
102
+ |---|---|---|---|
103
+ | `includeLibrary` | `installed`, `detail` | `false` | Requests public metadata; the default makes no website calls |
104
+ | `includeReadme` | Library step 2, or `detail` with `includeLibrary:true` | `false` | Returns README text, capped at 65,536 characters, with its format and truncation flag |
105
+ | `includeVerbose` | `detail` | `false` | Returns Ollama's license and Modelfile fields independently of README enrichment |
106
+ | `limit`, `cursor` | `raw`, library tag listings; `limit` also applies to library search | Tag/raw page size 20; search limit 10 | Pages large lists; the tag cursor rejects a changed tag list |
107
+ | `ollamaEndpoint` | Direct Ollama views and library inventory reads | Configured Ollama endpoint | Chooses the Ollama instance; enriched managed inventory uses each model's assigned backend |
108
+
109
+ An incompatible option returns an error before any lookup. Installed enrichment omits full READMEs;
110
+ request one model's detail to read its README.
111
+
112
+ ### Supported features
113
+
114
+ `knowledge.supportedFeatures` preserves the feature strings from the selected source
115
+ (`supportedFeaturesSource`: `ollama_api` or `freellama_catalog`). Unknown future strings stay visible
116
+ but do not create routing requirements. `knowledge.supportedUseCases` explains each recognized
117
+ feature with `capability`, `use`, `reason`, and `basis:"supported_feature"`;
118
+ `knowledge.quality` stays `"metadata_only"`.
119
+
120
+ | Feature | Supported workflow | What to evaluate separately |
121
+ |---|---|---|
122
+ | `completion` | Text generation | Coding, summarization, reasoning, and instruction-following accuracy |
123
+ | `tools` | Tool calls | Argument correctness, tool selection, and agent-loop reliability |
124
+ | `vision` | Image input | OCR and visual understanding accuracy |
125
+ | `audio` | Audio workflows advertised by the model | Supported audio task and accuracy |
126
+ | `embedding` | Retrieval and similarity vectors | Retrieval quality on your documents |
127
+ | `thinking` | A thinking mode | Reasoning accuracy, latency, and token cost |
128
+ | `insert` | Suffix-based text insertion | Completion accuracy in the target code or text |
129
+ | `image` | Image generation | Output quality and supported controls |
130
+
131
+
132
+ ### Public guidance and provenance
133
+
134
+ For a verified installed model, `knowledge.library` contains the source page, tag-page URL,
135
+ `fetchedAt`, `expiresAt`, `cached`, exact public tag metadata, and:
136
+
137
+ | Field | Meaning |
138
+ |---|---|
139
+ | `description` | The public family description |
140
+ | `advertisedFamilyCapabilities` | Family feature chips; these do not extend the local tag's capabilities |
141
+ | `advertisedUseCases` | Recognized coding, tool-calling, image-understanding/OCR, reasoning, embedding, summarization, question-answering, translation, and long-context claims |
142
+ | `advertisedUseCases[].evidence` | A bounded source excerpt, source URL, and fetch timestamp |
143
+ | `usageNotes` | Bounded excerpts about requirements, restrictions, context, memory, languages, or query prefixes |
144
+ | `readmeAvailable` | Whether a README was extracted |
145
+ | `readme` | Requested text with `format` (`markdown` or `text`) and `truncated` |
146
+
147
+
148
+ Advertised uses have `basis:"advertised"`, `scope:"family"`, and `quality:"unmeasured"`. Extraction
149
+ skips fenced code and negative statements; an omitted use means no recognized claim, not absence.
150
+ These labels are not the `run_task` task enum. Local capabilities filter advertised uses: a family
151
+ vision chip cannot make `gemma3:1b` a vision candidate.
152
+
153
+ Installed enrichment requires the exact public tag and a digest-prefix match of at least 12 hex
154
+ characters. Custom names are never mapped by architecture or guessed base model; without a verified
155
+ match, public guidance is withheld. Library step 2 describes public models before installation, so
156
+ its guidance stays family-scoped; each `tags[]` entry carries its own modalities, context, digest
157
+ prefix, and `cloud` flag. Search's `cloudAvailable` badge does not prove local downloads are absent.
158
+
159
+ ### Lookup states
160
+
161
+ | `library.status` | Meaning | Next action |
162
+ |---|---|---|
163
+ | `not_requested` | Website enrichment was not requested | Set `includeLibrary:true` if external lookup is useful |
164
+ | `matched` | Installed tag and public digest prefix match | Read the sourced guidance, then evaluate the exact tag |
165
+ | `available` | Public family and tag pages were parsed in library step 2 | Inspect the exact tag before recommending a download |
166
+ | `unverified` | Digest or current backend inventory could not be verified | Recheck local inventory; retain local feature information |
167
+ | `digest_mismatch` | The public tag differs from the installed digest | Treat public guidance as unavailable for this installed model |
168
+ | `tag_not_found` | The parsed public tag list has no exact matching tag | Check the source and custom-model provenance |
169
+ | `unmatched` | The name cannot resolve to an exact public Ollama name | Keep use-case suitability unknown until provenance is verified |
170
+ | `not_found` | A requested public page returned HTTP 404 | Check the source URL or custom name |
171
+ | `unavailable` | Transport, timeout, HTTP refusal, or page-size limit prevented lookup | Retry later; local results remain available |
172
+ | `parse_error` | HTML content or tag rows were not recognized | Inspect the source; do not conclude the model is absent |
173
+ | `remote_model`, `remote_tag` | Remote Ollama fields or a hosted tag identify cloud execution | Select a local download tag for local execution |
174
+
175
+
176
+ `localModel:false` flags detected remote entries; cloud tags never become local trial
177
+ recommendations. This metadata is not processor-placement evidence.
178
+
179
+ ### Cache and request bounds
180
+
181
+ Each MCP process caches at most 128 families: successes for one hour, failures for one minute;
182
+ concurrent requests share one lookup and a restart clears the cache. Installed enrichment runs at
183
+ most four family lookups concurrently. Requests use GET, refuse redirects, cap each page at 2 MiB,
184
+ and time out after the smaller of 10 seconds and `FREELLAMA_MCP_FETCH_TIMEOUT_SECONDS`. They disclose
185
+ the requested public family name to ollama.com. Download size does not establish runtime memory
186
+ fit, placement, or quality, and model discovery never authorizes a pull. Sources:
187
+ [model details API](https://docs.ollama.com/api-reference/show-model-details),
188
+ [model-list API](https://docs.ollama.com/api/tags).
@@ -0,0 +1,293 @@
1
+ # Runtime status and live tuning
2
+
3
+ Use runtime status to inspect how FreeLlama manages delegated work: per-backend queues and
4
+ admission, memory pressure, resident models, execution usage, and resource holds. The operator can
5
+ reload supported limits without a restart; the calling agent can use these observations to decide
6
+ whether to wait, narrow a task, or handle it itself.
7
+
8
+ The API endpoints in this reference are served under `/_freellama/v1/` and use the same bearer
9
+ token as the rest of the control API when authentication is enabled.
10
+
11
+ Open **`http://127.0.0.1:11435/_freellama/ui`** (the address `serve` prints at startup) for a live
12
+ page of the same data, refreshed every two seconds: backends and queues, raw traffic, host RAM and
13
+ VRAM, Ollama's settings, loaded models with their current tasks and load times, and the last
14
+ eviction. The page itself is static and needs no token; when auth is on it asks for the bearer
15
+ token and keeps it only for the browser tab.
16
+
17
+ | Endpoint | CLI | MCP | What it returns |
18
+ |---|---|---|---|
19
+ | `GET /status` | `freellama status` | `doctor {view:"status"}` | Live view of every backend, the raw proxy, loaded models, host, Ollama settings, and today's usage |
20
+ | `GET /usage?days=N` | `freellama usage --days N` | `doctor {view:"usage", days:N}` | Totals per day and per model (default 7 days) |
21
+ | `GET /metrics` | | | Prometheus text exposition |
22
+ | `GET /config` | `freellama config` | | Effective runtime settings and the source of each |
23
+ | `POST /config/reload` | `freellama config --reload` | | Re-read the runtime file now; `422` keeps the last good values |
24
+ | `GET /jobs` | `freellama jobs` | `task_jobs {action:"list"}` | Deferred job metadata without prompts or retained results |
25
+ | `GET /jobs/:id` | `freellama jobs --id <uuid>` | `task_jobs {action:"get", jobId}` | One job receipt and its retained result or error |
26
+ | `POST /jobs/:id/cancel` | `freellama jobs --id <uuid> --cancel` | `task_jobs {action:"cancel", jobId}` | Cancellation receipt after local permits are released |
27
+ | `DELETE /jobs/:id` | `freellama jobs --id <uuid> --remove` | `task_jobs {action:"remove", jobId}` | Stops active work, releases local permits, and removes the retained record |
28
+
29
+ ## Read the live status
30
+
31
+ `status` answers "why is my task waiting?" in one call:
32
+
33
+ - **`backends.gpu` / `backends.cpu`**: admission (units in use, current limit, ceiling, queue depth,
34
+ oldest wait, refusal and timeout counters), the adaptive limiter state, and the circuit breaker
35
+ (`closed`, `open` with seconds remaining, or `half_open`).
36
+ - **`raw_proxy`**: active and waiting raw streams against their cap and wait budget.
37
+ - **`loaded_models`**: Ollama's `/api/ps` with total and VRAM bytes, context length, expiry, and
38
+ whether the model is pinned.
39
+ - **`host`**: available and reserved RAM, whether the pressure gate is holding, and discrete-GPU
40
+ total and free memory (`nvidia-smi` or amdgpu sysfs) when available. Optional `gpu_activity`
41
+ reports driver counters separately from resident memory. On macOS, `thermal_pressure` is the
42
+ system thermal pressure level (`nominal`, `moderate`, `heavy`, `trapping`, `sleeping`); `heavy`
43
+ or worse holds CPU-assigned work and cold loads. Other platforms report `null`.
44
+ - **`ollama`**: the Ollama server's effective `OLLAMA_*` settings with a source for each — the
45
+ running process's environment (Linux `/proc/<pid>/environ`, macOS `ps eww` for a same-user
46
+ process), `launchctl getenv` for the macOS app, FreeLlama's own environment, or Ollama's default.
47
+ A remote endpoint is never probed and is reported as unknown.
48
+ - **`usage_today`**: tasks, errors, tokens, and busy time since midnight UTC.
49
+ - **`task_jobs`**: deferred task IDs, selected models, configured backends, priorities, total
50
+ deadlines, states, and waiting reasons. States cover discovery, admission, resources, runner
51
+ transitions, loading, execution, and completion. Metadata excludes the original payload.
52
+
53
+ Use `run_task {defer:true}` in MCP or `task --defer` in the CLI to get a job handle. A list or
54
+ status request omits results; fetching one ID returns its retained result or structured failure.
55
+ Terminal states are `completed`, `failed`, `cancelled`, and `expired`. Cancellation is per task,
56
+ waits for local permits to be released, and does not unload a shared runner. Process-local job
57
+ retention limits are documented in [CLI controls](CLI.md#execute-tasks).
58
+
59
+ Removal uses the same exact job ID. It cancels active work before discarding the record, returns
60
+ `{id, removed:true, status, scope:"process_memory"}`, and omits the saved result. The ID then returns
61
+ `404` on lookup or another removal. Other jobs and installed models are unaffected. Local
62
+ cancellation closes the upstream request; physical computation may continue on a shared runner.
63
+
64
+ `ollama.config` describes the primary process; `ollama.cpu_config` describes the CPU process when
65
+ configured. Process attribution matches `OLLAMA_HOST` to the selected endpoint, so separate
66
+ parallelism and KV cache settings size each backend independently. Fallback sources remain visible
67
+ when process settings cannot be observed.
68
+
69
+ Process settings are cached for five seconds and refreshed on discovery or monitoring requests,
70
+ including after an Ollama restart. Each config receipt includes `observed_at` and
71
+ `observation_scope: "process_snapshot"`. Refresh also updates backend memory estimates and
72
+ invalidates the use of measurements taken under different parallelism or KV cache settings.
73
+ FreeLlama admission limits remain governed by its runtime configuration.
74
+
75
+ `host.gpu_activity` is nullable. When available, it identifies its `source`,
76
+ `scope: "observed_devices_all_processes"`, `window: "driver_defined"`, and individual `devices`.
77
+ Each device has an identity, nullable `busy_percent`, and nullable `memory_busy_percent`. Apple
78
+ devices may add `allocated_memory_bytes`, the driver's allocated memory across all processes.
79
+ An observed zero means the driver reported zero; a missing or malformed counter remains unknown.
80
+ Use `host.sample_age_ms` to check freshness.
81
+
82
+ NVIDIA activity comes from the same bounded `nvidia-smi` query as memory. Apple Silicon activity
83
+ comes from the accelerator's `PerformanceStatistics` in a bounded IORegistry read. Those Apple
84
+ properties are driver-specific and may disappear or change; the read can cover only the devices
85
+ within its retained output. AMD, Windows, unsupported drivers, and unavailable reads report unknown activity. The counters include other processes, use a driver-defined observation
86
+ window, and do not attribute activity to a FreeLlama task or establish bandwidth or energy
87
+ efficiency. They are diagnostics and do not alter admission or pressure decisions.
88
+
89
+ Each backend's admission `queue_depth` includes both `slot_waiters` and `resource_waiters`.
90
+ A resource waiter returns its execution slot after two seconds but remains in the bounded queue
91
+ until capacity recovers, its deadline expires, or it is cancelled.
92
+
93
+ ## Record usage
94
+
95
+ Every managed task updates in-memory usage totals and offers one record to a bounded writer queue.
96
+ The record contains time, model, backend, task kind, priority, outcome, HTTP status, prompt and
97
+ output tokens, duration, queue wait, load time, and output tokens per second. It contains no prompt
98
+ or response text. One worker writes records in order; task completion does not wait for disk.
99
+
100
+ The writer queue defaults to 128 records. Configure its positive startup-only capacity through
101
+ `usage_queue_capacity` or `FREELLAMA_USAGE_QUEUE_CAPACITY`; runtime reload does not resize the worker.
102
+ A full queue or unavailable worker drops the record; a disk
103
+ failure records a failed write. Inspect `usage_ledger` in `status`, or `ledger` in `usage`, for
104
+ `pending`, `failed`, `dropped`, `records`, `capacity`, and `last_error`. The durability contract is
105
+ `asynchronous_best_effort`: pending records can be lost on a crash, and in-memory totals can exceed
106
+ persisted totals. Error evidence remains visible after later successful writes.
107
+
108
+ `serve` replays a bounded regular-file ledger at startup and rotates it to `usage.jsonl.1` at
109
+ 16 MiB. Successful writes contribute to restart totals; completion is not a zero-loss persistence
110
+ promise. Embedded callers can use the bounded `flush_ledger` barrier for orderly teardown; it
111
+ confirms attempted writes, not recovery of dropped/failed records or a filesystem sync.
112
+
113
+ The ledger lives next to the feedback file in the platform data directory. Choose another path with
114
+ `--usage-file` (or `FREELLAMA_USAGE_FILE`), or keep totals in memory only with `--ephemeral-usage`.
115
+
116
+ ## Scrape metrics
117
+
118
+ `/metrics` exposes counters (`freellama_tasks_total`, `freellama_prompt_tokens_total`,
119
+ `freellama_output_tokens_total`, `freellama_task_seconds_total`, `freellama_queue_wait_seconds_total`,
120
+ `freellama_load_seconds_total`, `freellama_raw_requests_total`, `freellama_evictions_total`,
121
+ `freellama_circuit_open_total`, `freellama_concurrency_limit_changes_total`) labelled by model,
122
+ backend, task, and outcome, plus gauges for admission, queues, the raw proxy, host and GPU memory,
123
+ loaded models, and `freellama_ollama_num_parallel`. Point Prometheus, Grafana Agent, or any
124
+ OpenMetrics-compatible scraper at it.
125
+
126
+ ## Back-pressure
127
+
128
+ FreeLlama waits for safe capacity within a deadline and bounds the retained backlog:
129
+
130
+ | Situation | Status | `code` |
131
+ |---|---|---|
132
+ | Managed queue full | `429` | `admission_queue_full` |
133
+ | Raw proxy over its cap after `raw_queue_wait_seconds` | `429` | |
134
+ | 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
+ | Backend circuit open | `503` | `upstream_circuit_open` |
137
+
138
+ These capacity refusals carry a `Retry-After` header and `retry_after_seconds` in the body. For a queue it
139
+ is estimated from the queue depth, the lanes that can run at once (current limit divided by the
140
+ task's cost), and the backend's recent average service time, which excludes queue wait (1 to 120
141
+ seconds). A task can ask for a shorter wait with `max_wait_seconds` (`maxWaitSeconds`
142
+ in MCP); the server caps it at the configured maximum.
143
+
144
+ ## Circuit breaker
145
+
146
+ After `breaker_failures` consecutive upstream failures on a backend (connection errors, `500`,
147
+ `502`, or `504`), its circuit opens for `breaker_cooldown_seconds`; tasks routed there fail fast
148
+ with `503` rather than queueing behind a broken Ollama. When the cooldown ends, one probe request is
149
+ let through: success closes the circuit, failure reopens it. `4xx` responses such as an unknown
150
+ model do not count. Set `breaker_failures = 0` to disable it.
151
+
152
+ ## Adaptive concurrency
153
+
154
+ Managed task costs are configurable through the runtime file's `[task_costs]` table. Valid keys
155
+ are `completion`, `coding`, `code_repair`, `tools`, `browser`, `vision`, `embedding`, and
156
+ `long_context`. Each value is a positive integer through 4294967295. Omitted kinds retain their
157
+ defaults: vision four, embeddings one, and other tasks two. Embeddings multiply their base by
158
+ `ceil(input_items/4)`; the acquired charge cannot exceed the pool's current limit.
159
+
160
+ For a qualified light OCR workload, `[task_costs]` with `vision = 2` permits two vision requests
161
+ under a four-unit budget while leaving other task costs unchanged. This is an operator setting,
162
+ not automatic quality or fit qualification. The memory governor and Ollama's final admission
163
+ still apply.
164
+
165
+ A task captures its cost when execution starts. Reload affects tasks that start afterward;
166
+ already queued or active tasks keep their captured cost. `config` reports effective values and
167
+ the runtime-file source; invalid keys, zero,
168
+ or overflow reject the reload and retain the last good configuration. Preview advice, health
169
+ costs, and execution receipts use the resolved policy. Health retains its summary aliases and
170
+ exposes the complete task-kind map under `admission.costs.base_by_task`. Task kinds remain
171
+ caller-declared; these weights are cooperative scheduling policy, not workload classification.
172
+ See the
173
+ [runtime example](https://github.com/bgauryy/FreeLlama/blob/main/freellama.runtime.example.toml) for the table syntax.
174
+
175
+ With `adaptive_concurrency = "cpu"` (the default) or `"all"`, each pool's limit moves between 1 and
176
+ its configured ceiling:
177
+
178
+ - **Down (halve)** on an upstream error, host memory pressure (PSI or the pressure gate), or output
179
+ throughput below 70% of the matching execution profile's baseline. Decreases are at least
180
+ 10 seconds apart.
181
+ - **Up (+1 unit)** after five consecutive comparable healthy rate observations. Generation uses
182
+ output tokens per decode second; embeddings use input tokens per model-reported total second.
183
+ The profile records the metric kind, and unlike kinds cannot train or recover together.
184
+
185
+ Only completed warm executions with verified placement and a comparable observed profile train
186
+ speed baselines or healthy recovery. Identity includes model digest, explicit observed context,
187
+ backend/process settings, effective controls, and admission class. Fresh endpoint-attributed
188
+ process observations bracket candidate serial samples. Unknown identity, changed controls,
189
+ parallel intervals, invalid rate observations, and incomplete or canceled execution break the
190
+ recovery streak. Failures and observed memory pressure retain their safety decreases.
191
+
192
+ Serial samples require one managed task throughout the interval: unchanged admitted/released
193
+ counters, active charge, capacity, and policy epoch reject transient overlap or capacity changes.
194
+ This avoids comparing serial request speed with legitimate parallel decoding. It does not prove
195
+ that no external Ollama client ran concurrently. A successful parallel execution can therefore
196
+ report verified placement and `feedback.accepted:true` while
197
+ `execution.throughput_learning.eligible:false`; it contributes no comparable speed sample.
198
+
199
+ Each backend retains at most one adaptive profile window per task kind. Status exposes
200
+ `adaptive.profile_windows` keyed by task; `baseline_output_tokens_per_second` is a compatibility
201
+ output-only summary by model and can omit additional task windows for the same model. Embedding
202
+ windows report their explicit input-rate kind separately. Use the task windows for learning
203
+ evidence. See [automatic feedback](CPU_GPU_ROUTING.md#understand-automatic-feedback) for
204
+ persisted routing windows.
205
+
206
+ The CPU backend is adaptive by default because oversubscribing it shows up as a throughput collapse
207
+ rather than an error. Every change is counted in metrics and shown in `status`.
208
+
209
+ ## Model residency and eviction
210
+
211
+ Omitted managed `keep_alive` values use finite retention informed by measured reuse and loading.
212
+ Explicit values take precedence. For governed prewarming, profile compatibility, and retention
213
+ settings, see [Scope history and model warming](SCOPES_AND_WARMING.md).
214
+
215
+ When a model about to load needs room, FreeLlama unloads idle runners itself (`keep_alive: 0`)
216
+ instead of letting the load wait, fail, or spill to CPU. It does this in three cases: host RAM
217
+ can fall below the reserve, the host is already holding for low memory, or (discrete GPU) the
218
+ model does not fit in free VRAM, where Ollama otherwise chooses its own victim.
219
+
220
+ Which runners go is a small optimisation, in the spirit of llama-swap's `evict_costs` and LocalAI's
221
+ busy-aware LRU:
222
+
223
+ - **Never unloaded:** the model being loaded, `pinned_models`, `keep_alive: -1` runners, runners
224
+ Ollama is still loading, and any model with a FreeLlama task queued or running (unloading it forces an immediate reload). Busy status is checked again right before each unload.
225
+ - **Not for a model bigger than the GPU:** it spills to the CPU whatever is unloaded, so VRAM is
226
+ left alone.
227
+ - **Cost of unloading a runner** = its reload time (Ollama's measured `load_duration` from earlier
228
+ loads, or size ÷ 1.5 GB/s before the first one) × (1 + recent uses, decaying with a 30-minute
229
+ half-life; only tasks served count) × its `eviction_costs` weight (default 1).
230
+ - **Choice:** the set of runners with the lowest total cost that frees enough memory; ties go to
231
+ fewer runners, then less memory freed beyond what is needed. Only the memory that matters is
232
+ counted: VRAM for a GPU fit, the host-RAM part for a spill, the whole runner on CPU or unified
233
+ memory.
234
+
235
+ Every managed receipt that caused an eviction carries the plan under
236
+ `memory_reservation.eviction`: what was unloaded, its cost and reload estimate, and what was kept
237
+ and why. `status` and the page show the latest one that unloaded something. Eviction runs once per
238
+ task, after admission and before the memory wait, and is never cancelled halfway by a deadline.
239
+ Set `evict_idle_models = false` to leave residency entirely to Ollama.
240
+
241
+ ## Who decides what: FreeLlama and Ollama
242
+
243
+ Two schedulers that both guess at memory can disagree. The split is:
244
+
245
+ | Decision | Owner | How |
246
+ |---|---|---|
247
+ | Exact memory of a loaded runner | Ollama | Measured; FreeLlama reads it from `/api/ps` |
248
+ | Whether a new load fits | Both, Ollama final | FreeLlama estimates from Ollama's past measurements, then Ollama loads or refuses |
249
+ | Decoding slots per model | Ollama | `OLLAMA_NUM_PARALLEL`; FreeLlama's primary budget defaults to two weighted units per slot |
250
+ | Admission, priority, queue limits, back-pressure | FreeLlama | Weighted pools, 429/503 with `Retry-After` |
251
+ | Which idle runner to unload, and when | FreeLlama | The cost planner above, before Ollama has to choose |
252
+ | Context size | Ollama by default | `num_ctx` is left to Ollama when its default covers the request |
253
+
254
+ To keep the estimates honest, FreeLlama learns from every runner Ollama reports as resident,
255
+ including ones loaded by raw clients, and saves those measurements to `footprints.json` next to the
256
+ usage ledger. After a restart a model it has seen before is sized from Ollama's measurement, not a
257
+ formula. Each measurement records the `OLLAMA_NUM_PARALLEL` and KV-cache type it was taken under and
258
+ is used only while those match, so changing either setting falls back to the formula until Ollama
259
+ measures again. A larger context than any measured one is sized as the measurement plus exactly the extra
260
+ KV cache, when the model's KV shape is known.
261
+
262
+ ## Context sizing and Ollama's defaults
263
+
264
+ Sending `num_ctx` on a request pins the runner to that size: a later request for the same model
265
+ with a different or missing `num_ctx` forces Ollama to reload it, and Ollama's automatic
266
+ out-of-memory shrink-and-retry only applies when the context was not requested explicitly.
267
+
268
+ With `context_mode = "ollama_default"` (the default), FreeLlama sizes the context as before but
269
+ 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 resolved in Ollama's order: the Modelfile's `num_ctx`,
271
+ then `OLLAMA_CONTEXT_LENGTH`, then (discrete GPU only) Ollama's VRAM tier — 4096 below 24 GiB, 32768
272
+ below 48 GiB, 262144 above. Receipts show `context_sizing.num_ctx_sent` and the default used.
273
+ Memory estimates always use the context Ollama can allocate. Use `"explicit"` to always
274
+ send `num_ctx`.
275
+
276
+ ## Change settings without a restart
277
+
278
+ Put any of the settings above in a TOML file and start `serve --runtime-config <file>` (or set
279
+ `FREELLAMA_RUNTIME_CONFIG`). Start from
280
+ [`freellama.runtime.example.toml`](https://github.com/bgauryy/FreeLlama/blob/main/freellama.runtime.example.toml). `serve` checks the file every
281
+ two seconds and applies changes to live admission pools; a waiting task sees the new limit at once.
282
+
283
+ Precedence for every setting, strongest first: CLI flag, environment variable (where one exists),
284
+ the runtime file, the built-in default. Only these settings have an environment variable:
285
+ `FREELLAMA_MAX_QUEUE_WAIT_SECONDS`, `FREELLAMA_EVICT_IDLE_MODELS`, `FREELLAMA_USAGE_QUEUE_CAPACITY`,
286
+ and the individual `FREELLAMA_SCOPE_*` and `FREELLAMA_KEEP_ALIVE_*` limits. Set every other key in
287
+ the runtime file or with its CLI flag. A flag or variable pins a value, so editing the file cannot
288
+ override it; `freellama config` shows which source won: `cli`, `env`, `file`, a default source
289
+ such as `default` or `ollama_num_parallel`, or `env_invalid` when a set variable failed validation.
290
+ A malformed file or an unknown key is rejected at reload and the previous values stay in force.
291
+
292
+ The default GPU budget follows the Ollama server: 2 units per `OLLAMA_NUM_PARALLEL` slot (one chat
293
+ per decoding slot), read from the running Ollama process where visible.
@@ -1,17 +1,23 @@
1
1
  # Prepare FreeLlama for production
2
2
 
3
- This runbook prepares a single-operator or trusted-team FreeLlama deployment. FreeLlama now
4
- supports authenticated nonloopback listeners, but it is not a multi-tenant authorization or
5
- billing service. Put TLS and tenant-specific rate limits at an external ingress when traffic
6
- crosses a machine boundary.
3
+ This runbook prepares the FreeLlama management layer for agents using local models in a
4
+ single-operator or trusted-team deployment. Configure the Ollama backends, model evidence,
5
+ authentication, and resource limits before agents submit work.
6
+
7
+ FreeLlama supports authenticated nonloopback listeners. Put TLS and tenant-specific rate limits
8
+ at an external ingress when traffic crosses a machine boundary; FreeLlama's bearer token does
9
+ not provide tenant isolation or billing.
7
10
 
8
11
  ## Meet the prerequisites
9
12
 
10
13
  - Install one Ollama CLI and server version. Run `freellama doctor` and resolve any mismatch.
11
14
  - Install Node.js 20 or later for MCP and npm distribution use.
12
- - Use the release artifacts for your operating system, or build with Rust 1.85 or later.
15
+ - Use the release artifacts for your operating system, or build with Rust 1.88 or later.
13
16
  - Preinstall and benchmark exact model tags. Discovery never authorizes a pull.
14
17
  - Keep the primary and optional CPU Ollama processes on distinct loopback sockets.
18
+ - In a slim or distroless container, install the CA bundle (`ca-certificates`) or set
19
+ `SSL_CERT_FILE` if any upstream uses `https://`. Without one, FreeLlama starts with an empty trust
20
+ store and warns: plain-HTTP upstreams work, HTTPS upstreams fail their certificate check.
15
21
 
16
22
  After a tag has been published, install that exact checksummed release on macOS or Linux:
17
23
 
@@ -28,9 +34,14 @@ published tag:
28
34
  powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1 -Version VERSION
29
35
  ```
30
36
 
31
- There is no repository-hosted release automation. Build and test every claimed target in a clean
37
+ The repository has no CI or release workflows; they were removed (see git history). Build, verify,
38
+ and publish artifacts with the [release procedure](../RELEASE.md). The publish verifier checks that
39
+ a version tag matches the workspace version.
40
+ Live E2E and hardware qualification remain separate operator checks; verify those receipts before tagging.
41
+
42
+ For manual assembly, build and test every claimed target in a clean
32
43
  environment, place each executable and matching addon under `release-artifacts/<target>/`, run
33
- `yarn release:assemble release-artifacts release` and `yarn release:verify:publish`, then attach
44
+ `node scripts/assemble-release.mjs release-artifacts release` and `yarn release:verify:publish`, then attach
34
45
  `release/SHA256SUMS` and binaries to the release. Publish the eight `@octocodeai/freellama-native-*` packages
35
46
  first, followed by the exact-version `@octocodeai/freellama` and `@octocodeai/freellama-mcp-server` packages. Configure
36
47
  registry credentials in the release environment; never store them in the repository.
@@ -52,9 +63,13 @@ swap, eviction churn, or unacceptable queueing.
52
63
  | `OLLAMA_MAX_QUEUE` | Workload-specific, bounded value | Limits Ollama's internal queue independently of FreeLlama admission |
53
64
 
54
65
  Do not set a global `OLLAMA_CONTEXT_LENGTH` merely to maximize the advertised window. Managed
55
- FreeLlama tasks send the smallest sufficient request-specific `num_ctx`; a larger context and a
56
- larger `OLLAMA_NUM_PARALLEL` multiply K/V-cache memory. Direct Ollama clients still follow the
57
- server's context configuration, which defaults to 4096 tokens in current Ollama.
66
+ FreeLlama text tasks estimate a sufficient context and can omit `num_ctx` when Ollama's known default
67
+ covers the request within the configured automatic bound. Explicit context requests send `num_ctx`.
68
+ A larger context and a larger `OLLAMA_NUM_PARALLEL` multiply K/V-cache memory. See
69
+ [context sizing](MONITORING.md#context-sizing-and-ollamas-defaults) for defaults and receipts.
70
+ Direct Ollama clients still follow the
71
+ server's context configuration. Current context documentation describes VRAM-tiered 4k/32k/256k
72
+ defaults while the FAQ still says 4096, so treat `/api/ps` `context_length` after load as authority.
58
73
 
59
74
  `freellama doctor` returns `local_conservative_config_posture` as a **non-mutating** portable
60
75
  starting profile. It names the source of each value (`observed_process` or `configuration_hint`),
@@ -63,11 +78,13 @@ parallel stream, and a finite internal queue before benchmarking. It also report
63
78
  `host_runtime_signals` with source and permission scope. Treat unavailable GPU-memory, thermal, or
64
79
  power signals as unavailable; do not substitute host RAM or a guessed value.
65
80
 
66
- FreeLlama and Ollama have separate queues. FreeLlama acquires a weighted backend permit and waits
67
- for at most `--max-queue-wait-seconds`. An admitted request can then enter Ollama's internal queue,
68
- which is bounded by `OLLAMA_MAX_QUEUE`. Raw compatibility traffic bypasses FreeLlama admission and
69
- enters the primary Ollama queue directly. Set both limits from observed latency and overload
70
- behavior; changing one does not configure the other.
81
+ FreeLlama and Ollama have separate queues. FreeLlama caps retained managed waiters per backend with
82
+ `--max-queued-tasks`/`--cpu-max-queued-tasks`, then waits for at most
83
+ `--max-queue-wait-seconds`. An admitted request can then enter Ollama's internal queue,
84
+ 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
+ Set all limits from observed latency and overload behavior; changing one does not configure the
87
+ others.
71
88
 
72
89
  The following flow shows where each production setting applies:
73
90
 
@@ -76,20 +93,22 @@ flowchart LR
76
93
  C["Client"] --> FQ["FreeLlama admission<br/>weighted budget + wait deadline"]
77
94
  FQ -->|"refused"| E503["503 server busy"]
78
95
  FQ -->|"admitted"| OQ["Ollama queue<br/>OLLAMA_MAX_QUEUE"]
79
- RAW["Raw /api/* or /v1/*"] --> OQ
96
+ RAW["Raw /api/* or /v1/*"] --> RC["Raw stream cap<br/>default 1 in serve"]
97
+ RC -->|"refused"| E503
98
+ RC -->|"admitted until EOF/drop"| OQ
80
99
  OQ --> S["Ollama scheduler<br/>loaded models + parallel streams"]
81
100
  S --> M["Runner memory<br/>num_ctx x K/V cache"]
82
101
  ```
83
102
 
84
103
  These values are conservative starting points, not universal constants. NVIDIA, AMD, Apple, and
85
104
  CPU-only hosts must pass hardware validation before promotion. See
86
- [Ollama and FreeLlama optimization](OLLAMA_SYSTEM_OPTIMIZATION.md) for the ownership boundary and
105
+ [Ollama and FreeLlama optimization](dev/OLLAMA_SYSTEM_OPTIMIZATION.md) for the ownership boundary and
87
106
  [Run models on CPU and GPU](CPU_GPU_ROUTING.md) for device-specific controls.
88
107
 
89
108
  Put the values in the service manager that owns each Ollama process: launchd on macOS, systemd or
90
109
  the container definition on Linux, and the Windows service wrapper. Shell exports and
91
110
  `launchctl setenv` are useful diagnostics but are login-session state, not a reboot-persistent
92
- production configuration. After a real service restart, rerun `doctor` and `scripts/check.sh` and
111
+ production configuration. After a real service restart, rerun `doctor` and `skills/freellama/scripts/check.sh` and
93
112
  require the same visible values before admitting work.
94
113
 
95
114
  ## Create the security and state files
@@ -122,6 +141,18 @@ Only physically verified warm samples are saved. A corrupt or unsupported snapsh
122
141
  fail instead of silently discarding routing evidence. Use `--ephemeral-feedback` only for
123
142
  disposable tests.
124
143
 
144
+ ## Bound conversation history and residency
145
+
146
+ Scope histories and deferred jobs are process-local and are discarded on restart. Configure
147
+ `[scopes]` and `[warming]` limits in the runtime file from measured workload needs; finite history
148
+ bounds and automatic retention remain separate from host-memory reserves. Warm loads use the same
149
+ admission and placement checks as tasks. See [Scope history and model warming](SCOPES_AND_WARMING.md)
150
+ for expected revisions, forks, explicit history reads, and residency precedence.
151
+
152
+ Usage persistence is asynchronous best effort. Inspect pending, dropped, failed, and error evidence
153
+ in `status.usage_ledger`; task success does not prove its usage record reached disk. See
154
+ [Usage recording](MONITORING.md#record-usage) for replay, rotation, and shutdown boundaries.
155
+
125
156
  ## Configure MCP
126
157
 
127
158
  Set these values in the MCP host environment:
@@ -143,7 +174,7 @@ direct Ollama requests, and managed FreeLlama tasks send their own `num_ctx`.
143
174
 
144
175
  ## Verify lifecycle and placement
145
176
 
146
- `keep_alive:0` no longer sacrifices placement evidence. FreeLlama temporarily holds the runner,
177
+ `keep_alive:0` preserves placement evidence. FreeLlama temporarily holds the runner,
147
178
  observes `/api/ps`, records eligible feedback, explicitly unloads it, and verifies that it is no
148
179
  longer resident before returning. Inspect both `execution.observation` and
149
180
  `execution.lifecycle.status`.
@@ -166,12 +197,9 @@ the Ollama process does not expose to FreeLlama.
166
197
  Run compile and deterministic test checks from clean checkouts on Windows, Linux, and macOS. Live
167
198
  accelerator acceptance is separate because build machines do not necessarily represent production
168
199
  GPU drivers or memory topology. Prepare Apple Metal, NVIDIA Linux, AMD Linux, and NVIDIA Windows
169
- hosts, then run `benchmark/hardware/run_validation.py` directly on each host.
200
+ hosts, then run a hardware acceptance check directly on each host.
170
201
 
171
- Each environment supplies its exact GPU and CPU model tags and a running FreeLlama endpoint. The
172
- portable runner in `benchmark/hardware/run_validation.py` executes GPU coding and CPU embedding
173
- concurrently, verifies physical processor receipts, checks admission receipts, and writes a JSON
174
- artifact. Add `--vision-model` and `--vision-image` for that host's OCR/vision gate.
202
+ The portable hardware runners were removed from the repository; they remain in git history.
175
203
 
176
204
  Do not mark a hardware row validated until its archived receipt says `verdict: accept`. Missing
177
205
  hardware is an explicit release gap, not a result that documentation can waive.
@@ -188,7 +216,7 @@ Promote a release only when all conditions pass:
188
216
  6. Restart testing proves feedback reloads and a corrupt snapshot fails startup.
189
217
  7. Immediate unload reports verified pre-unload placement and verified post-unload absence.
190
218
  8. Every claimed hardware row has a real archived acceptance receipt.
191
- 9. The MCP schema remains eight tools and within its context budget.
219
+ 9. The MCP schemas match the published tool surface and pass its context-budget contract.
192
220
 
193
221
  Rollback by returning the listener to loopback, stopping the new service, and starting the prior
194
222
  checksummed binary with the same policy and feedback snapshot. Never downgrade across an unsupported