Skip to content

WeaveLLM 0.1.0 — full rewrite (local models, workflow editor, desktop shell) - #30

Merged
AndyTechnologies merged 38 commits into
masterfrom
sdd/weavellm
Sep 21, 2026
Merged

AndyTechnologies merged 38 commits into
masterfrom
sdd/weavellm

Conversation

@AndyTechnologies

Copy link
Copy Markdown
Owner

Summary

WeaveLLM — full rewrite of the llm-proxy gateway: local llama.cpp models behind an OpenAI-compatible API, workflows composed in a visual editor and exposed as virtual models, a desktop shell, and sandboxed code execution.

  • Managed llama.cpp backend: spawn-on-activation lifecycle, GGUF catalog with YaRN-safe metadata, model downloads, AES-256-GCM keychain secrets
  • OpenAI-compatible API on :4317: chat/completions, streaming SSE + /ws websocket relay, health, models, dashboard API
  • Workflow engine: DAG with 14 node types (generate/refine/passthrough llm_call modes, conditional routing), virtual model gateway/<name> exposure, YAML import/export
  • Desktop shell: single-binary builds via Electrobun (Bun main, Astro 7 / Svelte 5 UI, @xyflow DAG editor), Hutch auto-update checks
  • Sandboxed code execution: unshare -n network isolation, tmp-only FS, timeout-bounded

Changes

