Past-tense record of shipped changes.
Coordinated LocalX release.
Coordinated LocalX release.
-
One-line install for the whole stack.
localboxis now installed alongside the rest of LocalX by a single command, with each archive checked against its published SHA-256 before it is unpacked:curl -fsSL https://raw.githubusercontent.com/C0deGeek-dev/LocalPilot/main/install/install.sh | shThe train cuts every tool to one version and they are only tested together, so they are installed together;
localpilot update --allre-runs it. Nothing in this repository changed to support it — the release archives andmanifest.jsonalready published were the whole contract.
Coordinated LocalX release.
-
Releases now ship prebuilt binaries. A tagged release previously carried release notes and nothing else, so the only way to get this tool was to build it from source with a Rust toolchain. Each release now attaches an archive per platform — Linux x86-64 (glibc and a static musl build that runs anywhere), Linux arm64, macOS Apple Silicon, and Windows x86-64 — with a SHA-256 beside each archive and a
manifest.jsonindexing the release.Publishing happens once, only when every platform built. A partial release is worse than a failed one: a download cannot tell the difference. The checksums prove an archive was not corrupted in transit; they do not prove who produced it, which needs signing.
Coordinated LocalX release.
-
Classic draft-model speculative decoding is a first-class catalog surface. A model entry can name a
DraftModule(a drafter GGUF in its repo);localbox launch <model> --draftresolves it like the vision projector — shown in dry-run as present or will-download, fetched on demand, a failed download stops the launch — and the server runs it asdraft-simplespeculation. A drafter cannot combine with an MTP spec-type (one speculation engine per launch; refused up front). A drafter the server rejects for speculation (e.g. a draft/target vocab-type mismatch) does not fail the server — it runs without speculation — so the launcher detects that from the server log and warns that the drafter is loaded but idle. Both Bonsai entries wire their DSpark Q4_1 drafters; as of the current Prism release the server rejects those for exactly that mismatch, which the catalog descriptions now state. -
Added Bonsai 27B 1-bit (
bonsai27b, GGUF Q1_0, ~3.8 GB) to the shipped catalog. Q1_0 is upstream llama.cpp, so it runs in plain native mode on the pinned mainline build — no Prism fork required — making it the working fallback when the Prism engine is unavailable; vision via its own mmproj. -
Shipped configuration no longer goes stale on existing installs. The two shipped layers (
defaults.json,llm-models.example.json) now refresh to match the installed binary — previously they were seeded once and never updated, so new release pins and engine settings silently never reached an existing~/.local-llm(user overrides belong insettings.json, which always wins). Your editablellm-models.jsonis still never overwritten:localbox updatenow reports shipped models your catalog predates, and a newlocalbox update --merge-modelsadds exactly those missing entries — additive only, existing entries and aliases untouched,--checkpreviews. -
The Prism engine now installs on Linux (x64/arm64): CUDA archives matched to the driver's CUDA major (newest toolkit build within it), Vulkan on an AMD GPU, the plain CPU archive otherwise; rocm and KleidiAI archives are deliberately not selected. Windows/macOS selections are unchanged. The installer now also warns, on every platform, when the only available Prism CUDA build's major does not match the driver's — that pairing can emit garbage output, which the launch smoke test catches before an agent sees it. The
.build-stampvariant is derived from the actually selected asset (cuda-12.4 / cuda-12.8 / vulkan / cpu / metal) instead of a per-OS hardcode, and the shipped pin table covers the Linux archives. -
Engine pins now age loudly and advance deliberately.
localbox update --checkreports per pinned mode whether the pinned release tag is behind the latest upstream release (informational — nothing auto-installs), and a newlocalbox update --mode <m> --refresh-pinsadvances one mode's pin to the latest release: it installs this host's assets, verifies each download against the GitHub release's published sha256 digest (a mismatch refuses to install or record), and records the new tag plus asset hashes insettings.json, which wins layer precedence and survives upgrades. The PrismML engine pin moved to the current fork release, whose Windows binary and macOS Metal archive hashes are re-pinned indefaults.json. -
Fixed Prism responses being misreported by LocalPilot as truncated streams. The vendored shared proxy now synthesizes a missing Anthropic
content_block_startand flushes held-back visible text beforecontent_block_stop, while genuine EOFs still remain truncations. -
Added the Ternary Bonsai 27B runtime path end-to-end. The catalog now marks
tbonsai27bas requiring the newprismengine, so CLI, guided launches, saved defaults, and AutoBest cannot route its low-bit weights through an incompatible llama.cpp build. The pinned PrismML release installs the Windows x64 CUDA 12.4 binary plus runtime DLLs, or the standard Apple Silicon Metal archive; KleidiAI and DSpark are intentionally out of scope. -
Configured vision projectors now download on demand when
--visionis used. Dry-run shows whether the mmproj is present or will download, and a failed projector download stops the launch instead of silently claiming vision or degrading to text-only. -
Fixed runaway GPU memory on
localbox serve(and guided "for other tools" launches): those paths omitted--parallel, and llama-server's own default is now multi-slot auto (-np -1→ 4 slots), which allocates the full configured context per slot — roughly 4× the KV-cache memory the launch was sized for, OOMing models that fit fine underlaunch. Every launch path (CLIlaunch/serve, the guided launcher, and the native retry) now applies the same single-session defaults--parallel 1 --cache-reuse 256through one shared finalizer, restoring v1.x behaviour. The guided launcher also picks up thesettings.jsonlaunch tunables (LlamaCppAgentParallel,LlamaCppAgentCacheReuse,LlamaCppNCpuMoe,LlamaCppMlock,LlamaCppNoMmap) it previously ignored. To deliberately use llama-server's auto slot count, setLlamaCppAgentParallelto-1(a non-positive value is not emitted, leaving the server default in charge).
Coordinated LocalX release.
- The shared crate tier advanced: the no-think proxy's gateway key check is
now constant-time (SHA-256 digest comparison instead of a short-circuiting
string equality), and its docs state the LAN posture honestly — the key
gates access over plain HTTP, and
/healthdeliberately stays open. - Fixed the keyed LAN launch end-to-end: the reply-path smoke test now
authenticates with the gateway key, and the Claude/LocalPilot agent
environment carries that key instead of the loopback placeholder — a
--lan --passwordlaunch previously aborted at the smoke stage against a fresh key-enforcing proxy (and the agent would have been refused anyway). - Proxy reuse is now posture-aware: an existing proxy is reused only when its listen host and key match the plan, read from the live process itself. A keyless proxy can no longer be silently reused behind a "key required" banner, and an earlier open-LAN gateway no longer keeps serving after a loopback-only launch — mismatches restart the proxy with the wanted posture. Existing proxies started before this change restart once on the next launch.
--lan --keep-thinkingis refused up front:--keep-thinkingroutes the agent straight at the loopback-only server, so the LAN gateway it announced never actually started.- A failed reply check now stops the server (and any proxy) that launch had just started instead of stranding them; a reused proxy from an earlier launch keeps serving.
- The guided launcher resolves VRAM through the same shared ladder as the
CLI path: the
VRAMGBsetting is honored and a host with no detectable GPU falls back to the shared default instead of 0 GB (which painted every quant over-budget). - The native retry after a failed fork reply check re-derives its launch request with AutoBest off — as its own docs already claimed — instead of carrying fork-tuned params/quant/context into the native build (fork-only KV-cache types made that retry fail outright).
Coordinated LocalX release.
- A LocalPilot launch no longer wipes hand-added
.localpilot.tomlsections (e.g.[mcp.servers.*]for Playwright/context7). Previously every launch overwrote the whole file with just the provider/permissions blocks LocalBox generates; it now merges those into the existing file, preserving every other section untouched. A pre-existing file that fails to parse as TOML now fails the launch loudly instead of being silently discarded. - The guided launcher's "Save as my default" now persists the
Images (vision)toggle inDefaultLaunch. A saved vision-on recipe replays for that same model after restarting LocalBox, while other models still start text-only unless vision is explicitly enabled. - Docs now describe the weight-vs-VRAM fit estimate accurately: it is an advisory picker colour (green/yellow/red), not a guard that blocks a launch, and KV-cache pressure is not computed. Corrected the README and architecture notes that overstated it.
- The LAN-gateway refusal message now names the real CLI flags (
--password,--lan,--allow-public-no-auth) instead of retired PowerShell-module flags and aLOCAL_LLM_SERVE_PASSenv var that was never read. - Clarified that GGUF weight downloads are integrity-checked at the reply-path smoke test, not by a per-file checksum (only the llama.cpp binary zips are sha256-pinned).
- Restoring the shell env after a launch now returns a variable that was set to an empty string before launch verbatim, instead of removing it.
- Raised the default
LocalModelMaxOutputTokensfrom 4096 to 16384. Agentic coding replies routinely hit the old cap and stopped mid-word with no error (a legitimatefinish_reason: lengththat nothing in the pipeline surfaced) — the no-think proxy's<think>-tag holdback was not at fault. The cap only bounds decode time for replies that actually need it; it does not reserve extra VRAM/KV-cache.docs/troubleshooting.mdnow documents the symptom and how to raise it further insettings.json. - Fixed the actual cause of replies vanishing silently mid-sentence: the
no-think proxy's
<think>-tag stripper discarded everything after a<think>tag that never got a matching</think>before the turn ended — and did so incrementally on every chunk, not just once at the end — with no warning and no effect on the stream's terminal marker, so the client saw a clean, seemingly-complete reply that was actually missing real content. Any local model that ever emits a stray/unclosed<think>-like substring mid-turn triggered this, independent of platform or model. Unterminated<think>spans are now flushed as visible text instead of discarded. (Sharedlocalx-llamafix; re-pinned.) - Fixed a second, more common cause of the same symptom: an unterminated
<think>span was only recovered once the stream reached its own natural end, so a false-positive<think>-like substring in ordinary (non-reasoning) text — confirmed via llama-server's own log to leave generation completely healthy, with no further reasoning activity — could freeze the visible reply for the rest of the turn if the caller gave up on the stream first. The no-think proxy now bails out of a<think>span that runs past 32KB without closing, flushing it as visible text and resuming normal streaming instead of waiting indefinitely. (Sharedlocalx-llamafix; re-pinned.)
Coordinated LocalX release.
Coordinated LocalX release.
Coordinated LocalX release.
Coordinated LocalX release.
Coordinated LocalX release.
- Streamed local-model replies are no longer truncated by up to ~7 characters.
The no-think proxy held back the last few bytes of the visible text for
split-
<think>-tag safety and only released them after the stream's end marker ([DONE]/message_stop) — where the agent had already stopped reading — so every reply lost its final characters (e.g. "…What can I do for you?" arrived as "…What can I do f"). The proxy now flushes the held-back tail in-band, just before the end marker. (Sharedlocalx-llamaproxy fix; re-pinned.)
Coordinated LocalX release.
- Agent launches now apply the permission/bypass gate again. On first launch of an agent that supports it (Claude, Codex, LocalPilot) LocalBox asks once whether to let the model act without per-action approval — defaulting off, saving your answer, and never enabling a bypass in a non-interactive session.
- New
--auto-bestflag forserve/launch: applies the saved localbench profile (best-<model>.json) — tuned quant/context/mode plus KV-cache and n-cpu-moe — on a headless launch, the way the guided launcher already does. - The documented
settings.jsontunables now actually take effect:LlamaCppMlock,LlamaCppNoMmap,LlamaCppAgentParallel,LlamaCppAgentCacheReuse,LlamaCppNCpuMoe,LocalModelMaxOutputTokens, and the health/smoke timeouts were previously read from nothing. - An AMD GPU with no NVIDIA driver now installs and runs the Vulkan build instead of silently falling back to CPU.
- A turboquant/mtpturbo build that fails its reply check now falls back to native llama.cpp instead of hard-stopping.
localbox stopspares the embedding server, so a chat-model stop no longer takes down the embeddings endpoint LocalMind uses.- A model server that exits during startup (e.g. OOM) now fails in seconds with its log path, instead of waiting out the full readiness timeout.
- A configured
VRAMGBnow overrides the auto-detected value. - Removed phantom settings and the stale MCP page; corrected example model keys,
the SECURITY version table, and a retired command name in a proxy error.
An existing saved setting or a
LOCAL_LLM_*env override is honored, and the chosen posture is printed before hand-off.
Coordinated LocalX release.
- Guided launcher rebuilt around one live band. 2.0.1 drew a new
inline viewport per menu and printed summaries between them, so screens
stacked as leftovers. Every state now renders as one composed frame in a
single terminal band: a hardware banner (GPU name + memory via
nvidia-smi, then AMD tools; plain CPU-only fallback), the plan summary as a standing panel beside the menu, and content-sized boxes. Notices insert above the band into scrollback; launching hands the screen back cleanly and narrates its stages (server start + log path, model load, ready, reply check, agent start). Ctrl+C leaves the launcher from any menu. - Model rows are informative:
key · name · size · context-as-words · images, size from the catalog or the downloaded file, with the fit traffic light coloring only the size segment. - Customize polish: the cursor survives toggles, "Save these as my default" returns to the launch menu, and the saved recipe's Strict toggle actually replays (the resolver never read it — fixed, per-model like quant/context).
- Auto-tune is a full tuning menu: optimize-for, workload, engine,
quality, memory, trial budget, runs per trial, cached-vs-fresh
measurements, and save-vs-preview — every setting opens an option
sub-menu with plain descriptions, technical names, the default and the
current selection marked. An ℹ row explains every setting; the tune
passes the current plan's quant/context so "Launch now" replays the
winner, and it actually runs
localbench findbest.
Coordinated LocalX release.
- 1.x leftovers are now detected and named. A 1.x
install.ps1deployment survives the 2.0.0 upgrade badly: a symlink-mode install leaves a dangling~/.local-llm/LocalLLMProfile.ps1link (a red "Could not find file" error at every PowerShell start), a copy-mode install keeps running the stale 1.x launcher silently — and the cleanup logic lived in the deletedinstall.ps1, so nothing repaired either.localbox statusand the guided launcher now detect the deployed 1.x launcher file, thelib/module tree, and a PowerShell profile that still dot-sourcesLocalLLMProfile.ps1, and print one bounded notice with the remedy (localbox::migrate, unit-tested). - "Upgrading from 1.x" documented.
docs/install.mdgains the manual migration steps (remove the profile hook, delete the deployed 1.x files, install the binary) and the full 1.x → 2.x command mapping; the README links it and no longer cites the retiredinfo -Commands.
Coordinated LocalX release.
-
Retired the PowerShell launcher, the Python no-think proxy, and the .NET TUI; LocalBox is now a single native binary. The
local-llm/libprofile module,localbox-proxy,tui/, the Pester suite, andinstall.ps1are gone — every behaviour they carried ships in the Rust binary, each hard-won invariant pinned by a golden test before its logic was ported. The no-think proxy runs in-process (the binary hosts it vialocalbox nothink-proxy), the guided launcher islocalboxitself, and the first run seeds~/.local-llm(defaults plus an editable catalog, never overwriting). Install iscargo install --path crates/localbox --lockedor a release binary — LocalBox no longer needs PowerShell, .NET, or Python at runtime on any platform. CI keeps the tri-platform Rust gate and the cross-repo launcher-contract check. -
Catalog inspection and cleanup in the binary.
localbox infolists the configured models by tier (or one in detail; any of a model's names resolves),localbox purgestops servers and deletes downloaded model files strictly under the GGUF root, andlocalbox logtails the most recent server log. -
Driver policy + resilience (
localbox-tui::driver). Scrollback safety by construction: the terminal options pin an inline fixed-height viewport (no alternate screen, no whole-screen clear — content above the live band stays in native scrollback). Failures render as one bounded plain-language warning line (first line only, no backtrace vocabulary); a non-TTY stdout or an explicit plain request degrades to numbered-line menus with zero escape sequences; and UTF-8 console output is ensured best-effort on Windows so box-drawing renders without profile edits. -
The Customize path (
localbox-tui::customize). Progressive disclosure over the resolved plan: every row shows its current value and choosing one merges the delta back into the overrides. Auto-tune owns Engine + KV — with it on, those rows lock with a plain explanation (never a silent block) and any manual KV override is dropped so it cannot strand against the tuner's choice; turning it off restores manual control. Save is target-gated:servecannot be saved as the default launch, refused with the friendly name in the reason. -
Guided-launcher widgets (
localbox-tui::ui). The model picker (key · DisplayName, dim[strict],[Show all tiers]/[Cancel]footers), the recommended-plan summary panel, and the exact five-item confirm menu (Launch now / Customize / Auto-tune / What do these mean? / Back to models) — backend-agnostic ratatui widgets whose rendered screens are pinned byTestBackendsnapshot tests, including the no-jargon contract on the summary. Quant rows get the fit-aware traffic light (green fits / yellow tight / red over; unknown stays uncolored) from the shared fit classifier. -
Guided-launcher core in Rust (
localbox-tui: vocabulary + plan). The plain-language vocabulary (Run with / Quality / Memory / Speed / Images friendly names, memory-as-words at tokens×0.75, quality-as-hint+GB, the glossary) and the recommended-plan summary with the no-jargon contract as a test (quant/AutoBest/turboquantmust not appear; the friendly labels must). The plan resolver pins the precedence: explicit overrides > the saved DefaultLaunch's cross-model preferences (target/engine/auto-tune) > the per-model definition > hard defaults, with quant/context applying from the recipe only for the model it was saved for; a returning user's plan IS their last-good plan, previews are non-committing by construction, and the.llm-defaultworkspace override resolves by walk-up with nearer markers shadowing outer ones. -
Security posture + serve guard in Rust (
localbox-launcher::posture). The one-screen posture (permission/bypass gate status without prompting, the loopback-only agent proxy, serve-gateway exposure and auth, and the download pin posture incl. the trust-on-first-use spelling), the public-HTTP classifier that spares loopback/RFC-1918/link-local/localhost while flagging public addresses and DNS names on plain HTTP, and the serve guard: open no-auth HTTP on a public-looking address is refused with the remedy unless explicitly opted into; password-protected public HTTP stays allowed and visible. Discovery defaults derive from the home directory — never a hardcoded machine path. -
Launch planning in Rust (
localbox-launcher::orchestrate). One read-only resolution — model → context → expected GGUF path (no download) → vision projector (opt-in AND actually resolved) → free server port → full llama-server argv → proxy config → provider TOML → agent env plan — produces the inspectable plan that serves both DryRun (print it; commits no session state, creates no files) and the live launch. Vision is honest end to end:--mmprojenters the argv andsupports_visionis declared only when a projector resolved; a present projector stays unused unless requested. The smoke-fallback rule is pinned: a non-native fork failing the smoke retries on native llama.cpp; native failing is a hard stop. -
Launch smoke test in Rust (
localbox-launcher::smoke). The degenerate-output detectors with thinking stripped FIRST (a reasoning model may legitimately fill its budget with<think>before a short answer): the[no output]marker, 8+ runs of flood punctuation (the GPU/driver-mismatch//////signature), and 10+ consecutive identical tokens; verdicts name their failure mode (no response / think-only / degenerate), the Anthropic reply body parses fail-closed, and failure rendering is collapsed and bounded for the operator. -
.localpilot.tomlprovider wiring in Rust (localbox-launcher::localpilot_config). The generated provider block pins the coupling rules by test: provider kind and endpoint move together (anthropic behind the no-think proxy, openai-compatible direct; base_url always ends in/v1),api_key_envfollows the kind, the model's context is declared asproviders.local.context_window— never a[harness]context_token_limitkey —supports_visionis auto-declared only when the launch actually loaded a projector,max_tokens/context_windoware omitted at zero, and bypass is a[permissions] profile = "bypass"config block, never argv. -
Permission/bypass gating in Rust (
localbox-launcher::permissions). The three agent gates (Claude skip-permissions, LocalPilot bypass, Codex bypass) resolve fail-closed: env override → persisted per-machine setting → a one-time first-run prompt that defaults OFF. A non-interactive session never silently enables anything and never persists; a preview/DryRun resolve is read-only; an explicit "no" persists a literal false (decided-no, not never-asked); Codex bypass is never defaulted; LocalPilot bypass is written to.localpilot.tomlas[permissions] profile = "bypass", never argv. The tests build from a REAL empty settings file and assert the observable gate decision, and the settings store refuses catalog-only keys. -
Agent env envelope in Rust (
localbox-launcher::env). One plan function computes the launch's environment variables — it is both the DryRun snapshot and the live setter's source, so the two can never drift (the PowerShell version hand-mirrored the list in two places). The envelope saves every canonical variable before mutating and restores after: values present before come back, values absent before are removed. The canonical set carries its reasons in place (the 1800000ms SDK timeout for slow local prefill, the auto-memory and experimental-betas/ToolSearch disables, the no-think trio skipped under keep-thinking, the paired context/auto-compact caps, the conditional per-model image ceiling, and the LOCALBOX_* telemetry exports), and a test pins that every setter variable is inside the envelope. All over a store seam so tests never race the real process environment. -
No-think proxy lifecycle in Rust (
localbox-launcher::proxy). The launch-time proxy orchestration over the shared tri-state machine, with every effect behind a mockable seam: reap-before-probe (a dead-upstream orphan still answers/healthand must never read as a live match), reuse-on-match with the gateway-logs rule (an owned proxy restarts so logs are captured; a foreign matching one is refused with the llm-stop remedy), repoint-on-mismatch (tear down and restart at the wanted target, never fail into a silent direct route), kill-stale-listener-first before binding (Windows SO_REUSEADDR), bounded readiness polling that tears down a never-ready start, owned-vs-any teardown (llm-stop reaps every owner on the port), and the netstat/lsof socket→PID parsers. The shared health state now distinguishes proxy-down (upstream up, proxy missing) from fully-down. -
Native Rust workspace seeded (
crates/localbox-launcher). The launcher contract now has its Rust implementation alongside the shipping PowerShell module (which stays authoritative until each piece is retired): the three-layer config load (defaults.json<llm-models.json< per-machinesettings.json) over the shared precedence engine with catalog-only keys locked, andLlamaLauncherimplementing the sharedLaunchertrait — catalog-backed model/quant/context resolution delegating to the shared domain crate, on-disk GGUF and mmproj resolution (configured module wins, deterministic auto-detect otherwise; a missing GGUF fails with the install remedy), per-mode install roots and llama-server binary resolution, KV-type capability per fork, free-port/wait/stop lifecycle with a recorded backend session, and~/%VAR%path expansion. The version envelope passes the shared compatibility gate (api 1 / export 1, LocalBox/llamacpp declared). -
The model catalog is now per-user, not shipped.
llm-models.jsonis your own list (gitignored); the repo shipsllm-models.example.jsonas the template.install.ps1seeds~/.local-llm/llm-models.jsonfrom it on first run and never overwrites an existing catalog, so your models stay yours and aren't published for everyone. Existing installs are unaffected; a fresh checkout falls back to the template. Add models withaddllmor by editing your local catalog.
Coordinated LocalX release.
- New default
llmexperience: a guided, plain-language launcher. When Spectre is available,llmnow walks you through launching in plain words — pick a model, then Launch now (recommended) or Customize (Run with / Quality / Memory / Speed / Images), with a What do these mean? help screen — and returns to the model list when the agent exits. Recommended settings are pre-filled to fit your machine, so the common path is model → Launch now. The developer-oriented inline board is opt-in viaLOCALBOX_BOARD=1;LOCALBOX_LEGACY_WIZARD=1restores the old step wizard;llmc/llmsremain the explicit classic/Spectre entrypoints. - Registered
ornith35hapexin the model catalog — a decensored (Heretic) + APEX GGUF of Ornith-1.0-35B (4 tiers: Quality/Compact/I-Quality/I-Compact + visionmmproj, Parserqwen36, contexts capped for a 24 GB GPU,experimental, not the default). It reuses the existing serving glue (proxy 11435→8080,--mmproj). On wikitext-2 perplexity it is on par with theq3635ba3bapexbaseline (6.96 vs 6.91) at comparable throughput and VRAM, and adds vision; trunk-only (no MTP draft head).Repopoints at the public HuggingFace releaseC0deGeek/Ornith-1.0-35B-heretic-APEX-GGUF. Serve withllmdefaultserve ornith35hapex.
Coordinated LocalX release.
Start-LocalPilot -UseVisionnow actually loads the vision projector, and auto-declares it to LocalPilot. The LocalPilot agent launch previously hardcoded an empty projector path, so-UseVisionset the AutoBest profile but never passed--mmprojtollama-server— an image-capable model ran text-only. It now resolves the model'smmproj.gguf(mirroring the Claude Code launch), guarded by an availability check so a missing projector gives a clear message and a text-only launch rather than a broken--mmproj. A real launch downloads the projector on demand; a-DryRunpreview resolves the expected path without downloading. On that vision launch LocalBox also writessupports_vision = trueinto the[providers.local]block of the generated.localpilot.toml, so LocalPilot accepts image input zero-config. The default (no-UseVision) path loads no projector and declares nothing — unchanged. Seedocs/harness-mode.md→ "LocalPilot harness".
Coordinated LocalX release.
-
A CPU-only embedding server (
llmembedserve). A small, self-contained sibling ofllmdefaultservethat serves a GGUF embedding model through llama-server's OpenAI-compatiblePOST /v1/embeddingson a dedicated loopback port (8090by default), forced onto the CPU (-ngl 0) so it costs zero GPU VRAM. That CPU rule is load-bearing for fair benchmarking: a GPU-resident embedding model would steal VRAM from a chat model running alongside it, so a benchmark pairing the two would see a degraded chat model on the embeddings side only — keeping embeddings on the CPU leaves the chat model byte-identical. The server has its own port, process, and lifecycle (llmembedstop), independent of the chat server. Default model: Qwen3-Embedding-0.6B (GGUFQ8_0, Apache-2.0, 1024-dim,--pooling last), acquired on first run into the models dir (never committed) and overridable viaEmbedModelRepo/EmbedModelFile/EmbedModelRoot/EmbedPort/EmbedPoolinginsettings.json.-WhatIfrenders the exact served command without acquiring a model or launching anything;Test-LocalLLMEmbedEndpointprobes a running server and returns the vector dimension. Seedocs/harness-mode.md→ "CPU embedding server". -
no-think proxy v0.4.0 — normalizes system messages so strict (qwen-family) chat templates accept Anthropic agentic clients. llama.cpp's qwen3 template hard-rejects any system message that is not the first message (
raise_exception('System message must be at the beginning')), surfacing as400 Unable to generate parser for this template. Anthropic clients such as Claude Code put the base prompt in the top-levelsystemfield and can inject a secondrole: systemmessage insidemessages(e.g. a SessionStart hook); llama.cpp renders both, so the in-array one lands second and the template raises. The proxy now folds any in-array system message into the top-levelsystemfield (preserving existing content blocks and theircache_control) and removes it frommessages; for OpenAI-form requests (no top-levelsystem) it collapses misplaced/duplicate system messages into a single leading system message. Default-on; opt out withNO_THINK_PROXY_MERGE_SYSTEM=0.defaults.jsonNoThinkProxyRequiredVersionbumped to0.4.0. This unblocks driving the default local model from Claude Code (and any Anthropic-native harness) throughllmdefaultserve. (The no-think proxy remains deprecated and kept one release for non-LocalPilot clients.)
Coordinated LocalX 1.0 release. First stable launcher surface.
-
Dead-code cleanup: removed 7 unused PowerShell helpers. No call sites remained for
Convert-ToPosixPath,Get-HuggingFaceModelFiles,Get-LlamaCppTemplatesDir,Set-LocalBoxTuiSetting,Invoke-LocalBoxTuiLaunch,Get-LocalBenchLauncherBestConfig, orGet-LocalBenchLauncherBestConfigCandidates. Also dropped the stalelocal-llm/bench-history.jsonl.gitignoreentry (nothing writes it). No behaviour change. (TheEnsure-LlamaBenchExe/Ensure-LlamaPerplexityExefinders/installers were left in place: they are part of the LocalBench launcher contract surface, not dead.) -
llmdefaultserve -DryRunnow previews the recipe that actually launches. When the DefaultLaunch recipe selects a non-default quant, the dry run used to show the model's default quant (e.g.APEX-Balanced.ggufwithq8KV-cache args) while the live launch ran the selected one (e.g.APEX-I-Quality.ggufwithturbo3args) — the quant was applied only on the live path. The selected quant is now resolved for both paths, so the preview renders the same GGUF + AutoBest/KV-cache recipe the live launch consumes; a dry run reverts the change afterwards, so previewing still commits no session state. -
Stale no-think proxy is now diagnosable instead of a bare 502. When the no-think proxy is up but the upstream model server is down, a request returned only
502 Bad Gateway. A bounded, non-blocking health probe now distinguishes that stale state from a fully-down or healthy stack and recommends the fix (llmstop; llmdefaultserve); it is surfaced when a headless serve's smoke test fails, and never blocks the launch. -
llmdefaultserve— headless model serve for CLI / agent / CI. Brings up the DefaultLaunch model as a background llama-server + no-think proxy (loopback) with a visible-response smoke test and does not attach an interactive agent or tear the endpoint down on exit — unlikellmdefault, whose agent-attach (Start-LocalPilot) stops the server and proxy when the attached process exits. For driving the model from a separatelocalpilot/claudeprocess. Distinct from the LAN serve gatewayllmserve(binds 0.0.0.0 with auth); this one is loopback-only. Stop withllmstop. -
Fixed the
-DryRunlaunch-plan "Agent argv" error. An empty extra-args list arrives as a nested empty array element (helpers return,$extras); the real launch splats it away, but the preview'sFormat-LocalLLMArgvLinefailed to bind it as a string. The formatter now flattens nested elements, so the preview renders the agent command line cleanly. -
Removed the legacy bench history viewer. The
obenchcommand and its70-bench.ps1module are gone — LocalBench owns benchmarking. The old~/.local-llm/bench-history.jsonl(written by the retiredospeedhelper) is no longer read; use LocalBench for benchmarking and tuning.
-
Bypass is no longer a default. Launching LocalPilot through LocalBox no longer passes
--bypassunconditionally, and Codex no longer defaults--dangerously-bypass-approvals-and-sandboxto on. Each is now a first-run, persisted decision (LocalPilotBypass/CodexBypassApprovalsAndSandbox) that defaults off and fails closed in non-interactive sessions, mirroring the existingLocalModelSkipPermissionsprompt. The active posture is shown inShow-LocalBoxSecuritySummaryand every-DryRunlaunch plan, and an env override (LOCAL_LLM_LOCALPILOT_BYPASS/LOCAL_LLM_CODEX_BYPASS) applies per launch. Seedocs/settings.md. This restores parity with LocalPilot's "bypass is never the default" posture for users who enter through LocalBox. -
Codex bypass default fully enforced at config load.
Import-LocalLLMConfigno longer injectsCodexBypassApprovalsAndSandbox = $truefor an unset key, which had quietly re-enabled the default-on posture for a fresh machine even though the launch path itself never prompted. The key now stays absent when unset — exactly likeLocalPilotBypass— so the security summary reads "undecided" and the resolver reaches its first-run prompt (interactive) or fails closed (non-interactive). A regression test loads the real merged config (not a stubbed one) to keep this from regressing again. -
Fixed the LocalPilot install hint thrown by
Start-LocalPilot: the crate iscargo install localpilot(notlocalpilot-cli), matching the troubleshooting doc. -
Repinned the turboquant llama.cpp build to the forked
tqp-v0.2.0(b9901, lazy-grammar), fixing theq3635ba3bapex400empty grammar stack after <think>failure on constrained-decoding requests. Dropped the stale TheTom turboquant refs.
- Documented the SemVer policy in
docs/versioning.md: break → major, add → minor, fix → patch, plus the pre-1.0 rules (breaking changes bump the minor0.MINOR; features and fixes bump the patch) and the deprecation-vs-removal distinction. Linked from the docs index.
- Marked
localbox-proxy/no-think-proxy.pydeprecated (scheduled for removal). LocalPilot strips<think>blocks natively on both provider paths and suppresses the thinking request shape itself, so the out-of-band proxy is no longer needed for the LocalBox → LocalPilot path.
- Split the long top-level
README.mdinto a lean overview plus owneddocs/pages (install, harness mode, llama.cpp modes, usage, model management, settings, MCP, auto-tuner, wizard/TUI, architecture, troubleshooting), indexed bydocs/README.md. - Fixed the LocalPilot install hint in troubleshooting: the crate is
cargo install localpilot(notlocalpilot-cli). - Added an in-repo wiki source (
docs/wiki/) that is one-way CI-synced to the GitHub Wiki, plus an offline link check over the docs.
Coordinated LocalX beta release.
-
Serve gateway now discloses its safe operating posture (LAN/VPN-only, HTTPS in front) in the client instructions and the security banner; the guard still refuses open public HTTP.
-
Conformed the bundled tuner best-config fixture to the current
tuner-best-configschema (added the requiredprofilefield) so producer and consumer agree on the versioned contract. -
llm-updatenow refreshes installed artifacts after source updates. LocalPilot is reinstalled from its updated checkout when it fast-forwards, so thelocalpilotCLI onPATHno longer lags behind the repo. Added-RefreshInstalledto force redeploy/rebuild from already-current checkouts;Update-LocalPilot -RefreshInstalleddoes the same for the standalone helper.
- Aligned LocalBox with the coordinated LocalX
v0.3.0-beta.1beta release. - Kept the LocalBench launcher contract binding and updated the no-think proxy required version marker for this release train.
- Remote launch target renamed to Serve. The TUI action contract now uses
serve, the command isllmserve, the password environment variable isLOCAL_LLM_SERVE_PASS, and the docs describe the gateway as serving any Anthropic-compatible agentic client, with LocalPilot as one example.
llmtuidocumented as the explicit Terminal.Gui preview path. README now covers publish/install, profile resolution, core navigation keys, and the LocalBench handoff key.- Spectre model catalog layout fixed. The dashboard now uses explicit column widths and a compact quant list so the context column stays readable instead of wrapping to one or two characters.
- MTP catalog contexts expanded.
q3535ba3bmtpandgenesisv2now expose an explicit256kcontext key while keeping default context at128k. - Quant naming clarified. README notes that labels like
mtp,mtp-apex, andmtp-q8kpare model-local quant keys that map to concrete GGUF filenames. - TUI packaging added.
install.ps1 -InstallTuipublishes LocalBox.Tui and LocalBench.Tui when available;llm-update -InstallTuirefreshes installed TUI binaries. lbtuiwrapper added. LocalBox now exposes a LocalBench.Tui entrypoint alongsidellmtui, and inline help documents both.
- Ollama support has been removed. LocalBox now targets llama.cpp's
llama-serverexclusively. The-Backend ollamaparameter, the Ollama process control (Start-OllamaApp,Wait-Ollama,Stop-OllamaModels, …), Modelfile-based alias creation, Ollama strict siblings, the Ollama remote gateway path, and every shortcut that pulled or rebuilt Ollama aliases (init,initmodel,ostop,qkill,ops,cleanorphans,listorphans,ospeed) are gone. If you still need that path, check out theollama-classicgit tag. -Chatand-Q8flags removed from per-model shortcuts.llama-serverhas no chat REPL, and Q8 KV was the Ollama env var (OLLAMA_KV_CACHE_TYPE=q8_0). Use-KvK q8_0 -KvV q8_0(or the wizard's KV-cache step) for the equivalent llama.cpp setting.- Catalog scalars removed.
MinOllamaVersion,OllamaAppPath,OllamaCommunityRoot,KeepAlive,RequireAdvertisedTools,LlamaCppCoexistOllamaare stripped fromdefaults.jsonand from any merged settings at load time.SourceType: remotemodel entries are no longer supported (all in-catalog entries aregguf). ollama-proxy/folder renamed tolocalbox-proxy/. The deployed location is now~/.localbox-proxy/. The Python no-think proxy itself is unchanged in behavior; it now targets127.0.0.1:8080by default instead of127.0.0.1:11434. Theenforcer-claude.ps1Ollama wrapper has been deleted.Save-LLMDefaultLaunchschema simplified. No moreBackend,UseQ8. ExistingDefaultLaunchentries with those fields will ignore the obsolete keys; re-save via the wizard if you want the schema clean.
Invoke-Backendno longer takes-Backend; it always dispatches to llama.cpp.launch-chataction removed.llm-statusis now justInvoke-LlamaCppStatus.Show-OllamaStatusis replaced byShow-LocalBackendStatus+Show-ConfiguredGgufQuantsin the dashboard.- The wizard's backend step is now a mode picker (native / turboquant / mtpturbo). Default is
LlamaCppDefaultMode(stillnative). - Codex launches always use the OpenAI-compatible llama-server provider; the
--oss --local-provider ollamapath is gone.
ostopnow leaves Ollama stopped. It no longer restarts the Ollama app after teardown.llm-stop. Added a hyphenated all-backend stop command alongsidellmstop/unloadall.- Codex launch target. Model shortcuts and the wizard now support
-Codex/Codexas a peer to Claude Code and LocalPilot. Ollama launches use Codex's local Ollama provider; llama.cpp launches pass a custom OpenAI-compatible provider pointed at the selectedllama-server/v1endpoint. - Default launch recipes. The wizard can save the selected model, target, backend, context, quant, strict/Q8 flags, llama.cpp mode, KV cache, and AutoBest profile into
DefaultLaunchsollmdefaultcan replay the full recipe. - Wizard default is native selectable.
llm/llmmenunow use an in-repo arrow-key picker by default.llmsopens the Spectre wizard explicitly, and$env:LOCAL_LLM_USE_SPECTRE=1optsllmback into Spectre. - Context menu noise reduced. Removed visible
fast,deep, and bare128context aliases from the catalog and new-model defaults. Use32k,64k,128k, and256k; legacy aliases still resolve for old commands and saved AutoBest profiles.
llm-update/Update-LocalLLMSuite. Checks LocalBox, LocalPilot, and LocalBench when they are installed as git checkouts, fetches upstream state, and fast-forwards only when an update is available. Missing companions are skipped, current checkouts are reported as current, and diverged/no-upstream checkouts are left untouched with a reason.LocalBoxRootsetting.install.ps1now records the source checkout used for installation so deployed copy-mode profiles can find the LocalBox repo for future self-updates.- LocalPilot-only command surface. Removed the old shorthand and pre-rename aliases. Model launches now use the explicit
-LocalPilotswitch, and the default shortcut isllmdefaultlocalpilot.
updatellm <key>/Update-LocalLLMModelQuants. Backfills missing quants on an existing GGUF entry by re-fetching its HF repo and merging any quant codes not already present. ExistingQuants,QuantSizesGB, andQuantNotesentries are preserved verbatim — only new keys are added (auto-generated note viaNew-LocalLLMQuantNoteText).-DryRunpreviews the additions without writing. Applied to the catalog:qcoder303 → 23,qcodernext3 → 23,q27heretic4 → 6,q27hauhau2 → 10.q36plus(HF gated, returns 401 on the API) andq36heretic(subdirectory-organized repo layout) were left untouched.
- LM wizard couldn't go back one step. Both
Start-LLMWizardClassicandStart-LLMWizardSpectrewere a flatwhile ($true)/continueloop where every[[Back]]returned to the top (re-pick model). The Spectre quant menu had no Back at all (only[[Keep current: …]]). Both wizards are now step-state machines ('model' → 'quant' → 'context' → 'action' → 'q8' → 'launch'); each step's$nullreturn walks back exactly one step. Quant menu in Spectre now has both[[Keep current: <q>]]and[[Back]]; the classic quant menu uses a letter shortcut (k= keep current,0= back) via a new-LetterChoiceshashtable onRead-LLMChoiceIndex. The q8 prompt also acceptsb(classic) /[[Back]](Spectre) to walk back to action selection. addllmcould pick up imatrix calibration files. Top-level*.imatrix.gguf(mradermacher's calibration data, not a quantized model) used to pass the file filter and only got dropped becauseGet-HuggingFaceQuantCodereturned$nullfor it. Now excluded explicitly in bothAdd-LocalLLMModelandUpdate-LocalLLMModelQuantsso a future quant-code regex change can't accidentally include them.install.ps1failed when-Profilewas passed. The[switch]$Profileparameter shadowed PowerShell's$PROFILEautomatic variable inside the script, so$PROFILE.CurrentUserAllHostsresolved to[switch].CurrentUserAllHosts(no such property →$null), thenTest-Path $nullthrewValue cannot be null. Renamed the parameter to[switch]$SetupProfilewith[Alias("Profile")]so existing-Profileinvocations still bind. Also collapsed the convolutedinstallFilesflag computation into one line, and fixed a cosmetic message bug where\$PROFILEwas meant as a literal but PowerShell escapes with backtick (`), not backslash — the message accidentally interpolated the auto-variable.
- Spectre-rendered
llmwizard.Start-LLMWizardnow dispatches toStart-LLMWizardSpectrewhen PwshSpectreConsole is available, falling back toStart-LLMWizardClassicotherwise. The Spectre flow usesRead-SpectreSelectionfor model / quant / context / action picks andRead-SpectreConfirmfor the-Q8toggle, and renders the fullShow-ModelCatalogSpectretable above the model picker so quant fit / size / built status stay visible while choosing. Same env switch as the dashboard:$env:LOCAL_LLM_NO_SPECTRE=1forces the classic wizard. llmcescape hatch. Newllmcfunction callsStart-LLMWizardClassicdirectly, bypassing Spectre regardless of availability — useful when a Spectre render bug makes the rich wizard unusable.- Wizard error trap. Each Spectre prompt is wrapped in
Invoke-LLMWizardStep; on exception,Save-LocalLLMWizardErrorrecords the full trace (timestamp, context tag, exception type/message,InvocationInfo.PositionMessage,ScriptStackTrace, inner exception) to~/.local-llm/wizard-errors.logand pauses withPress Enter to continueso a Spectre live-display refresh can't scroll the trace off screen. Inspect withllmlogerr [-Lines 80]; reset withllmlogerrclear.
- Spectre markup parse errors crashed wizard prompts. Choice labels like
[Back],[Cancel],[Show all tiers],[Keep current: …], and the fit tags[fits]/[tight]/[over]/[?]were passed straight toSelectionPrompt, which interprets[…]as Spectre markup — every render frame threwEncountered malformed markup tag …and the live-display refresh hid the trace. Sentinels are escaped as[[…]]; user-supplied text (display names, quant/context keys, notes,$ModelKeytitles) is routed throughConvertTo-LocalLLMSpectreSafe; fit tags became proper colored markup ([green]fits[/],[yellow]tight[/],[red]over[/],[grey50]?[/]). - Renderables leaked into captured pipeline output.
Format-SpectrePanel/Format-SpectreTablereturnaSpectre.Console.Renderable; PwshSpectreConsole'sformat.ps1xmlonly renders that to ANSI atOut-Default. InsideShow-ModelCatalogSpectre(called fromSelect-LLMModelKeySpectre, captured by$modelKey = …), the Panel and Table objects bubbled up into$modelKey, producing arrays like[Panel, Table, "qcoder30"]and trippingCannot convert value to type System.Stringon the nextGet-ModelDef -Key $modelKey. All sixFormat-Spectre*call sites now pipe to| Out-Hostso the renderable renders eagerly and emits nothing to the caller's pipeline. Side effect: the catalog table that was silently swallowed during the wizard now appears as intended.
qcoder30256k context. Added"256": 262144to the Qwen3-Coder-30B-A3B Heretic model and a newiq4xsquant (Qwen3-Coder-30B-A3B-Instruct-Heretic.i1-IQ4_XS.gguf, ~16.5 GB). The 256k profile only fits a 4090 with IQ4_XS weights + q4_0 KV cache (~6 GB at 256k); useqcoder -Ctx 256 -Quant iq4xs.qcodernext(experimental). New entry pointing atmradermacher/Huihui-Qwen3-Coder-Next-abliterated-i1-GGUF— the 80B/3B-active hybrid DeltaNet+Attention coder. Quants:iq1m,iq2s,iq3xxs. Onlyiq1m(~18.1 GB) fits a single 4090 with any KV headroom; flagged as experimental and "tight on 4090" in the display name.- Per-model
Description,QuantNotes,ContextNotescatalog fields. Free-form strings keyed by quant/context name. Backfilled across the existing catalog so users can see file sizes, KV pressure, and "when to pick this" guidance without leaving the launcher. info/llmdocs/llmwizard surfaces.Show-ModelCatalog,Show-LLMDynamicModelSummary,Select-LLMModelKey,Select-LLMQuantKey, andFormat-LLMContextLabelall render the new notes inline. The current default quant is marked with*in the per-quant list.addllm -Description,-QuantNotes,-ContextNotes. Optional params onAdd-LocalLLMModel/addllmthat round-trip into the catalog entry. Notes are hashtables (@{key='note'}) keyed by the same quant/context shortname.-Q8+ long-context guard.Invoke-ModelShortcutrefuses-UseQ8whenever the resolvednum_ctxexceeds theQ8KvMaxContextceiling. The error message tells the user to drop-Q8, lower-Ctx, or raise the threshold.- VRAM-aware recommendations. New top-level
VRAMGBsetting plusGet-LocalLLMVRAMInfohelper. Auto-detects vianvidia-smi --query-gpu=memory.total(largest GPU on a multi-card box). Override viaSet-LocalLLMSetting VRAMGB 32. The dashboard surfaces the resolved value + source (configured / auto / fallback). QuantSizesGBper-quant numeric field. Drives a[fits]/[tight]/[over]badge next to each quant ininfoand the wizard, computed against the host's VRAM (weight-budget heuristic:[fits]when the model leaves >=7 GB headroom for KV,[tight]when only ~2 GB headroom,[over]otherwise). Backfilled acrossqcoder30,qcodernext,q36plus,q36heretic,q27heretic,q27hauhau.Q8KvMaxContextnow scales with VRAM by default. Removed the explicit131072literal from the catalog. The guard derives(VRAMGB - 16) * 16384(floored at 64k) when not pinned, so a 5090 (32 GB) gets ~256k while a 4090 (24 GB) gets ~128k. Override still works viaSet-LocalLLMSetting Q8KvMaxContext.- Quant notes rewritten to be VRAM-agnostic where possible. The hand-written notes describe quality/use-case (no longer "partial offload on a 4090"); the per-quant
[fits]/[tight]/[over]badge is the live verdict for the host's actual VRAM.
Picking a quant and context blindly was costing real time — Q4_K_M is fine at 64k but cannot fit 256k KV; Q6_K is too heavy at any long context; -Q8 looks free until it OOMs at 128k+. The notes encode the tradeoff directly next to the selector, and the guard prevents the worst foot-gun (-Q8 -Ctx 256) from ever launching.
VRAM auto-detection was the next cliff: every recommendation in the catalog implicitly assumed a 24 GB 4090. A 5090 user (32 GB) should see Q5_K_M as [fits], not "partial offload"; a 4080 user (16 GB) should see most 35B variants flagged [over] and not waste time downloading them. The fit badge gives a per-host verdict without the user having to do KV-cache arithmetic.
The catalog gained one realistic 256k coder option (qcoder30 -Ctx 256 -Quant iq4xs) and one aspirational one (qcodernext) so the "uncensored 256k on a 4090" question has a documented answer instead of trial-and-error.
~/.local-llm/settings.json— per-machine overlay for the catalog. Top-level scalars (LocalPilotRoot,OllamaAppPath,Default,KeepAlive,RequireAdvertisedTools,NoThinkProxyPort,LocalModelTools,LocalPilotRepoUrl, etc.) load fromllm-models.jsonfirst, then any matching keys insettings.jsonoverride.ModelsandCommandAliasesare catalog-only and protected from override.Set-LocalLLMSetting <Key> <Value>— writes tosettings.jsonand reloads. Pass$null/""to remove a key. RefusesModels/CommandAliases.LocalPilotRepoUrlconfig field, defaulting tohttps://github.com/C0deGeek-dev/LocalPilot.Ensure-LocalPilotInstalled— called byInvoke-LocalPilotClibefore doing anything. If the configuredLocalPilotRootdoesn't containsrc/entrypoints/cli.tsx, it promptsClone <url>? [y/N]and runsgit cloneon confirmation. Aborts with a clear instruction otherwise.settings.jsonadded to.gitignoreso per-machine config never lands in the repo.install.ps1prints a tip pointing atSet-LocalLLMSettingfor fresh-machine setup.
Cloning the public repo onto a different machine should not require editing llm-models.json to fix LocalPilotRoot (and risking merge conflicts with future pulls). LocalPilot launches should do the obvious thing on a fresh machine instead of failing because no checkout is around.
The external harness fork was renamed to LocalPilot. Propagated through this project:
- JSON config field renamed to
LocalPilotRoot. - Internal CLI wrapper renamed to
Invoke-LocalPilotCli. - Switch parameter renamed to
-LocalPilotonStart-ClaudeWithOllamaModel,Invoke-ModelShortcut, and the per-model shortcut functions. - User-visible labels updated: launcher banner, wizard action label, install diagnostics, README, quick reference (
llmdocs). - Existing local folder paths were not renamed and still work as the configured
LocalPilotRoot.
Reviewed the project, then ran a single-day refactor pass guided by an explicit plan (plan.md, retired into this changelog).
- Persona pollution.
LocalLLMProfile.ps1had a hardcoded "You are Qwen, created by Alibaba Cloud" prepended to every model launch — wrong for Devstral and even somewhat wrong for the Qwen variants whose GGUF templates already self-identify. Removed the persona layer entirely; the system prompt now contains only universal tool-use rules, plus an opt-in deferred-tool-schema block (gated onLimitTools). enforcer-claude.ps1rewritten. The wrapper used to hardcodeqcoder30and bypass the no-think proxy by pointing atlocalhost:11434. Now it readsDefaultfromllm-models.json(or$env:ENFORCER_MODEL), routes through the proxy on11435, self-starts the proxy if needed, and sets the same thinking/caching/attribution env stack as the main launcher.- Legacy harness stub deleted. It was a one-liner that called the old harness wrapper with no args and ignored everything. The flag-based LocalPilot launch path covers it now.
- Tool-support detection rewritten.
Test-OllamaModelSupportsToolsused to grepollama showtext for the literal word "tools" — which could match unrelated lines. Now POSTs to/api/showand checks the structuredcapabilitiesarray. Falls back to the regex if the API is unreachable. - Devstral parser confirmed correct.
Parser: "none"was the right call (its GGUF self-templates with persona,[SYSTEM_PROMPT]/[TOOL_CALLS]tags, andcapabilities=[completion,vision,tools]). Documented inline via aParserNotefield. init -Staleparameter shadow bug.Initialize-LocalLLMdeclared[switch]$Stale; the body did$stale = @(Get-StaleModelAliases). PowerShell variables are case-insensitive, so the assignment tried to coerce an array into aSwitchParameterand failed silently, leaving$staleas the boolean$true. Renamed the local to$staleEntries.
- Per-model
Toolsallowlist.Start-ClaudeWithOllamaModelnow takes-Tools;Invoke-ModelShortcutreads the optionalToolsfield from the model def, falling back to the globalLocalModelTools. No models populated yet — capability only. - Auto-generated alias prefixes. Added
ShortNamefield per model.Register-ModelShortcutswalkedShortName × Contexts × actionsand registered PowerShell aliases. Pruned the 30 hand-maintainedCommandAliasesentries to{}. - Parser-version stamping.
New-OllamaModelFromSourcenow writes a sha256-hash sidecar at<profile-root>\parser-versions\<aliasname>.txt.Test-ModelAliasFresh,Get-StaleModelAliases,init -Stale, and theinfodashboard surface stale aliases (parser config drifted since build). - Default model. Added
"Default"field at the top ofllm-models.json.Get-DefaultModelKeyreads it (with a recommended-tier fallback). New shortcuts:llmdefault, an LocalPilot default shortcut, andllmdefaultchat. Used by the enforcer. ThinkingPolicyper model. Eitherstrip(default) orkeep.keepmode bypasses the no-think proxy, pointsANTHROPIC_BASE_URLat Ollama directly, and skips the thinking-disable env vars. Set onq36opus47abl. Launcher banner shows the active mode.- Configurable
OLLAMA_KEEP_ALIVE. Top-levelKeepAlivefield;Set-OllamaRuntimeEnvreads it (defaults to"-1"). Wait-Ollamaresilience. Deadline bumped 20s → 60s. After 5s of waiting, printsWaiting for Ollamaand adds a.every 2s.- Bench history persistence.
Test-OllamaSpeednow appends to<profile-root>\bench-history.jsonlper run.Show-LLMBenchHistory [-Model] [-Last N]and the shortobenchalias display recent runs. - Header truth. File header lost the "+ LM Studio" advertisement (LM Studio support was never implemented). Now states "Windows / PowerShell only — does not work in WSL/bash."
- Flag-based shortcut scheme (Option C). Replaced ~135 multi-suffix functions with 9 model functions:
dev,qcoder,q36,q36hau,q36p,q36h,q27,q27hau,qop. Each takes-Ctx,-LocalPilot,-Chat,-Q8, and (where applicable)-Quant. IntroducedGet-ModelShortcutNameandUnregister-AllModelShortcuts;Register-ModelShortcutsis now idempotent.
- Diagnostic logging on tool-call failure. Naive stderr-tee breaks Claude Code's interactive terminal; needs better design (probably a debug-mode flag rather than a wrapper).
Project predates this changelog. The state at the start of this round:
- Single 2,506-line
LocalLLMProfile.ps1engine with JSON catalog (llm-models.json). - Per-(model, context) Ollama aliases.
- Hand-maintained
CommandAliasesmap. - HTTP proxy on
11435stripping Anthropic thinking/reasoning fields. - Hardcoded "You are Qwen" persona prepended to every launch.
enforcer-claude.ps1hardcoded toqcoder30and pointing at the wrong port.