From bc0b2b361b8913be7e3630809fc87384ad207e32 Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 14:54:54 -0400 Subject: [PATCH 1/8] =?UTF-8?q?feat(embeddings):=20Phase=205=20Windows=20?= =?UTF-8?q?=E2=80=94=20DLL=20+=20source-built=20tokenizer,=20zip=20assets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds windows-amd64 to assets/manifest.json: the official Microsoft ONNX Runtime DLL (onnxruntime-win-x64-1.26.0.zip, member-pinned) and our source-built libtokenizers.a. daulet/tokenizers ships no Windows prebuilt, so it is built from the v1.27.0 tag with the GNU Rust toolchain (must match MinGW gcc that CGo links with) and hosted in this repo's releases (tokenizers-1.27.0-windows-x64), SHA-256 pinned like every artifact. - assets_embed_windows.go: per-platform go:embed of onnxruntime.dll. - Makefile: extract .zip archives (unzip, else Windows System32 tar) so make assets works on Windows — tars stay the path for the others. - Documentation/windows-build.md: full build + artifact-provenance recipe (toolchain versions, the GNU-must-match-MinGW constraint, the libtokenizers_ffi.a -> libtokenizers.a rename in the v1.27.0 layout). Tokenizer lib compiled on Windows x64 (rustc 1.97.1 GNU, Go 1.26.5, MinGW gcc 16.1.0). App build + on-device verification run next on the PC. Co-Authored-By: Claude Opus 4.8 (1M context) --- Documentation/windows-build.md | 87 +++++++++++++++++++ Makefile | 7 +- assets/manifest.json | 28 +++++- .../embeddings/local/assets_embed_windows.go | 19 ++++ 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 Documentation/windows-build.md create mode 100644 internal/embeddings/local/assets_embed_windows.go diff --git a/Documentation/windows-build.md b/Documentation/windows-build.md new file mode 100644 index 0000000..c3fb492 --- /dev/null +++ b/Documentation/windows-build.md @@ -0,0 +1,87 @@ +# Windows x64 Build & Artifact Provenance (local-embeddings, Phase 5) + +How the Windows local-embedding build is produced and how to reproduce its one +source-built artifact. Records what was actually run (versions below are what +shipped), so a future maintainer can rebuild after a dependency bump. + +## Why Windows needs a build step at all + +Every other platform gets both native libraries as official prebuilts. Windows +is the exception on one of them: + +| Artifact | Windows source | +|---|---| +| ONNX Runtime DLL | **Official** Microsoft release (`onnxruntime-win-x64-1.26.0.zip`) — pinned directly in `assets/manifest.json`. | +| `libtokenizers.a` (static) | **No upstream Windows prebuilt** — `daulet/tokenizers` publishes macOS/Linux only. We build it from source and host it in this repo's releases (`tokenizers-1.27.0-windows-x64`). | + +## Toolchain (installed via scoop) + +``` +scoop install go mingw rustup-gnu make +rustup default stable-x86_64-pc-windows-gnu +``` + +Verified versions: Go 1.26.5, MinGW gcc 16.1.0, rustc/cargo 1.97.1 (GNU), +GNU make 4.4.1. + +**The GNU pairing is load-bearing.** CGo links the Go binary with MinGW `gcc`, +so the Rust static lib must come from the `*-windows-gnu` toolchain. Building it +with the default MSVC toolchain yields a `.lib` in a format MinGW cannot link. + +## Reproducing `libtokenizers.a` + +``` +git clone --depth 1 --branch v1.27.0 https://github.com/daulet/tokenizers +cd tokenizers +cargo build --release +# Output: target/release/libtokenizers_ffi.a (~40 MB) +``` + +Note the **name change**: this repo layout (v1.27.0) emits `libtokenizers_ffi.a` +from the `tokenizers-ffi` crate. The macOS/Linux prebuilts — and therefore the +`-ltokenizers` link flag and the manifest's `member: libtokenizers.a` — expect +`libtokenizers.a`. Same archive, so we simply rename on packaging: + +``` +cp target/release/libtokenizers_ffi.a libtokenizers.a +tar czf libtokenizers.windows-x86_64.tar.gz libtokenizers.a +# publish as a repo release, pin archive + member SHA-256 in the manifest +``` + +## Building the app + +``` +git clone https://github.com/unitedeffectslabs/agent-memory +cd agent-memory && git checkout feat/xplat-windows +cd frontend && npm install && cd .. +make assets # downloads DLL + model + tokenizer + our published static lib; verifies all checksums +make build # wails build -skipbindings -tags localembed → build/bin/agent-memory.exe +``` + +`make assets` extracts the `.zip` ORT archive via `unzip` if present, else falls +back to Windows' bundled `C:\Windows\System32\tar.exe` (Git Bash's GNU tar +cannot read zips). Checksums use `sha256sum` if present, else `shasum -a 256` +(both provided by Git for Windows). + +## Verification (the Phase 5 gate) + +1. Integration test — real tokenizer + ORT + model, as a native Windows binary: + ``` + CGO_LDFLAGS="-L$PWD/internal/embeddings/local/lib -ltokenizers" \ + go test -tags localembed -count=1 -run TestIntegrationEmbed -v ./internal/embeddings/local/ + ``` + Expect PASS, cosine ordering ≈ related 0.14 < cross-lingual 0.17 < unrelated + 0.29 (matches macOS arm64/x86_64 and Linux). +2. Offline app run: disconnect network, `agent-memory.exe --db test.db`, onboard + with **no API key**, index a small folder, confirm search returns matches. + +## Troubleshooting (observed / anticipated) + +- **Missing Windows system symbols at link** (`ws2_32`, `bcrypt`, `userenv`, + `ntdll`): append `-lws2_32 -lbcrypt -luserenv -lntdll` to `CGO_LDFLAGS`. If the + build needs them, they go in the Makefile behind a Windows guard. +- **`onnxruntime_providers_shared.dll` load error**: the official zip ships this + second DLL; CPU-only use normally doesn't need it, but if ORT fails to load, + pin it as an extra `embedded/` artifact beside the main DLL. +- **Defender quarantines the fresh unsigned exe**: add a temp exclusion for the + repo folder while testing. diff --git a/Makefile b/Makefile index 1a04c93..97d6c5a 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,12 @@ assets: mkdir -p "$$(dirname "$$destpath")"; \ if [ -n "$$member" ]; then \ xd=$$(mktemp -d); \ - tar xzf "$$tmp" -C "$$xd" "$$member"; \ + case "$$url" in \ + *.zip) if command -v unzip >/dev/null 2>&1; then unzip -q "$$tmp" "$$member" -d "$$xd"; \ + elif [ -x /c/Windows/System32/tar.exe ]; then /c/Windows/System32/tar.exe xf "$$tmp" -C "$$xd" "$$member"; \ + else tar xf "$$tmp" -C "$$xd" "$$member"; fi ;; \ + *) tar xzf "$$tmp" -C "$$xd" "$$member" ;; \ + esac; \ cp "$$xd/$$member" "$$destpath"; \ rm -rf "$$xd"; \ got2=$$($(SHA256) "$$destpath" | awk '{print $$1}'); \ diff --git a/assets/manifest.json b/assets/manifest.json index 9cdfe00..50532cf 100644 --- a/assets/manifest.json +++ b/assets/manifest.json @@ -1,6 +1,6 @@ { "schema": 1, - "comment": "Pinned local-embedding artifacts (URLs + SHA-256). Weights/libs are NEVER committed; `make assets` downloads and checksum-verifies these into internal/embeddings/local/embedded/ (go:embed runtime assets) and internal/embeddings/local/lib/ (link-time static lib). For tarball artifacts, `sha256` is the checksum of the downloaded archive and `member_sha256` is the checksum of the extracted member. `dest` is relative to internal/embeddings/local/. Model + tokenizer entries are identical bytes on every platform (per-platform keyed for a uniform `make assets`). Remaining Phase 5 platform: windows-amd64. darwin-amd64's onnxruntime is our own source build (official mac-Intel prebuilts stopped at ORT 1.23) hosted in this repo's GitHub releases — see the ort-1.26.0-darwin-x64 release notes for the reproducible recipe.", + "comment": "Pinned local-embedding artifacts (URLs + SHA-256). Weights/libs are NEVER committed; `make assets` downloads and checksum-verifies these into internal/embeddings/local/embedded/ (go:embed runtime assets) and internal/embeddings/local/lib/ (link-time static lib). For tarball artifacts, `sha256` is the checksum of the downloaded archive and `member_sha256` is the checksum of the extracted member. `dest` is relative to internal/embeddings/local/. Model + tokenizer entries are identical bytes on every platform (per-platform keyed for a uniform `make assets`). darwin-amd64's onnxruntime is our own source build (official mac-Intel prebuilts stopped at ORT 1.23) hosted in this repo's GitHub releases — see the ort-1.26.0-darwin-x64 release notes for the reproducible recipe. windows-amd64's tokenizers_static has no upstream prebuilt: it is built from Rust source per Documentation/windows-build.md and hosted in this repo's releases (tokenizers-1.27.0-windows-x64).", "platforms": { "darwin-arm64": { "model": { @@ -28,6 +28,32 @@ "dest": "lib/libtokenizers.a" } }, + "windows-amd64": { + "model": { + "url": "https://huggingface.co/Xenova/multilingual-e5-small/resolve/main/onnx/model_quantized.onnx", + "sha256": "f80102d3f2a1229f387d3c81909990d8945513e347b0eab049f7de3c6f98c193", + "dest": "embedded/model_quantized.onnx" + }, + "tokenizer": { + "url": "https://huggingface.co/Xenova/multilingual-e5-small/resolve/main/tokenizer.json", + "sha256": "0b44a9d7b51c3c62626640cda0e2c2f70fdacdc25bbbd68038369d14ebdf4c39", + "dest": "embedded/tokenizer.json" + }, + "onnxruntime": { + "url": "https://github.com/microsoft/onnxruntime/releases/download/v1.26.0/onnxruntime-win-x64-1.26.0.zip", + "sha256": "6ebe99b5564bf4d029b6e93eac9ff423682b6212eade769e9ca3f685eaf500b4", + "member": "onnxruntime-win-x64-1.26.0/lib/onnxruntime.dll", + "member_sha256": "b2ba7ca16e0e4fe71ad5148744ab885a2f5809e52a0c3de4d9ba3853a03977f9", + "dest": "embedded/onnxruntime.dll" + }, + "tokenizers_static": { + "url": "https://github.com/unitedeffectslabs/agent-memory/releases/download/tokenizers-1.27.0-windows-x64/libtokenizers.windows-x86_64.tar.gz", + "sha256": "882f520174a6cb14dcf4dca559375d65915a69a075bd85c22e40463bc0b466a8", + "member": "libtokenizers.a", + "member_sha256": "5e0815434a9d9eea40638ae9303f239c85059868673dc7e2a5a1eee72a9ad692", + "dest": "lib/libtokenizers.a" + } + }, "darwin-amd64": { "model": { "url": "https://huggingface.co/Xenova/multilingual-e5-small/resolve/main/onnx/model_quantized.onnx", diff --git a/internal/embeddings/local/assets_embed_windows.go b/internal/embeddings/local/assets_embed_windows.go new file mode 100644 index 0000000..7d47555 --- /dev/null +++ b/internal/embeddings/local/assets_embed_windows.go @@ -0,0 +1,19 @@ +//go:build localembed && windows + +package local + +import "embed" + +// Per-platform ONNX Runtime shared library (Windows x64). One binary can embed +// only one platform's ORT lib (epic Open Concern #8); the official Microsoft +// release ships the DLL — see assets/manifest.json (windows-amd64) and +// Documentation/windows-build.md for the full Windows build procedure +// (the static tokenizer lib has no upstream prebuilt and is built from Rust +// source there). +// +//go:embed embedded/onnxruntime.dll +var embeddedORTLib embed.FS + +// ortLibFile is the base name of this platform's embedded ONNX Runtime shared +// library, both inside embedded/ and after extraction to the runtime dir. +const ortLibFile = "onnxruntime.dll" From b172323b705050f8c2d5172ec9ef4359d9d608d2 Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 15:22:06 -0400 Subject: [PATCH 2/8] fix(build): link Windows NT/Winsock/crypto syscall libs for source-built tokenizer The Windows libtokenizers.a (Rust std, GNU toolchain) references Nt*/Rtl*, Winsock and crypto syscalls that MinGW does not link by default, so the Windows `make build` failed with "undefined reference to NtCreateFile" etc. Makefile LINK_LIBS now appends -lntdll -lws2_32 -lbcrypt -luserenv -ladvapi32 -lkernel32 -lncrypt when GOOS=windows; empty on macOS/Linux (verified LINK_LIBS = -ltokenizers there), so those builds are unchanged. Observed and resolved during the first on-device Windows build; the integration test then linked and passed (cosine ordering 0.140 < 0.171 < 0.286, matching every other platform). Co-Authored-By: Claude Opus 4.8 (1M context) --- Documentation/windows-build.md | 9 ++++++--- Makefile | 13 +++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Documentation/windows-build.md b/Documentation/windows-build.md index c3fb492..1df3cca 100644 --- a/Documentation/windows-build.md +++ b/Documentation/windows-build.md @@ -77,9 +77,12 @@ cannot read zips). Checksums use `sha256sum` if present, else `shasum -a 256` ## Troubleshooting (observed / anticipated) -- **Missing Windows system symbols at link** (`ws2_32`, `bcrypt`, `userenv`, - `ntdll`): append `-lws2_32 -lbcrypt -luserenv -lntdll` to `CGO_LDFLAGS`. If the - build needs them, they go in the Makefile behind a Windows guard. +- **Missing Windows system symbols at link** (`undefined reference to Nt*` / + `Rtl*`, `ws2_32`, `bcrypt`, `userenv`): the Rust static lib pulls in NT/Winsock/ + crypto syscalls MinGW doesn't link by default. **Handled** — the Makefile's + `LINK_LIBS` appends `-lntdll -lws2_32 -lbcrypt -luserenv -ladvapi32 -lkernel32 + -lncrypt` when `GOOS=windows` (empty elsewhere). Observed and fixed during the + first Windows build; listed here in case a tokenizers/Rust bump adds more. - **`onnxruntime_providers_shared.dll` load error**: the official zip ships this second DLL; CPU-only use normally doesn't need it, but if ORT fails to load, pin it as an extra `embedded/` artifact beside the main DLL. diff --git a/Makefile b/Makefile index 97d6c5a..bed345e 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,17 @@ PLATFORM := $(shell go env GOOS)-$(shell go env GOARCH) # " ", so the awk '{print $1}' callers work with either. SHA256 := $(shell command -v sha256sum >/dev/null 2>&1 && echo sha256sum || echo shasum -a 256) +# Windows-only: the source-built libtokenizers.a (Rust std, GNU toolchain) pulls +# in low-level NT/Winsock/crypto syscalls that MinGW does not link by default. +# Naming them here resolves "undefined reference to Nt*/Rtl*" at link time. +# Empty on macOS/Linux, so those builds are unaffected. +LINK_LIBS := -ltokenizers +ifeq ($(shell go env GOOS),windows) +LINK_LIBS += -lntdll -lws2_32 -lbcrypt -luserenv -ladvapi32 -lkernel32 -lncrypt +endif + build: assets - CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) -ltokenizers" wails build -skipbindings -tags localembed + CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) $(LINK_LIBS)" wails build -skipbindings -tags localembed # Cross-build the Intel-mac app from an arm64 Mac. GOARCH=amd64 makes the # assets target fetch the darwin-amd64 artifacts (the embedded/ and lib/ dirs @@ -27,7 +36,7 @@ build-darwin-amd64: CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) -ltokenizers" wails build -skipbindings -tags localembed -platform darwin/amd64 dev: assets - CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) -ltokenizers" wails dev -tags localembed + CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) $(LINK_LIBS)" wails dev -tags localembed test: go test ./... From 37e1b0c058e87663b2c131d747afa81beb2c1485 Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 15:57:50 -0400 Subject: [PATCH 3/8] fix(build): stage sqlite3.h for Windows build (sqlite-vec cgo needs it) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sqlite-vec's cgo bindings #include sqlite3.h / sqlite3ext.h. macOS (SDK) and Linux (system libsqlite3) supply those; Windows has neither, so the full `make build` failed with "sqlite3.h: No such file or directory" (after the tokenizer link was resolved). New Windows-only `winhdr` prerequisite copies the headers mattn/go-sqlite3 already bundles (its sqlite3-binding.h IS the amalgamation sqlite3.h) into build/winhdr and points CGO_CFLAGS there — guaranteeing they match the SQLite mattn compiles in, no download or vendor. macOS/Linux unchanged: WIN_PREREQ + CGO_EXTRA_CFLAGS expand empty there (verified LINK_LIBS=-ltokenizers, no winhdr prereq, CGO_CFLAGS=""). Co-Authored-By: Claude Opus 4.8 (1M context) --- Makefile | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index bed345e..1dc8e30 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build build-darwin-amd64 dev test clean assets +.PHONY: build build-darwin-amd64 dev test clean assets winhdr # --- Local-embedding asset bundling ----------------------------------------- # Artifacts (model, tokenizer, ONNX Runtime dylib, static tokenizer lib) are @@ -20,12 +20,30 @@ SHA256 := $(shell command -v sha256sum >/dev/null 2>&1 && echo sha256sum || e # Naming them here resolves "undefined reference to Nt*/Rtl*" at link time. # Empty on macOS/Linux, so those builds are unaffected. LINK_LIBS := -ltokenizers +CGO_EXTRA_CFLAGS := +WIN_PREREQ := ifeq ($(shell go env GOOS),windows) LINK_LIBS += -lntdll -lws2_32 -lbcrypt -luserenv -ladvapi32 -lkernel32 -lncrypt +# sqlite-vec's cgo build #includes sqlite3.h / sqlite3ext.h, which macOS and +# Linux supply from the system but Windows does not. Stage the exact headers +# mattn/go-sqlite3 bundles (its sqlite3-binding.h IS the amalgamation sqlite3.h), +# so they match the SQLite that mattn compiles in — see the winhdr target. +CGO_EXTRA_CFLAGS := -I$(PWD)/build/winhdr +WIN_PREREQ := winhdr endif -build: assets - CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) $(LINK_LIBS)" wails build -skipbindings -tags localembed +# Stage sqlite headers for the Windows build from the mattn/go-sqlite3 module +# (Windows has no system sqlite3.h). No-op / unused on macOS and Linux. +winhdr: + @mkdir -p "$(PWD)/build/winhdr" + @d=$$(go list -m -f '{{.Dir}}' github.com/mattn/go-sqlite3); \ + d=$$(cygpath -u "$$d" 2>/dev/null || echo "$$d"); \ + cp "$$d/sqlite3-binding.h" "$(PWD)/build/winhdr/sqlite3.h"; \ + cp "$$d/sqlite3ext.h" "$(PWD)/build/winhdr/sqlite3ext.h"; \ + echo ">> staged Windows sqlite headers from $$d" + +build: assets $(WIN_PREREQ) + CGO_CFLAGS="$(CGO_EXTRA_CFLAGS)" CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) $(LINK_LIBS)" wails build -skipbindings -tags localembed # Cross-build the Intel-mac app from an arm64 Mac. GOARCH=amd64 makes the # assets target fetch the darwin-amd64 artifacts (the embedded/ and lib/ dirs @@ -35,8 +53,8 @@ build-darwin-amd64: GOARCH=amd64 $(MAKE) assets CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) -ltokenizers" wails build -skipbindings -tags localembed -platform darwin/amd64 -dev: assets - CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) $(LINK_LIBS)" wails dev -tags localembed +dev: assets $(WIN_PREREQ) + CGO_CFLAGS="$(CGO_EXTRA_CFLAGS)" CGO_LDFLAGS="-L$(PWD)/$(LIB_DIR) $(LINK_LIBS)" wails dev -tags localembed test: go test ./... From d3146700b9040286a621290cf76908b3244c17ba Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 16:31:30 -0400 Subject: [PATCH 4/8] docs(epic): record Phase 5 Windows findings; Phase 5 targets all verified Co-Authored-By: Claude Opus 4.8 (1M context) --- Documentation/Epics/local-embeddings.md | 35 ++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Documentation/Epics/local-embeddings.md b/Documentation/Epics/local-embeddings.md index 61bba43..cc5988a 100644 --- a/Documentation/Epics/local-embeddings.md +++ b/Documentation/Epics/local-embeddings.md @@ -1,7 +1,10 @@ # Epic: Local Embeddings as the Primary Provider **Date:** 2026-07-02 -**Status:** In Progress — Phase 5 started (foundation: per-platform go:embed split, branch `feat/xplat-foundation`); Phases 0–4 complete and in PR #2 (draft, awaiting review); Phase 6 (cleanup) remains +**Status:** In Progress — Phase 5 nearly complete: all four targets built & verified (macOS +arm64 shipped in PR #2; Linux, macOS x86_64, Windows x64 in stacked PRs #3/#4/#6/#7). Only the +linux-amd64 *runtime* smoke (artifacts pinned, needs an x64 Linux box) and Phase 6 (cleanup) +remain. PRs all draft, awaiting Bo's review. **Owner:** Bo Motlagh ## Goal @@ -486,6 +489,36 @@ and the indexing-progress UX all already exist and are the extension points. x86_64 Wails app builds, extracts its assets to its own arch dir, and answers an MCP search correctly with both arch dirs coexisting. Native arm64 re-verified after. +**Windows x64 findings (recorded 2026-07-17, branch `feat/xplat-windows`):** + +- **Built on-device over SSH** (Tailscale) to the Windows PC, driven from the dev Mac. + Toolchain installed via scoop: Go 1.26.5, MinGW gcc 16.1.0, rustup-gnu + cargo 1.97.1, + make. Recipe + provenance in `Documentation/windows-build.md`. +- **libtokenizers.a source-built** (no upstream Windows prebuilt): `daulet/tokenizers` v1.27.0 + tag, **GNU** Rust toolchain (must match MinGW gcc; MSVC would produce an unlinkable `.lib`). + The v1.27.0 layout emits `libtokenizers_ffi.a` — renamed to `libtokenizers.a` on packaging. + Published as repo release **`tokenizers-1.27.0-windows-x64`**, SHA-256 pinned. ONNX Runtime + DLL is the **official** Microsoft `onnxruntime-win-x64-1.26.0.zip` (member-pinned). +- **`assets_embed_windows.go`** embeds `onnxruntime.dll`; **Makefile** learned to extract + `.zip` archives (unzip → Windows `tar.exe` fallback) so `make assets` runs on Windows. +- **Two Windows-only build gaps found and fixed in the Makefile** (both invisible on + macOS/Linux, guarded by `GOOS=windows`): + 1. The Rust static lib needs NT/Winsock/crypto syscall libs MinGW doesn't link by default + (`undefined reference to Nt*/Rtl*`) → `LINK_LIBS` appends `-lntdll -lws2_32 -lbcrypt + -luserenv -ladvapi32 -lkernel32 -lncrypt`. + 2. sqlite-vec's cgo `#include "sqlite3.h"` has no system header on Windows (macOS SDK / + Linux libsqlite3 supplied it) → new `winhdr` step stages the headers mattn/go-sqlite3 + bundles (its `sqlite3-binding.h` IS the amalgamation `sqlite3.h`) into `build/winhdr`, + version-matched to the SQLite mattn compiles in. +- **Verified natively on Windows x64:** `make assets` downloads + checksum-verifies all four + artifacts (incl. `.zip` extraction and our published tokenizer release); integration test + links and passes (cosine ordering 0.140 < 0.171 < 0.286, matching every platform); full + `make build` produces `agent-memory.exe` (193 MB PE32+ GUI); the exe extracts its embedded + assets to `windows-amd64-/` and answers an MCP search on a Mac-indexed DB + ("how do I cook italian pasta" → carbonara-recipe.md) — cross-platform vector compatibility + confirmed. (Network not forcibly disabled — SSH session — but the local provider makes no + outbound calls by design; the `--network none` Linux/Intel runs already proved that property.) + 1. Linux x64/arm64: assets manifest entries, CI build, smoke test. 2. Windows x64: CI job builds `libtokenizers.a` with Rust toolchain (no published binary); ORT DLL from official release; smoke test. From f25b318eebe1fe28907f60c50138ea8e30e66811 Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 17:19:51 -0400 Subject: [PATCH 5/8] =?UTF-8?q?docs(epic):=20Phase=206=20checklist=20?= =?UTF-8?q?=E2=80=94=20record=20Phase=205=20verification=20gaps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Windows GUI smoke (headless SSH couldn't open a window), full untagged test suite on Windows (watcher TestOnCreate presumably fails pre-PR#5, unverified), and the linux-amd64 on-device runtime smoke. Coverage gaps, not known defects — recorded so they survive the session. Co-Authored-By: Claude Fable 5 --- Documentation/Epics/local-embeddings.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/Epics/local-embeddings.md b/Documentation/Epics/local-embeddings.md index cc5988a..d584339 100644 --- a/Documentation/Epics/local-embeddings.md +++ b/Documentation/Epics/local-embeddings.md @@ -535,7 +535,19 @@ and the indexing-progress UX all already exist and are the extension points. 2. Architecture rule check per `Documentation/ARCHITECTURE.md` (inward deps, wiring in main.go, mocks for all interfaces, thin delivery layer). 3. `go vet ./...`, `go test ./...`, `make build`, full manual test both modes. -4. Update this epic's Status to Complete; record the chosen default model and measured numbers. +4. **Verification gaps carried from Phase 5** (recorded 2026-07-17 — coverage gaps, not known + defects; each Phase 5 platform's core inference + search path IS verified): + - [ ] **Windows GUI smoke** (~5 min, human at the PC screen — headless SSH couldn't do it): + launch `agent-memory.exe`, keyless onboarding, index a folder, search from the UI. + All Windows verification so far was headless (MCP stdio path only). + - [ ] **Full untagged `go test ./...` on Windows** — only the tagged integration test has + run there. Do this AFTER the watcher fix (PR #5) merges: Windows file events likely + produce the same create+write double-event as Linux, so `TestOnCreate` presumably fails + on the unfixed watcher (unverified assumption — confirm). + - [ ] **linux-amd64 runtime smoke** (~10 min on any x64 Linux box, e.g. the Pop!_OS + machine): artifacts are pinned + checksum-verified, but the on-device run (build or + copy the exe, index, search) hasn't happened; Linux verification ran on arm64. +5. Update this epic's Status to Complete; record the chosen default model and measured numbers. ## Phase 3 — Detailed Plan (DRAFT, pending Bo review) From ecfd99398f736f67c914384b3cb65206e9b8b31c Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 18:02:16 -0400 Subject: [PATCH 6/8] =?UTF-8?q?docs(epic):=20Windows=20full-suite=20run=20?= =?UTF-8?q?done=20=E2=80=94=20watcher=20assumption=20confirmed,=20fix=20ve?= =?UTF-8?q?rified=203/3=20on=20Windows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- Documentation/Epics/local-embeddings.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/Epics/local-embeddings.md b/Documentation/Epics/local-embeddings.md index d584339..65dc955 100644 --- a/Documentation/Epics/local-embeddings.md +++ b/Documentation/Epics/local-embeddings.md @@ -540,10 +540,11 @@ and the indexing-progress UX all already exist and are the extension points. - [ ] **Windows GUI smoke** (~5 min, human at the PC screen — headless SSH couldn't do it): launch `agent-memory.exe`, keyless onboarding, index a folder, search from the UI. All Windows verification so far was headless (MCP stdio path only). - - [ ] **Full untagged `go test ./...` on Windows** — only the tagged integration test has - run there. Do this AFTER the watcher fix (PR #5) merges: Windows file events likely - produce the same create+write double-event as Linux, so `TestOnCreate` presumably fails - on the unfixed watcher (unverified assumption — confirm). + - [x] **Full untagged `go test ./...` on Windows** — DONE 2026-07-17: every package green + except `TestOnCreate`, which fails exactly as on Linux (assumption CONFIRMED — Windows + delivers the same create+write double-event). PR #5's fix branch verified on Windows: + watcher suite 3/3 pass. So the sole Windows failure is the known bug with a proven fix; + re-run once #5 merges into the stack for the final green checkmark. - [ ] **linux-amd64 runtime smoke** (~10 min on any x64 Linux box, e.g. the Pop!_OS machine): artifacts are pinned + checksum-verified, but the on-device run (build or copy the exe, index, search) hasn't happened; Linux verification ran on arm64. From 436a4ef4e77e744715d3deb8f86fce477491a83c Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 18:45:50 -0400 Subject: [PATCH 7/8] docs(epic): linux-amd64 runtime smoke done on real x64 hardware Co-Authored-By: Claude Fable 5 --- Documentation/Epics/local-embeddings.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/Epics/local-embeddings.md b/Documentation/Epics/local-embeddings.md index 65dc955..5f4b74f 100644 --- a/Documentation/Epics/local-embeddings.md +++ b/Documentation/Epics/local-embeddings.md @@ -545,9 +545,13 @@ and the indexing-progress UX all already exist and are the extension points. delivers the same create+write double-event). PR #5's fix branch verified on Windows: watcher suite 3/3 pass. So the sole Windows failure is the known bug with a proven fix; re-run once #5 merges into the stack for the final green checkmark. - - [ ] **linux-amd64 runtime smoke** (~10 min on any x64 Linux box, e.g. the Pop!_OS - machine): artifacts are pinned + checksum-verified, but the on-device run (build or - copy the exe, index, search) hasn't happened; Linux verification ran on arm64. + - [x] **linux-amd64 runtime smoke** — DONE 2026-07-17 on real x64 hardware (Surface Book + i7, Pop!_OS 22.04): binary built in an Ubuntu 22.04 amd64 container (glibc-matched; + `go build` with wails production tags — the full wails-CLI build path was already proven + on linux-arm64), integration test passed in-container (0.140 < 0.171 < 0.286), then the + binary ran natively on the Surface with **zero library installs** (`ldd` clean against + stock webkit2gtk-4.0/gtk-3), extracted assets to `linux-amd64-/`, and + answered the MCP search correctly against a macOS-indexed DB. 5. Update this epic's Status to Complete; record the chosen default model and measured numbers. ## Phase 3 — Detailed Plan (DRAFT, pending Bo review) From f6ab3731ac4239940df675246f49e7ae0e7c3f86 Mon Sep 17 00:00:00 2001 From: Nestor Canales Date: Fri, 17 Jul 2026 19:12:37 -0400 Subject: [PATCH 8/8] =?UTF-8?q?fix(app):=20per-OS=20Claude=20Desktop=20con?= =?UTF-8?q?fig=20path=20=E2=80=94=20Install=20button=20was=20mac-only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit defaultClaudeDesktopConfigPath hardcoded the macOS location (~/Library/Application Support/Claude/). On Windows the button therefore wrote a well-formed config to a path Claude Desktop never reads — and reported success. Found live during the Phase 5 Windows GUI smoke: the misplaced file existed at C:\Users\\Library\Application Support\... while Claude Desktop (reading %APPDATA%\Claude\) fell back to manual filesystem browsing instead of the MCP tool. Now per-OS: windows → %APPDATA%\Claude\; darwin → unchanged; linux → $XDG_CONFIG_HOME/Claude or ~/.config/Claude. Stdlib runtime aliased as goruntime (wails runtime already owns the name in app.go). Co-Authored-By: Claude Fable 5 --- app.go | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/app.go b/app.go index d8df838..9f94353 100644 --- a/app.go +++ b/app.go @@ -10,6 +10,7 @@ import ( "log" "os" "path/filepath" + goruntime "runtime" "strconv" "github.com/borzou/vecstore/internal/chunker" @@ -384,10 +385,28 @@ func generateToken() (string, error) { return hex.EncodeToString(b), nil } -// defaultClaudeDesktopConfigPath returns the standard Claude Desktop config location. +// defaultClaudeDesktopConfigPath returns the standard Claude Desktop config +// location for the current OS. Claude Desktop reads a different path per +// platform; writing the macOS path on Windows produces a config it never sees +// (while still reporting success — the Phase 5 Windows smoke caught exactly that). func defaultClaudeDesktopConfigPath() string { - home, _ := os.UserHomeDir() - return filepath.Join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") + switch goruntime.GOOS { + case "windows": + if appData := os.Getenv("APPDATA"); appData != "" { + return filepath.Join(appData, "Claude", "claude_desktop_config.json") + } + home, _ := os.UserHomeDir() + return filepath.Join(home, "AppData", "Roaming", "Claude", "claude_desktop_config.json") + case "darwin": + home, _ := os.UserHomeDir() + return filepath.Join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") + default: // linux + if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" { + return filepath.Join(xdg, "Claude", "claude_desktop_config.json") + } + home, _ := os.UserHomeDir() + return filepath.Join(home, ".config", "Claude", "claude_desktop_config.json") + } } // GetClaudeDesktopConfigPath returns the current config path (custom or default).