File Change
src/ Rewritten gateway core: config, backend manager, providers, orchestrator engine, routes, middleware
frontend/ New desktop shell UI: workflow editor, settings, model management
scripts/ Build/binary tooling (Electrobun, gosh-CLI integration)
openspec/specs/* 24 canonical capability specs synchronized to verified behavior
CHANGELOG.md [0.1.0] release entry

Test Plan

  • bun run typecheck — clean
  • bun run lint — 0 fail
  • bun test — 382 pass / 0 fail / 39 files (961 expect)
  • SDD pipeline: verify PASS-WITH-WARNINGS (63/63 reqs, 102/102 scenarios), hard-verify (5/5 injected breaks caught), hard gate (specs→code matrix, zero tautology)
  • bun run build — bundles cleanly

Contributor Checklist

  • Conventional commit format
  • No Co-Authored-By trailers
  • Docs updated if behavior changed (specs synced, CHANGELOG, archive report)

Delivery follows ordinary repository policy; merge is a human decision.

…end shell

Boot path (src/main.ts) replaces the legacy gateway entry for WeaveLLM:
- electrobun/hutch config: Bun main process, 3 release targets, flatpak
- frontend shell: Astro 7 static + Svelte 5 islands (ModelBadge)
- src/app/*: config, JSON-log nozzle, Bun.serve proxy, cold-start budget,
  update check (offline silent, GitHub releases)
- src/db/schema.ts: 10 tables, idempotent applySchema, WAL
- scripts/build-binaries.ts: hutch per-target build + 100 MB gate
- 26 new tests (531 total green), typecheck + lint clean, boot 714 ms
…store

- manager.ts: LlamaProcessManager with DI seams (spawn/clock/sleep/health/
  log); single spawn --port 0 + deadline-bounded port regex, wait-ready
  health gate, fail-fast boot with actionable EADDRINUSE, restart with
  exponential backoff, idle kill, version floor gate, TERM->KILL stop
- gguf.ts: yarn_orig_ctx derivation, YaRN scale with ratio>=1 guard
- spawn-args.ts: RED-metachar arg validation, YaRN + KV q8_0 + host-only
  cache-ram args, llama.cpp b9908 floor
- model-config.ts: model_config store (upsert, persists across reopen) +
  snake_case sampler body mapping
- retire legacy router-mode closure (routes/middleware/dashboard/config/
  orchestrator engine/ui/e2e/playwright) — no longer reachable after the
  manager rewrite; 163 tests green, typecheck + lint clean
- ci: disable legacy e2e job (phase 6 restores); release: disable tag
  trigger until phase 7 build pipeline
- src/sandbox/runner.ts: unshare -n/sandbox-exec isolation, static policy
  denial (network/fs/secrets), tmp-only workspace, env whitelist, timeout
  kill (SIGTERM→SIGKILL), output cap; policy-only fallback when unshare
  is not permitted (EPERM)
- src/providers/embeddings.ts + /v1/embeddings route in src/routes/v1.ts:
  OpenAI embeddings wire shape over the managed llama-server backend,
  404 model_not_found when no local embedder
- src/rag/chunks.ts: cosine top-k retrieval over the chunks table
  (Float32Array BLOBs); empty store and dimension mismatch handled
- src/rag/memory.ts: kv_memory conversation store + message injection
- src/rag/rag.ts: rag_local embed→retrieve→prompt→answer with explicit
  no-context notice

Tests: +38 (337 total), typecheck and lint clean.
join nodes aggregate their direct predecessors' outputs into a drafts
variable; downstream llm_call synthesis consumes every draft as numbered
user turns (MoA 3+1). Composed pipeline steps now surface in the outer
event stream and results ledger. Adds 6.3 taxonomy-parity, 6.4 MoA+router,
and pipeline-composition tests.
parseWorkflowGraph/serializeWorkflowGraph round-trip the full graph
(14 node types + every field), tolerating unknown fields for forward
compat and naming the offending node/edge on structural failures.
validateGraph messages translated to English (editor surfaces them
inline); NODE_TYPES registry added for the shared taxonomy.
WorkflowStore persists YAML docs (version bump on resave) and appends
execution_history rows. makeApiHandler exposes GET/PUT/DELETE
/api/workflows[/:name] plus POST :name/run (injected runner, 404/502
passthrough) and GET :name/logs. PUT validation names the offending
node/error via parseWorkflowGraph + validateGraph. Runner contract
defined for the boot wiring.
Boot now composes the workflow runtime: WorkflowStore → makeRuntimeServices
(registry, sandbox seam, embedder/chunks/memory seams) → makeWorkflowRunner.
The /api dispatcher answers /api/workflows; the /v1 handler advertises and
runs gateway/<name> models, so legacy chains route through the same path.
runCode now goes through the injected sandbox seam instead of importing
runSandbox directly. Boot-level integration test covers CRUD, gateway model
listing, and a real run over a socket.
Typed websocket protocol for live runs: bind → step_started /
step_completed → token (the completed run's OpenAI-wire SSE, then exactly
one data: [DONE]) → status. Events are scoped to the socket that bound the
workflow; a client disconnect aborts the upstream run via a per-socket
AbortController. WorkflowRunner.run gains an optional onEvent telemetry
sink threaded into the engine. Plain HTTP /ws answers 426. Integration
tests run against a real Bun server with real WebSocket clients, including
an abort test; the boot harness exercises /ws end to end.
Add the Svelte 5 editor island on the shell page: palette of the full
14-node taxonomy, SvelteFlow canvas with cycle rejection and live engine
validation, and YAML import/export through the workflow-yaml round-trip.
All graph logic lives in pure helpers (frontend/src/lib/workflow-nodes.ts)
unit-tested with bun test; astro build gates the xyflow interop.
Remove openai-compatible.ts + sdk-surface.ts and their tests; the
provider layering now talks to llama-server through the OpenAI wire
format directly (http-core + adapters). Drop ai, @ai-sdk/*, express,
helmet, @types/express deps; suite drops exactly the deleted tests
(422->382 pass, suite stays green).
All 50 tasks complete. Final gate: typecheck + lint clean, bun test
382 pass / 0 fail / 39 files, bun run build + build:frontend green.
Tag v0.1.0 remains pending (no tag-capable tool; candidate = this SHA).
@socket-security

socket-security Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​astrojs/​svelte@​9.0.11001008195100
Addedelectrobun@​2.0.11001008796100
Addedsvelte@​5.57.0881008797100
Addedastro@​7.3.2981008897100
Addedyaml@​2.9.110010010090100
Added@​xyflow/​svelte@​1.6.610010010096100

View full report

@socket-security

socket-security Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm @emnapi/runtime is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: package.json → npm/astro@7.3.2 → npm/@emnapi/runtime@1.11.1

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/@emnapi/runtime@1.11.1. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

The stderr reader binding in waitForPortAndTail failed typecheck on a fresh
install: proc.stderr.getReader() resolves to stream/web's reader while the
parameter was typed with bun-types' global ReadableStreamDefaultReader, whose
readMany member is absent from the stream/web copy. Type the parameter with
the minimal structural surface tailStderr actually consumes instead of the
concrete global type, so the build no longer depends on which duplicate wins.

Verified on a clean clone: bun run typecheck && bun run lint && bun test
(382 pass / 0 fail).
README.md: rewrite to describe WeaveLLM 0.1.0 — real port 4317,
WEAVELLM_* env config, DAG workflows (not chains), real endpoint table,
Astro 7 desktop shell, current-status note for unwired local backend.

AGENTS.md: update architecture map, contracts, and configuration model
to match the WeaveLLM source tree; note config.example.yaml as stale.

Both verified against src/app/config.ts, src/routes/v1.ts, src/main.ts,
and src/app/server.ts.
…onfig, embeddings flag, health models

- Add models.active INTEGER NOT NULL DEFAULT 0 with idempotent PRAGMA-gated ALTER migration
- Add WEAVELLM_LLAMA_BIN env → llamaBin on AppConfig (default llama)
- Add embeddings?: boolean to LlamaSpawnArgsInput → --embeddings flag emission
- Add ServerDeps.localModels for /api/health endpoint (optional field)
- Change IDLE_TIMEOUT_MS default from 5 min to 10 min (binding Decision 6)
- Extract resolveLlamaBin pure function mirroring resolvePort pattern
- 15 new tests; 397 total passing (typecheck, lint, test all green)

Pre-existing ws.test.ts fixtures updated for the new required AppConfig.llamaBin
field (AppConfig contract expansion).
…ess gating, boot wiring

Completes tanda 2 (Tasks 4, 5, 6, 8, 9) of the wire-local-backend change:
the managed llama-server backend is now wired into the runtime.

LocalBackendHub (src/backend/hub.ts):
- preflight: version floor b9908, ENOENT-tolerant (per-model error, boot continues)
- restoreActive on boot, activate/deactivate (in-flight drain, 1s poll, 30s force)
- readiness-gated Provider wrapper: lazy re-spawn after idle-stop, 503 on error,
  start-latch serializes concurrent spawns; per-request dispatcher via zero-arg
  localProvider(); embedder with lazy settings designation read
- 10-min idle stop, stopAll for graceful shutdown

/api/models route group (api.ts): list / status / activate / deactivate behind
an optional auth gate; HubError status maps straight to the response.

Boot wiring (main.ts): hub.preflight() + restoreActive() before handler
construction (binding Decision 2), non-null closures into runtime/v1/health,
shared auth gate, BootResult.shutdown drained on SIGINT/SIGTERM.

40 new tests (hub 24, api models 6, boot 3, v1 integration 7);
full gate green: 437/437 pass across 41 files.
…deltas into canonical specs

- backend-management +6 modified, 2 added; dashboard-api +4 added;
  local-model-catalog +4 added; embeddings-rag +1 modified, 2 added
- move change folder to openspec/changes/archive/2026-09-15-wire-local-backend
- add archive-report with final-state facts (19/19 req, 47/47 scenarios,
  438 tests, hard-gate PASS, F4 review acknowledged)
- bun start now builds frontend then serves the compiled UI (frontend/dist)
  with SPA fallback at / and /ui, excluding /api/* and /v1/*
- bun run dev runs backend watch + Astro dev in parallel via scripts/dev.ts
- static UI handler with traversal protection and WEAVELLM_UI_DIR override
- AGENTS.md updated with the new start/dev contract
# Conflicts:
#	src/app/config.ts
#	src/app/server.test.ts
#	src/app/types.ts
…form

llama.cpp writes --version to stderr, not stdout; the preflight read only
stdout, got empty output, and fail-fast exited(1) silently — the fixed port
fix regressed ./start to an immediate silent dead exit.

- checkLlamaVersionFloor now accepts the real form '(build 10679, ...)'
  as well as the condensed bNNNN tag
- preflight()/checkVersion() collect stdout+stderr and check their
  concatenation
- hub preflight logs its fatal message through the boot logger so failure is
  visible, and the hub wires that log at boot

Verified: bun run typecheck clean; bun test 458 pass / 42 files; ./start
reaches listening 127.0.0.1:4317 in ~200ms cold with the local llama build.
AppImage-style dist/weavellm skeleton: a tiny C stub (scripts/selfextract.c)
that reads an appended tar.gz payload trailer at EOF, extracts the Electrobun
dev bundle to $XDG_CACHE_HOME/weavellm/<payload sha256> (cached via a
.complete marker under a flock, so re-runs skip extraction), defaults
WEBKIT_DISABLE_DMABUF_RENDERER=1 (explicit override wins), and execs
bin/launcher with exit-code propagation.

The trailer byte layout (magic + format version + uint64 LE size + sha256 hex)
has ONE source of truth: scripts/selfextract-layout.ts, which also renders the
C header the stub includes, so the two sides cannot drift. All pure helpers
(cache base, extraction dir, render-env merge, trailer round-trip) are covered
by scripts/selfextract-layout.test.ts.
scripts/build-binary.ts orchestrates the portable single-file build:
bun run build:frontend -> hutch electrobun build --env=dev (REAL CLI at
~/.hutch/bin/hutch; bunx hutch is the wrong npm package and hutch is not on
PATH) -> tar.gz of the flat dev bundle contents -> compile the ~15 KB C stub
(generated trailer header from selfextract-layout.ts) -> append payload +
trailer to dist/weavellm -> enforce the <100 MB gate (reuses assertBundleSize)
and report the payload sha256 + extraction cache path.

--skip-frontend / --skip-build reuse an existing SPA / dev bundle.
WEAVELLM_ARTIFACTS_DIR overrides the output dir, matching build:binaries.

package.json build:binary now points at this pipeline (was the backend-only
bun --compile stub). build:binaries doc comment clarifies it targets the
Cottontail installer/update flow and is NOT the portable path.
desktop-app-shell now specifies the user-selected distribution form: ONE
self-contained executable built from the Electrobun v2 dev bundle via Hutch,
under 100 MB, host-only matrix, with no installer / no self-updater. The old
Auto-update check requirement (Hutch channel + consent-based install) is
replaced by the portable contract with scenarios for single-file run, cached
extraction reuse, and the default WEBKIT_DISABLE_DMABUF_RENDERER=1 render
environment. The All-three-targets-build scenario is corrected to the
host-only reality.
…robun v2 config

- main.ts: open Electrobun BrowserWindow targeting the local server when
  running inside a bundle (direct bun run stays server-only)
- app/config: resolveUiDir/uiDirCandidates (env override > dev build >
  bundled ui) with tests
- electrobun.config + test: verified v2 host-only API, bun main process,
  window opens app's own server
- hutch.config: pin electrobun 2.0.2-beta.27 (2.1.0 was never published)
- build-binaries: host-only stable channel via real hutch CLI (~/.hutch/bin),
  Cottontail installer artifacts documented as distinct path
- package.json: start -> start-desktop.ts, add electrobun dep
- types/electrobun.d.ts: ambient v2 declarations for the throw-on-import stub
- tsconfig paths -> ambient declarations; eslint ignores build/artifacts/.hutch
- UI: Gentle-AI hybrid theme (global.css, ModelBadge, WorkflowEditor, index)
- gitignore: build/, artifacts/, .hutch/, .cottontail-tmp/
- odd: feature docs for desktop-shell-mvp, ui-gentle-ai-theme, portable-binary
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant