updates

ober

fb0db34a6fb012f46ba9849319d1c4d6d49b105c

diff --git a/.jerbuild b/.jerbuild
index 4090343..e0f4e65 100644
--- a/.jerbuild
+++ b/.jerbuild
@@ -3,38 +3,29 @@
 ;; jerbuild bundles Chez Scheme + the jerboa stdlib, so NO jerboa source
 ;; checkout or external Chez is required. The only external input is the native
 ;; Rust lib (libjerboa_native), built from vendor/jerboa-native-rs with the
-;; features jcode needs (tls + crypto). SQLite comes from jerboa-sqlite's C
-;; shim so the binary does not link duplicate jerboa_sqlite_* symbols.
-;;
-;; Static FFI needs NO source patching: jerboa-sqlite.sls falls through to (void)
-;; and tui-ffi.ss honors JERBOA_STATIC=1 (set by support/jcode-main.c), so the
-;; linked-in shim symbols resolve via the registered FFI symbols below.
+;; features jcode needs (tls + crypto). SQLite session storage comes from the
+;; pure Scheme jsqlite library in ../jsqlite/src.
 
 (entry  "main-binary.ss")
 (output "jcode")
 ;; do-binary-build auto-appends the bundled stdlib; list only project + vendor.
 (libdirs "lib"
-         "vendor/jerboa-sqlite/lib"
+         "../jsqlite/src"
          "vendor/jerboa-websearch/src")
 
-;; Symbols statically registered via Sforeign_symbol (sqlite shim, termbox TUI
-;; shim, jerboa-native tls+crypto). The custom main.c #includes + calls them.
+;; Symbols statically registered via Sforeign_symbol (termbox TUI shim and
+;; jerboa-native tls+crypto). The custom main.c #includes + calls them.
 (ffi-symbols "support/ffi-symbols.list")
 
 ;; Stock jerbuild main.c + setenv(JERBOA_STATIC=1); see the file's header.
 (main-c "support/jcode-main.c")
 
-;; C shims compiled into the binary. SQLite comes from the Cargo-built bundled
-;; archive below, with support/sqlite3.h providing the small C API surface used
-;; by the shim.
+;; C shims compiled into the binary.
 (extra-sources
-  ("vendor/jerboa-sqlite/jerboa_sqlite_shim.c" cflags: "-Isupport")
   ("src/jcode/ui/jcode_tui_shim.c" cflags: "-DTB_OPT_ATTR_W=32 -Ivendor/termbox2")
   ("support/debug-repl-socket-shim.c")
   ("support/landlock-shim.c"))
 
-(extra-archives "support/sqlite-bundled/target/release/libjcode_sqlite_bundled.a")
-
 ;; jerboa-native (Rust): tls + crypto only (no sqlite/duckdb/pcap/postgres). jerbuild
 ;; runs cargo and links the resulting libjerboa_native.a.
 (rust-crates
diff --git a/AGENTS.md b/AGENTS.md
index ca30460..0b26b44 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -433,6 +433,21 @@ Jerboa is niche — every non-trivial pattern you discover prevents future sessi
 
 **Recipe format**: `id` (kebab-case), `tags` (4-6 search keywords incl. module name), `imports` (all required), `code` (complete working example), `notes` (gotchas/alternatives).
 
+### Save anti-patterns (`~/mine/jerboa/data/anti-patterns.sexp`) whenever you:
+- See a plausible local-model strategy that failed verification
+- Find a weak verifier pattern that allowed false success
+- See a repeated repair loop, such as broad-reading after a concrete error
+- Find a generic runtime mistake, such as missing lower-bound checks before vector access
+
+**Before saving**: check `jerboa_anti_pattern_lookup` to avoid duplicates. If none exists, call `jerboa_anti_pattern_add`; only edit `data/anti-patterns.sexp` directly if the writer tool is unavailable.
+
+### Save error fixes (`jerboa_error_fix_add`) whenever you:
+- See exact compiler/runtime/verifier text with a repeatable repair
+- Hit an error that `jerboa_failure_advisor` should classify better next time
+- Debug a local-model generated-code failure where a short diagnosis prevents another failed iteration
+
+**Before saving**: check `jerboa_error_fix_lookup` with the exact error text.
+
 ### Suggest tooling improvements (`jerboa_suggest_feature`) whenever you:
 - Make multiple sequential tool calls that could be one tool
 - Fall back to bash because an MCP tool is missing or insufficient
@@ -440,7 +455,7 @@ Jerboa is niche — every non-trivial pattern you discover prevents future sessi
 **Before suggesting**: check `jerboa_list_features`; vote with `jerboa_vote_feature` if it already exists.
 
 ### Save Discoveries Mechanisms
-- **`/save-discoveries` skill**: invoke anytime to review session and save patterns + suggestions
+- **`/save-discoveries` skill**: invoke anytime to review session and save recipes, anti-patterns, error fixes, feature suggestions, and security patterns
 - **PreCompact hook**: add `PreCompact` hook with `type: "prompt"` in `.claude/settings.json` to auto-save before context compaction
 
 ---
diff --git a/Makefile b/Makefile
index ba809ef..10993fb 100644
--- a/Makefile
+++ b/Makefile
@@ -14,19 +14,18 @@ JERBUILD ?= $(shell if [ -x ./jerbuild ] && [ -x ./jerboa ]; then echo ./jerbuil
 # asking the jerbuild binary where it unpacked its bundle.
 JH = $(shell "$(JERBUILD)" --jerboa-home 2>/dev/null)
 
-LIBDIRS = --libdirs ./lib:vendor/jerboa-sqlite/lib:vendor/jerboa-websearch/src:$(JH)/lib
+JSQLITE_DIR ?= $(HOME)/mine/jsqlite
+JSQLITE_LIBDIR ?= $(JSQLITE_DIR)/src
+
+LIBDIRS = --libdirs ./lib:$(JSQLITE_LIBDIR):vendor/jerboa-websearch/src:$(JH)/lib
 JEXEC   = $(JERBUILD) exec $(LIBDIRS)
 
 # Library paths for FFI shared objects (macOS: dylib, Linux: so). The native
 # Rust lib now lives in ./lib (dropped by the native-rs target), matching the
 # (std crypto native-rust) loader's CWD-relative "lib/" fallback.
-SHIM_DIR       := $(CURDIR)/vendor/jerboa-sqlite
-SQLITE_STAGE   := vendor/jerboa-sqlite/.jcode-src
-SQLITE_BUNDLED_DIR := support/sqlite-bundled
-SQLITE_BUNDLED_A   := $(SQLITE_BUNDLED_DIR)/target/release/libjcode_sqlite_bundled.a
 TUI_SHIM_DIR   := $(CURDIR)/vendor/termbox2
 NATIVE_LIB_DIR := $(CURDIR)/lib
-LDPATH         := $(SHIM_DIR):$(TUI_SHIM_DIR):$(NATIVE_LIB_DIR)
+LDPATH         := $(TUI_SHIM_DIR):$(NATIVE_LIB_DIR)
 
 # Native Rust lib (vendored crate, built with cargo). Only the features jcode
 # uses — tls + crypto; no duckdb/pcap/postgres.
@@ -50,7 +49,7 @@ else
 JCODE_OS_LIBS := -lm -ldl -lpthread -luuid -lncurses -lstdc++
 endif
 
-.PHONY: all help ensure-jerboa-tools build gen run test test-providers local-eval clean repl binary install tui-shim run-tui native-rs sqlite-bundled linux linux-check linux-amd64 linux-arm64 jcode-linux-amd64 jcode-linux-arm64 test-linux test-linux-amd64 freebsd freebsd-amd64 jcode-freebsd-amd64 purge-stale sqlite-shim sqlite-lib android android-clean vendor-deps vendor-clean
+.PHONY: all help ensure-jerboa-tools build gen run test test-providers local-eval clean repl binary install tui-shim run-tui native-rs linux linux-check linux-amd64 linux-arm64 jcode-linux-amd64 jcode-linux-arm64 test-linux test-linux-amd64 freebsd freebsd-amd64 jcode-freebsd-amd64 purge-stale android android-clean vendor-deps vendor-clean
 
 all: help
 
@@ -64,9 +63,8 @@ help:
 	@echo "  run          Start interactive agent REPL"
 	@echo "  run-tui      Start TUI mode"
 	@echo "  repl         Open a bare Scheme REPL with project libdirs"
-	@echo "  gen          Transpile src/ → lib/ + rebuild sqlite shim (jerbuild)"
+	@echo "  gen          Transpile src/ → lib/ (jerbuild)"
 	@echo "  native-rs    Build vendored libjerboa_native (cargo, tls+crypto)"
-	@echo "  sqlite-bundled Build bundled SQLite archive via cargo"
 	@echo "  binary       Build native binary via 'jerbuild build' (.jerbuild)"
 	@echo "  install      Install binary to ~/.local/bin"
 	@echo "  binary       Build jcode for THIS host's os/arch (jerbuild, native)"
@@ -77,8 +75,6 @@ help:
 	@echo "  linux-check  Fast drift check of the cross-build (no link, ~10s)"
 	@echo "  clean        Remove compiled artifacts and binaries"
 	@echo "  purge-stale  Remove stale .so/.wpo files"
-	@echo "  sqlite-shim  Rebuild jerboa_sqlite_shim.so"
-	@echo "  sqlite-lib   Transpile vendor/jerboa-sqlite src/ → lib/"
 	@echo "  tui-shim     Rebuild jcode_tui_shim"
 	@echo "  android      Build Android APK in Termux (android/build/*.apk)"
 	@echo "  android-clean  Remove android/build/"
@@ -108,9 +104,6 @@ ensure-jerboa-tools:
 # source no longer exists). This makes "make build" idempotent and immune
 # to the class of bug where a stale .so silently linked against an old
 # shim causes a runtime "no entry for X" foreign-procedure error.
-#
-# Always also clear the prebuilt vendor/jerboa-sqlite artifacts — they pin
-# absolute paths to the shim and are cheap to recompile.
 purge-stale:
 	@find lib -name "*.so" -o -name "*.wpo" 2>/dev/null | while read f; do \
 	  src=$$(echo $$f | sed -e 's|^lib/|src/|' -e 's|\.so$$|.ss|' -e 's|\.wpo$$|.ss|'); \
@@ -129,39 +122,6 @@ purge-stale:
 	    break; \
 	  fi; \
 	done
-	@rm -f vendor/jerboa-sqlite/lib/jerboa-sqlite.so vendor/jerboa-sqlite/lib/jerboa-sqlite.wpo
-
-# ── jerboa-sqlite shim build ──────────────────────────────────────────────────
-# Rebuild the FFI shim if its C source is newer than the .so. This catches
-# the case where vendor/jerboa-sqlite is updated but the .so isn't refreshed.
-sqlite-bundled:
-	@command -v cargo >/dev/null 2>&1 || { \
-	  echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; exit 1; }
-	@if [ ! -f "$(SQLITE_BUNDLED_A)" ] || \
-	    [ "$(SQLITE_BUNDLED_DIR)/Cargo.toml" -nt "$(SQLITE_BUNDLED_A)" ] || \
-	    [ -n "$$(find $(SQLITE_BUNDLED_DIR)/src -name '*.rs' -newer $(SQLITE_BUNDLED_A) 2>/dev/null)" ]; then \
-	  echo "=== Building bundled SQLite archive ==="; \
-	  ( cd $(SQLITE_BUNDLED_DIR) && cargo build --release ); \
-	fi
-
-sqlite-shim: vendor/jerboa-sqlite sqlite-bundled
-	@if [ ! -f vendor/jerboa-sqlite/jerboa_sqlite_shim.so ] || \
-	    [ vendor/jerboa-sqlite/jerboa_sqlite_shim.c -nt vendor/jerboa-sqlite/jerboa_sqlite_shim.so ] || \
-	    [ support/sqlite3.h -nt vendor/jerboa-sqlite/jerboa_sqlite_shim.so ] || \
-	    [ "$(SQLITE_BUNDLED_A)" -nt vendor/jerboa-sqlite/jerboa_sqlite_shim.so ]; then \
-	  echo "=== Rebuilding jerboa_sqlite_shim.so ==="; \
-	  cc -shared -fPIC -O2 \
-	    -Isupport \
-	    -o vendor/jerboa-sqlite/jerboa_sqlite_shim.so \
-	    vendor/jerboa-sqlite/jerboa_sqlite_shim.c $(SQLITE_BUNDLED_A); \
-	fi
-
-sqlite-lib: ensure-jerboa-tools vendor/jerboa-sqlite
-	@rm -rf $(SQLITE_STAGE)
-	@mkdir -p $(SQLITE_STAGE)
-	@sed '/^(import (jerboa prelude))$$/d' \
-	  vendor/jerboa-sqlite/src/jerboa-sqlite.ss > $(SQLITE_STAGE)/jerboa-sqlite.ss
-	$(JERBUILD) transpile $(SQLITE_STAGE) vendor/jerboa-sqlite/lib --force
 
 # ── libjerboa_native (Rust FFI) ─────────────────────────────────────────────
 # secrets.ss + std/net/request + std/regex etc. all bind FFI symbols from
@@ -201,13 +161,7 @@ native-rs: $(NATIVE_DIR)
 # we do NOT use git submodules — every target that needs vendor/<x> depends on
 # vendor-deps so a fresh checkout populates itself.
 
-vendor-deps: vendor/jerboa-sqlite vendor/termbox2 vendor/jerboa-websearch
-
-vendor/jerboa-sqlite:
-	@mkdir -p vendor
-	@echo "=== Cloning jerboa-sqlite into vendor/ ==="
-	@git clone --depth 1 https://git.sr.ht/~lisp/jerboa-sqlite vendor/jerboa-sqlite
-	@rm -f vendor/jerboa-sqlite/jerboa_sqlite_shim.so
+vendor-deps: vendor/termbox2 vendor/jerboa-websearch
 
 vendor/termbox2:
 	@mkdir -p vendor
@@ -242,7 +196,7 @@ $(REPL_TOKEN_FILE):
 	@head -c 16 /dev/urandom | od -An -tx1 | tr -d ' \n' > $@
 	@echo "Generated debug-REPL auth token in $(REPL_TOKEN_FILE)"
 
-gen: ensure-jerboa-tools vendor-deps purge-stale sqlite-shim sqlite-lib $(REPL_TOKEN_FILE)
+gen: ensure-jerboa-tools vendor-deps purge-stale $(REPL_TOKEN_FILE)
 	JCODE_REPL_TOKEN=$$(cat $(REPL_TOKEN_FILE)) $(JERBUILD) transpile src lib
 
 build: ensure-jerboa-tools gen native-rs
@@ -321,7 +275,7 @@ install: binary
 JERBOA_HOME      ?= $(HOME)/mine/jerboa
 SCHEME           ?= $(JERBOA_HOME)/.chez/bin/scheme
 FREEBSD_AMD64_CC ?= $(JERBOA_HOME)/support/cross-cc-freebsd-amd64
-XC_LIBDIRS        = ./lib:vendor/jerboa-sqlite/lib:vendor/jerboa-websearch/src:$(JH)/lib:$(JERBOA_HOME)/lib
+XC_LIBDIRS        = ./lib:$(JSQLITE_LIBDIR):vendor/jerboa-websearch/src:$(JH)/lib:$(JERBOA_HOME)/lib
 
 # `make linux` defaults to the linux amd64 cross-build.
 linux: linux-amd64
diff --git a/build-jcode-cross.ss b/build-jcode-cross.ss
index 315e2f3..33bdd4d 100644
--- a/build-jcode-cross.ss
+++ b/build-jcode-cross.ss
@@ -56,11 +56,8 @@
 ;; jcode uses only this subset of jerboa-native-rs features:
 ;;   tls    — provider/provider.ss (rustls)
 ;;   crypto — secrets.ss, hashing, hmac, aead, scrypt, argon2id
-;;
-;; SQLite is linked through vendor/jerboa-sqlite/jerboa_sqlite_shim.c plus
-;; support/sqlite-bundled. The Rust crate's sqlite feature exports a different
-;; jerboa_sqlite_* surface, so enabling it here creates duplicate symbols and
-;; still does not provide the int64/bytes/constants API the Scheme module uses.
+;; Session storage uses pure Scheme jsqlite from the libdirs; no sqlite C shim
+;; or jerboa-native sqlite feature is linked here.
 (define cargo-features "tls,crypto")
 
 (define jerboa-native-a
@@ -68,10 +65,6 @@
       (format "~a/jerboa-native-rs/target/~a/release/libjerboa_native.a"
               jerboa-home rust-target)))
 
-(define sqlite-bundled-a
-  (format "support/sqlite-bundled/target/~a/release/libjcode_sqlite_bundled.a"
-          rust-target))
-
 (define cross-csv-dir
   (let ([lib (format "~a/lib" cross-prefix)])
     (unless (file-directory? lib)
@@ -102,8 +95,7 @@
 (printf "    xpatch:        ~a~n" xpatch)
 (printf "    cross-cc:      ~a~n" cross-cc)
 (printf "    output:        ~a~n" output)
-(printf "    features:      ~a~n" cargo-features)
-(printf "    sqlite archive: ~a~n~n" sqlite-bundled-a)
+(printf "    features:      ~a~n~n" cargo-features)
 
 ;; ── Step 0: Build/rebuild jerboa-native-rs for x86_64-linux-musl ───────────
 ;; libjerboa_native.a is shared across jerboa-shell, jerboa-code, etc. If a
@@ -169,30 +161,6 @@
   (printf "  $ ~a~n" cmd)
   (zero? (system cmd)))
 
-(define (build-sqlite-bundled!)
-  (require-file "support/sqlite-bundled/Cargo.toml")
-  (let* ([sqlite-dir "support/sqlite-bundled"]
-         [cargo-args (format "build --release --target ~a" rust-target)]
-         [cc-env (format "CARGO_TARGET_~a_LINKER='~a' CC_~a='~a' AR_~a='~a' "
-                         rust-target-env-upper cross-cc
-                         rust-target-env-lower cross-cc
-                         rust-target-env-lower cross-ar)]
-         [via-rustup
-          (and rustup-bin-dir
-               (format "cd '~a' && env ~aPATH='~a':$PATH RUSTC='~a/rustc' '~a/cargo' ~a"
-                       sqlite-dir cc-env rustup-bin-dir rustup-bin-dir rustup-bin-dir cargo-args))]
-         [via-path (format "cd '~a' && env ~acargo ~a" sqlite-dir cc-env cargo-args)]
-         [ok? (or (and via-rustup (try-cargo-build via-rustup))
-                  (try-cargo-build via-path))])
-    (unless ok?
-      (error 'build-jcode-cross
-        (format "failed to build bundled SQLite for ~a with ~a"
-                rust-target cross-cc)))
-    (unless (file-exists? sqlite-bundled-a)
-      (error 'build-jcode-cross
-             "cargo succeeded but bundled SQLite archive is missing"
-             sqlite-bundled-a))))
-
 (define (rebuild-native-lib!)
   (let* ([nrs-dir (format "~a/jerboa-native-rs" jerboa-home)]
          [cargo-args (format "build --release --no-default-features --features ~a --target ~a"
@@ -230,8 +198,7 @@
            (file-modification-time native-features-sentinel))
    ;; The .a is shared across sibling repos (jerboa-shell, etc.). A newer .a
    ;; than our sentinel means someone rebuilt it — possibly with different
-   ;; features — so our tag can't be trusted. Rebuild to be sure (prevents
-   ;; the silent "undefined reference to jerboa_sqlite_*" cross-link break).
+   ;; features — so our tag can't be trusted. Rebuild to be sure.
    (printf "==> jerboa-native-rs .a newer than sentinel (foreign rebuild?) — rebuilding (features=~a)~n" cargo-features)
    (rebuild-native-lib!)]
   [(rs-source-newer-than? jerboa-native-a)
@@ -240,11 +207,6 @@
   [else
    (printf "==> jerboa-native-rs up to date (features=~a)~n" cargo-features)])
 
-(printf "==> building bundled SQLite archive (~a)~n" rust-target)
-(build-sqlite-bundled!)
-
-(printf "~n")
-
 ;; ── Step 0.5: isolate cross-compiled objects ───────────────────────────────
 ;; Never patch source libraries in-place.  Chez xpatch can compile target
 ;; objects while `library-directories` maps source directories to a separate
@@ -319,20 +281,7 @@
 ;; Chez's load-shared-object error path strlen()s it.
 
 (define ffi-shim-symbols
-  '(;; jerboa-sqlite shim (vendor/jerboa-sqlite/jerboa_sqlite_shim.c)
-    "jerboa_sqlite_open" "jerboa_sqlite_close" "jerboa_sqlite_exec"
-    "jerboa_sqlite_prepare" "jerboa_sqlite_finalize" "jerboa_sqlite_reset"
-    "jerboa_sqlite_clear_bindings" "jerboa_sqlite_step"
-    "jerboa_sqlite_column_count" "jerboa_sqlite_column_name"
-    "jerboa_sqlite_column_type" "jerboa_sqlite_column_int64"
-    "jerboa_sqlite_column_double" "jerboa_sqlite_column_text"
-    "jerboa_sqlite_column_bytes" "jerboa_sqlite_column_blob"
-    "jerboa_sqlite_bind_int64" "jerboa_sqlite_bind_double"
-    "jerboa_sqlite_bind_text" "jerboa_sqlite_bind_blob"
-    "jerboa_sqlite_bind_null" "jerboa_sqlite_last_insert_rowid"
-    "jerboa_sqlite_changes" "jerboa_sqlite_errmsg"
-    "jerboa_SQLITE_ROW" "jerboa_SQLITE_DONE" "jerboa_SQLITE_OK"
-    ;; termbox2 TUI shim (src/jcode/ui/jcode_tui_shim.c)
+  '(;; termbox2 TUI shim (src/jcode/ui/jcode_tui_shim.c)
     "jcode_tb_init" "jcode_tb_shutdown"
     "jcode_tb_width" "jcode_tb_height"
     "jcode_tb_clear" "jcode_tb_present"
@@ -394,9 +343,10 @@
     "getuid" "geteuid" "getgid" "getegid"
     "sigemptyset" "sigfillset" "sigaddset" "sigdelset"
     "sigismember" "sigprocmask"
-    ;; terminal/fd — TUI + REPL
+    ;; terminal/fd — TUI + REPL + jsqlite locking/WAL shm
     "isatty" "tcgetattr" "tcsetattr" "tcgetpgrp" "tcsetpgrp"
     "pipe" "dup" "dup2" "lseek"
+    "open" "ftruncate" "mmap" "munmap" "flock" "usleep"
     ;; env/misc — std/os/env, std/text/time
     "setenv" "unsetenv" "strerror" "localtime" "strftime"
     "sysconf" "getpagesize" "getrlimit"
@@ -421,6 +371,7 @@
   (display "#include <sys/wait.h>\n" out)
   (display "#include <sys/resource.h>\n" out)
   (display "#include <sys/prctl.h>\n" out)
+  (display "#include <sys/file.h>\n" out)
   (display "#include <sys/socket.h>\n" out)
   (display "#include <netinet/in.h>\n" out)
   (display "#include <arpa/inet.h>\n" out)
@@ -454,7 +405,7 @@
   (display "static char dlerror_msg[] = \"static binary: dlopen of named libraries is stubbed\";\n" out)
   (display "char *dlerror(void)                     { return dlerror_msg; }\n\n" out)
   ;; extern decls for shim functions linked via .c files
-  (display "/* Shim function decls — jerboa_sqlite_shim.c + jcode_tui_shim.c + landlock-shim.c */\n" out)
+  (display "/* Shim function decls — jcode_tui_shim.c + landlock-shim.c */\n" out)
   (for-each (lambda (n) (fprintf out "extern void ~a();\n" n)) ffi-shim-symbols)
   ;; extern decls for libjerboa_native.a symbols
   (display "\n/* libjerboa_native.a — features=tls,crypto */\n" out)
@@ -521,20 +472,14 @@
 ;; ── Stage 6: compile + link with cross-cc ──────────────────────────────────
 (printf "==> [6/6] compile + link with ~a~n" cross-cc)
 
-(define sqlite-shim-c    "vendor/jerboa-sqlite/jerboa_sqlite_shim.c")
 (define jcode-tui-shim-c "src/jcode/ui/jcode_tui_shim.c")
 (define landlock-shim-c  "support/landlock-shim.c")
-(define sqlite-include-dir "support")
 
-(require-file sqlite-shim-c)
 (require-file jcode-tui-shim-c)
 (require-file landlock-shim-c)
 (require-file jerboa-native-a)
-(require-file sqlite-bundled-a)
-(require-file "support/sqlite3.h")
 
-(printf "    sqlite3.h:  support/sqlite3.h~n")
-(printf "    tls/crypto via libjerboa_native.a; sqlite via jerboa_sqlite_shim.c + bundled SQLite~n")
+(printf "    tls/crypto via libjerboa_native.a; sessions via jsqlite Scheme sources~n")
 
 ;; -Wl,--export-dynamic exports symbols into the dynamic symbol table so
 ;; Chez's foreign-procedure / dlsym(RTLD_DEFAULT) can find them in a
@@ -544,20 +489,18 @@
    (string-append
     "~a -O2 -static -Wl,--export-dynamic "
     "-I~a "                                                ;; scheme.h
-    "-I~a "                                                ;; sqlite3.h
     "-Ivendor/termbox2 -DTB_OPT_ATTR_W=32 "                ;; jcode_tui_shim
     "-o ~a "                                               ;; output
-    "~a ~a ~a ~a "                                         ;; main.c + 3 shims
+    "~a ~a ~a "                                            ;; main.c + 2 shims
     "~a/libkernel.a ~a/libz.a ~a/liblz4.a "                ;; chez kernel
     "~a "                                                  ;; libjerboa_native.a
-    "~a "                                                  ;; bundled sqlite3
     "-Wl,--allow-multiple-definition "
     "-Wl,--defsym=_dl_find_object=0 "
     "-lm -ldl -lpthread")
-   cross-cc cross-csv-dir sqlite-include-dir output
-   main-c-path sqlite-shim-c jcode-tui-shim-c landlock-shim-c
+   cross-cc cross-csv-dir output
+   main-c-path jcode-tui-shim-c landlock-shim-c
    cross-csv-dir cross-csv-dir cross-csv-dir
-   jerboa-native-a sqlite-bundled-a))
+   jerboa-native-a))
 (printf "    ~a~n" link-cmd)
 (let ([rc (system link-cmd)])
   (unless (zero? rc)
diff --git a/build-jcode-freebsd-cross.ss b/build-jcode-freebsd-cross.ss
index 387255c..bb02a51 100644
--- a/build-jcode-freebsd-cross.ss
+++ b/build-jcode-freebsd-cross.ss
@@ -35,11 +35,8 @@
 ;; jcode uses only this subset of jerboa-native-rs features:
 ;;   tls    — provider/provider.ss (rustls)
 ;;   crypto — secrets.ss, hashing, hmac, aead, scrypt, argon2id
-;;
-;; SQLite is linked through vendor/jerboa-sqlite/jerboa_sqlite_shim.c plus
-;; support/sqlite-bundled. The Rust crate's sqlite feature exports a different
-;; jerboa_sqlite_* surface, so enabling it here creates duplicate symbols and
-;; still does not provide the int64/bytes/constants API the Scheme module uses.
+;; Session storage uses pure Scheme jsqlite from the libdirs; no sqlite C shim
+;; or jerboa-native sqlite feature is linked here.
 (define cargo-features "tls,crypto")
 
 (define jerboa-native-a
@@ -47,9 +44,6 @@
       (format "~a/jerboa-native-rs/target/x86_64-unknown-freebsd/release/libjerboa_native.a"
               jerboa-home)))
 
-(define sqlite-bundled-a
-  "support/sqlite-bundled/target/x86_64-unknown-freebsd/release/libjcode_sqlite_bundled.a")
-
 (define cross-csv-dir
   (let ([lib (format "~a/lib" cross-prefix)])
     (unless (file-directory? lib)
@@ -80,8 +74,7 @@
 (printf "    xpatch:        ~a~n" xpatch)
 (printf "    cross-cc:      ~a~n" cross-cc)
 (printf "    output:        ~a~n" output)
-(printf "    features:      ~a~n" cargo-features)
-(printf "    sqlite archive: ~a~n~n" sqlite-bundled-a)
+(printf "    features:      ~a~n~n" cargo-features)
 
 ;; ── Step 0: Build/rebuild jerboa-native-rs for x86_64-unknown-freebsd ──────
 ;; libjerboa_native.a is shared across jerboa-shell, jerboa-code, etc. If a
@@ -152,26 +145,6 @@
    "CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_LINKER='~a' CC_x86_64_unknown_freebsd='~a' AR_x86_64_unknown_freebsd=/opt/homebrew/opt/llvm/bin/llvm-ar "
    cross-cc cross-cc))
 
-(define (build-sqlite-bundled!)
-  (require-file "support/sqlite-bundled/Cargo.toml")
-  (let* ([sqlite-dir "support/sqlite-bundled"]
-         [cargo-args "build --release --target x86_64-unknown-freebsd"]
-         [via-rustup
-          (and rustup-bin-dir
-               (format "cd '~a' && env ~aPATH='~a':$PATH RUSTC='~a/rustc' '~a/cargo' ~a"
-                       sqlite-dir freebsd-cc-env rustup-bin-dir rustup-bin-dir rustup-bin-dir cargo-args))]
-         [via-path (format "cd '~a' && env ~acargo ~a" sqlite-dir freebsd-cc-env cargo-args)]
-         [ok? (or (and via-rustup (try-cargo-build via-rustup))
-                  (try-cargo-build via-path))])
-    (unless ok?
-      (error 'build-jcode-freebsd-cross
-        (string-append "failed to build bundled SQLite for x86_64-unknown-freebsd with "
-                       cross-cc)))
-    (unless (file-exists? sqlite-bundled-a)
-      (error 'build-jcode-freebsd-cross
-             "cargo succeeded but bundled SQLite archive is missing"
-             sqlite-bundled-a))))
-
 (define (rebuild-native-lib!)
   (let* ([nrs-dir (format "~a/jerboa-native-rs" jerboa-home)]
          [cargo-args (format "build --release --no-default-features --features ~a --target x86_64-unknown-freebsd"
@@ -209,11 +182,6 @@
   [else
    (printf "==> jerboa-native-rs up to date (features=~a)~n" cargo-features)])
 
-(printf "==> building bundled SQLite archive (x86_64-unknown-freebsd)~n")
-(build-sqlite-bundled!)
-
-(printf "~n")
-
 ;; ── Step 0.5: isolate cross-compiled objects ───────────────────────────────
 ;; Never patch source libraries in-place.  Chez xpatch can compile target
 ;; objects while `library-directories` maps source directories to a separate
@@ -288,20 +256,7 @@
 ;; Chez's load-shared-object error path strlen()s it.
 
 (define ffi-shim-symbols
-  '(;; jerboa-sqlite shim (vendor/jerboa-sqlite/jerboa_sqlite_shim.c)
-    "jerboa_sqlite_open" "jerboa_sqlite_close" "jerboa_sqlite_exec"
-    "jerboa_sqlite_prepare" "jerboa_sqlite_finalize" "jerboa_sqlite_reset"
-    "jerboa_sqlite_clear_bindings" "jerboa_sqlite_step"
-    "jerboa_sqlite_column_count" "jerboa_sqlite_column_name"
-    "jerboa_sqlite_column_type" "jerboa_sqlite_column_int64"
-    "jerboa_sqlite_column_double" "jerboa_sqlite_column_text"
-    "jerboa_sqlite_column_bytes" "jerboa_sqlite_column_blob"
-    "jerboa_sqlite_bind_int64" "jerboa_sqlite_bind_double"
-    "jerboa_sqlite_bind_text" "jerboa_sqlite_bind_blob"
-    "jerboa_sqlite_bind_null" "jerboa_sqlite_last_insert_rowid"
-    "jerboa_sqlite_changes" "jerboa_sqlite_errmsg"
-    "jerboa_SQLITE_ROW" "jerboa_SQLITE_DONE" "jerboa_SQLITE_OK"
-    ;; termbox2 TUI shim (src/jcode/ui/jcode_tui_shim.c)
+  '(;; termbox2 TUI shim (src/jcode/ui/jcode_tui_shim.c)
     "jcode_tb_init" "jcode_tb_shutdown"
     "jcode_tb_width" "jcode_tb_height"
     "jcode_tb_clear" "jcode_tb_present"
@@ -377,9 +332,10 @@
     "getuid" "geteuid" "getgid" "getegid"
     "sigemptyset" "sigfillset" "sigaddset" "sigdelset"
     "sigismember" "sigprocmask"
-    ;; terminal/fd — TUI + REPL
+    ;; terminal/fd — TUI + REPL + jsqlite locking/WAL shm
     "isatty" "tcgetattr" "tcsetattr" "tcgetpgrp" "tcsetpgrp"
     "pipe" "dup" "dup2" "lseek"
+    "open" "ftruncate" "mmap" "munmap" "flock" "usleep"
     ;; env/misc — std/os/env, std/text/time
     "setenv" "unsetenv" "strerror" "localtime" "strftime"
     "sysconf" "getpagesize" "getrlimit"
@@ -398,6 +354,8 @@
   (display "#include <sys/stat.h>\n" out)
   (display "#include <sys/wait.h>\n" out)
   (display "#include <sys/resource.h>\n" out)
+  (display "#include <sys/mman.h>\n" out)
+  (display "#include <sys/file.h>\n" out)
   (display "#include <sys/socket.h>\n" out)
   (display "#include <netinet/in.h>\n" out)
   (display "#include <arpa/inet.h>\n" out)
@@ -425,7 +383,7 @@
               (fprintf out "static int ~a() { return -1; }\n" n))
             freebsd-stub-symbols)
   ;; extern decls for shim functions linked via .c files
-  (display "\n/* Shim function decls — jerboa_sqlite_shim.c + jcode_tui_shim.c */\n" out)
+  (display "\n/* Shim function decls — jcode_tui_shim.c */\n" out)
   (for-each (lambda (n) (fprintf out "extern void ~a();\n" n)) ffi-shim-symbols)
   ;; extern decls for libjerboa_native.a symbols
   (display "\n/* libjerboa_native.a — features=tls,crypto */\n" out)
@@ -494,20 +452,14 @@
 ;; ── Stage 6: compile + link with cross-cc ──────────────────────────────────
 (printf "==> [6/6] compile + link with ~a~n" cross-cc)
 
-(define sqlite-shim-c    "vendor/jerboa-sqlite/jerboa_sqlite_shim.c")
 (define jcode-tui-shim-c "src/jcode/ui/jcode_tui_shim.c")
-(define sqlite-include-dir "support")
 ;; landlock-shim is Linux-only (sys/prctl.h, __NR_landlock_create_ruleset);
 ;; on FreeBSD jerboa_landlock_sandbox is provided by a static stub above.
 
-(require-file sqlite-shim-c)
 (require-file jcode-tui-shim-c)
 (require-file jerboa-native-a)
-(require-file sqlite-bundled-a)
-(require-file "support/sqlite3.h")
 
-(printf "    sqlite3.h:  support/sqlite3.h~n")
-(printf "    tls/crypto via libjerboa_native.a; sqlite via jerboa_sqlite_shim.c + bundled SQLite~n")
+(printf "    tls/crypto via libjerboa_native.a; sessions via jsqlite Scheme sources~n")
 
 ;; FreeBSD link differences from Linux musl:
 ;;   - Dynamic, not static (FreeBSD libc symbol versioning blocks libc.a)
@@ -521,18 +473,16 @@
    (string-append
     "~a -O2 -Wl,--export-dynamic "
     "-I~a "                                                ;; scheme.h
-    "-I~a "                                                ;; sqlite3.h
     "-Ivendor/termbox2 -DTB_OPT_ATTR_W=32 "                ;; jcode_tui_shim
     "-o ~a "                                               ;; output
-    "~a ~a ~a "                                            ;; main.c + 2 shims
+    "~a ~a "                                               ;; main.c + TUI shim
     "~a/libkernel.a ~a/libz.a ~a/liblz4.a "                ;; chez kernel
     "~a "                                                  ;; libjerboa_native.a
-    "~a "                                                  ;; bundled sqlite3
     "-lm -lpthread -lutil")
-   cross-cc cross-csv-dir sqlite-include-dir output
-   main-c-path sqlite-shim-c jcode-tui-shim-c
+   cross-cc cross-csv-dir output
+   main-c-path jcode-tui-shim-c
    cross-csv-dir cross-csv-dir cross-csv-dir
-   jerboa-native-a sqlite-bundled-a))
+   jerboa-native-a))
 (printf "    ~a~n" link-cmd)
 (let ([rc (system link-cmd)])
   (unless (zero? rc)
diff --git a/build-jcode-musl.sh b/build-jcode-musl.sh
index f5d25a7..25d60ed 100755
--- a/build-jcode-musl.sh
+++ b/build-jcode-musl.sh
@@ -17,6 +17,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
 HOME_DIR="${HOME:-/root}"
 JERBOA_HOME="${JERBOA_HOME:-${HOME_DIR}/mine/jerboa}"
 JERBOA_LIB="${JERBOA_HOME}/lib"
+JSQLITE_DIR="${JSQLITE_DIR:-${HOME_DIR}/mine/jsqlite}"
+JSQLITE_LIBDIR="${JSQLITE_LIBDIR:-${JSQLITE_DIR}/src}"
 SCHEME="${SCHEME:-${JERBOA_HOME}/.chez/bin/scheme}"
 
 if [ ! -x "${SCHEME}" ]; then
@@ -30,6 +32,7 @@ echo "Building jcode with musl libc (static)"
 echo "==================================="
 echo ""
 echo "Jerboa: $JERBOA_LIB"
+echo "jsqlite: $JSQLITE_LIBDIR"
 echo ""
 
 # Check musl availability
@@ -85,10 +88,10 @@ VALIDATE
 echo ""
 echo "[2/2] Running musl build..."
 
-LD_LIBRARY_PATH="${SCRIPT_DIR}/vendor/jerboa-sqlite:${SCRIPT_DIR}/vendor/termbox2:${JERBOA_LIB}:." \
+LD_LIBRARY_PATH="${SCRIPT_DIR}/vendor/termbox2:${JERBOA_LIB}:." \
 JERBOA_HOME="${JERBOA_HOME}" \
 JERBOA_MUSL_CHEZ_PREFIX="${MUSL_CHEZ_PREFIX}" \
-"${SCHEME}" -q --libdirs "${JERBOA_LIB}:./lib:vendor/jerboa-sqlite/src:vendor/jerboa-websearch/src" \
+"${SCHEME}" -q --libdirs "${JERBOA_LIB}:./lib:${JSQLITE_LIBDIR}:vendor/jerboa-websearch/src" \
     <build-jcode-musl.ss
 
 # Verify
diff --git a/build-jcode-musl.ss b/build-jcode-musl.ss
index 9caa951..a7ae641 100644
--- a/build-jcode-musl.ss
+++ b/build-jcode-musl.ss
@@ -1,7 +1,7 @@
 #!chezscheme
 ;;; build-jcode-musl.ss — Build a fully static jcode binary using musl libc
 ;;;
-;;; Usage: scheme -q --libdirs <jerboa-lib>:./lib:vendor/jerboa-sqlite/src < build-jcode-musl.ss
+;;; Usage: scheme -q --libdirs <jerboa-lib>:./lib:$HOME/mine/jsqlite/src:vendor/jerboa-websearch/src < build-jcode-musl.ss
 ;;;
 ;;; This script:
 ;;;   1. Compiles jcode modules (using stock scheme with glibc)
@@ -194,9 +194,8 @@
 
 ;; libc symbols needed by std/net/* and std/os/* (already linked from musl).
 ;; All are real libc functions, not macros — straight (void*)foo casts work.
-;; Variadic/macro ones (open/fcntl/ioctl/umask) are intentionally omitted;
-;; the modules that need them either run through the std/os shims (ffi_*)
-;; or call into the patched (load-shared-object) path that no longer fires.
+;; jsqlite uses open/flock/mmap directly through foreign-procedure; register
+;; those libc entry points here so the static binary can resolve them.
 (define libc-symbols
   '(;; sockets — std/net/tcp, std/net/udp
     "socket" "bind" "listen" "accept" "connect" "close"
@@ -211,9 +210,10 @@
     "getuid" "geteuid" "getgid" "getegid"
     "sigemptyset" "sigfillset" "sigaddset" "sigdelset"
     "sigismember" "sigprocmask"
-    ;; terminal / fd — TUI + REPL
+    ;; terminal / fd — TUI + REPL + jsqlite locking/WAL shm
     "isatty" "tcgetattr" "tcsetattr" "tcgetpgrp" "tcsetpgrp"
     "pipe" "dup" "dup2" "lseek"
+    "open" "ftruncate" "mmap" "munmap" "flock" "usleep"
     ;; env / misc — std/os/env, std/text/time
     "setenv" "unsetenv" "strerror" "localtime" "strftime"
     "sysconf" "getpagesize" "getrlimit"
@@ -225,20 +225,7 @@
 
 ;; FFI symbols that need Sforeign_symbol registration
 (define ffi-symbols
-  '(;; jerboa-sqlite shim
-    "jerboa_sqlite_open" "jerboa_sqlite_close" "jerboa_sqlite_exec"
-    "jerboa_sqlite_prepare" "jerboa_sqlite_finalize" "jerboa_sqlite_reset"
-    "jerboa_sqlite_clear_bindings" "jerboa_sqlite_step"
-    "jerboa_sqlite_column_count" "jerboa_sqlite_column_name"
-    "jerboa_sqlite_column_type" "jerboa_sqlite_column_int64"
-    "jerboa_sqlite_column_double" "jerboa_sqlite_column_text"
-    "jerboa_sqlite_column_bytes" "jerboa_sqlite_column_blob"
-    "jerboa_sqlite_bind_int64" "jerboa_sqlite_bind_double"
-    "jerboa_sqlite_bind_text" "jerboa_sqlite_bind_blob"
-    "jerboa_sqlite_bind_null" "jerboa_sqlite_last_insert_rowid"
-    "jerboa_sqlite_changes" "jerboa_sqlite_errmsg"
-    "jerboa_SQLITE_ROW" "jerboa_SQLITE_DONE" "jerboa_SQLITE_OK"
-    ;; termbox2 TUI shim
+  '(;; termbox2 TUI shim
     "jcode_tb_init" "jcode_tb_shutdown"
     "jcode_tb_width" "jcode_tb_height"
     "jcode_tb_clear" "jcode_tb_present"
@@ -276,17 +263,6 @@
     ;; jerboa-native (aproc) — used by (std os aproc) for bash tool
     "jerboa_aproc_spawn" "jerboa_aproc_spawn_pty"
     "jerboa_aproc_set_nonblock" "jerboa_aproc_killpg" "jerboa_aproc_wait4"
-    ;; jerboa-native (sqlite) — used by (std db sqlite) via sqlite-native.sls
-    "jerboa_sqlite_open" "jerboa_sqlite_close" "jerboa_sqlite_exec"
-    "jerboa_sqlite_prepare" "jerboa_sqlite_finalize" "jerboa_sqlite_reset"
-    "jerboa_sqlite_step" "jerboa_sqlite_changes" "jerboa_sqlite_errmsg"
-    "jerboa_sqlite_last_insert_rowid"
-    "jerboa_sqlite_bind_int" "jerboa_sqlite_bind_double"
-    "jerboa_sqlite_bind_text" "jerboa_sqlite_bind_blob" "jerboa_sqlite_bind_null"
-    "jerboa_sqlite_column_count" "jerboa_sqlite_column_type"
-    "jerboa_sqlite_column_int" "jerboa_sqlite_column_double"
-    "jerboa_sqlite_column_text" "jerboa_sqlite_column_blob"
-    "jerboa_sqlite_column_name"
     ;; jerboa-native (net/io) — vectored I/O wrapper used by (std net io)
     "jerboa_writev2"
     ;; landlock-shim (support/landlock-shim.c)
@@ -404,8 +380,8 @@
 ;; Rust native library — build a project-specific musl static lib with ONLY
 ;; the cargo features jcode actually uses. jcode's FFI surface is:
 ;;   - jerboa_tls_*  (provider/provider.ss)        => feature `tls`
-;;   - sqlite3_*     (via jerboa-sqlite shim)        => feature `sqlite`
-;; That's it. `crypto`, `duckdb_feat`, `pcap`, `spidermonkey`, `wasm`,
+;;   - jerboa_crypto_* / hashing / secret-store     => feature `crypto`
+;; That's it. `duckdb_feat`, `pcap`, `spidermonkey`, `wasm`, and
 ;; `postgres_feat` are not referenced from any jcode source.
 ;;
 ;; The old fall-back-to-glibc behaviour was the recurring source of "works on
@@ -423,7 +399,7 @@
 ;; A sentinel file under target/ records the exact feature set that produced
 ;; the .a, so future builds rebuild iff features changed or any .rs source
 ;; is newer than the .a (jerboa-shell uses the same pattern).
-(define jcode-cargo-features "tls,sqlite,crypto")
+(define jcode-cargo-features "tls,crypto")
 (define native-lib-path
   (format "~a/jerboa-native-rs/target/x86_64-unknown-linux-musl/release/libjerboa_native.a"
           jerboa-dir-base))
@@ -554,6 +530,7 @@
     (display "#include <sys/wait.h>\n"      out)  ;; waitpid
     (display "#include <sys/resource.h>\n"  out)  ;; getrlimit
     (display "#include <sys/prctl.h>\n"     out)  ;; prctl
+    (display "#include <sys/file.h>\n"      out)  ;; flock
     (display "#include <termios.h>\n"       out)  ;; tcgetattr/tcsetattr/tcgetpgrp/tcsetpgrp
     (display "#include <signal.h>\n"        out)  ;; kill, sigemptyset/sigprocmask family
     (display "#include <time.h>\n"          out)  ;; localtime, strftime
@@ -626,20 +603,6 @@
                  gcc harden-cflags scheme-h-dir
                  build-dir program-c))
 
-;; Compile jerboa-sqlite shim
-;; Copy sqlite3.h to build dir (can't use -I/usr/include with musl-gcc — glibc conflict)
-(let ([shim-src "vendor/jerboa-sqlite/jerboa_sqlite_shim.c"]
-      [sqlite3-h "/usr/include/sqlite3.h"])
-  (if (file-exists? shim-src)
-    (begin
-      (when (file-exists? sqlite3-h)
-        (system (format "cp '~a' '~a/'" sqlite3-h build-dir)))
-      (run-cmd (format "~a -c -O2 ~a -I'~a' -o '~a/jerboa-sqlite-shim.o' '~a' -Wall"
-                       gcc harden-cflags build-dir build-dir shim-src)))
-    (begin
-      (printf "  Note: jerboa-sqlite shim not found — creating stub~n")
-      (system (format "echo '' | ~a -c -x c -o '~a/jerboa-sqlite-shim.o' -" gcc build-dir)))))
-
 ;; Compile termbox2 TUI shim
 (run-cmd (format "~a -c -O2 ~a -DTB_OPT_ATTR_W=32 -Ivendor/termbox2 -o '~a/jcode-tui-shim.o' src/jcode/ui/jcode_tui_shim.c -Wall"
                  gcc harden-cflags build-dir))
@@ -661,13 +624,10 @@
                   "jcode-musl"
                   (list (format "~a/jcode_main_musl.o" build-dir)
                         (format "~a/static_boot.o" build-dir)
-                        (format "~a/jerboa-sqlite-shim.o" build-dir)
                         (format "~a/jcode-tui-shim.o" build-dir)
                         (format "~a/landlock-shim.o" build-dir))
-                  ;; Rust native lib includes sqlite3, TLS (rustls), regex, etc.
-                  (if has-native-lib?
-                    (list native-lib-path)
-                    (list "/usr/lib/x86_64-linux-gnu/libsqlite3.a"))
+                  ;; Rust native lib includes TLS, crypto, regex, aproc, etc.
+                  (list native-lib-path)
                   '(no-harden: #t))])
   ;; GCC 13+ libgcc_eh.a references _dl_find_object (glibc 2.35+) which
   ;; doesn't exist in musl. Stub it out with --defsym.
diff --git a/docs/getting-started.md b/docs/getting-started.md
index f704bf5..d2dbf31 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -40,12 +40,14 @@ prerequisites, building on each platform, configuration, and your first session.
 
 ## Vendored dependencies
 
-Three repos are cloned into `vendor/` at build time (the directory is
-git-ignored — these are **not** submodules):
+Two repos are cloned into `vendor/` at build time (the directory is git-ignored
+— these are **not** submodules). Session storage uses the sibling `jsqlite`
+checkout at `~/mine/jsqlite` by default; set `JSQLITE_DIR=/path/to/jsqlite` if
+it lives elsewhere.
 
 | Dependency | Source |
 |---|---|
-| `jerboa-sqlite` | `git.sr.ht/~lisp/jerboa-sqlite` — SQLite FFI shim for session storage |
+| `jsqlite` | `~/mine/jsqlite` — pure Scheme SQLite-compatible session storage |
 | `termbox2` | `github.com/termbox/termbox2` — the TUI's terminal backend |
 | `jerboa-websearch` | `git.sr.ht/~lisp/jerboa-websearch` — in-process web search |
 
@@ -54,7 +56,6 @@ over HTTPS:
 
 ```bash
 mkdir -p vendor
-git clone --depth 1 https://git.sr.ht/~lisp/jerboa-sqlite     vendor/jerboa-sqlite
 git clone --depth 1 https://github.com/termbox/termbox2.git vendor/termbox2
 git clone --depth 1 https://git.sr.ht/~lisp/jerboa-websearch vendor/jerboa-websearch
 ```
diff --git a/docs/local-model-smartness-plan.md b/docs/local-model-smartness-plan.md
index b107279..b9ed374 100644
--- a/docs/local-model-smartness-plan.md
+++ b/docs/local-model-smartness-plan.md
@@ -115,7 +115,8 @@ As of this plan, the harness already has:
 - MCP tool discovery and MCP-origin workflow tool exposure.
 - Automatic `jerboa_request_advisor` preflight for Jerboa-looking verified
   tasks.
-- MCP failure advisor on failing verify results.
+- Failed verify augmentation with source targets, MCP failure advice, MCP
+  error-fix lookup, and MCP anti-pattern lookup.
 - Native edit aliases for `old_str`/`new_str` and `old_string`/`new_string`.
 
 This plan builds on those capabilities.
@@ -764,7 +765,7 @@ Add a trace summarizer that extracts:
 
 ### Failure Pattern Data
 
-Create a local data file:
+For raw eval summaries, create a local data file:
 
 ```text
 data/local-model-failures.sexp
@@ -787,6 +788,17 @@ Example entry:
  (tests . ("verified-run: exact replacement aliases can repair rejected draft")))
 ```
 
+For reusable lessons, update the persistent Jerboa knowledge bases instead of
+only keeping local eval notes:
+
+- working pattern: `~/mine/jerboa/data/cookbooks.sexp` via `jerboa_howto_add`
+- plausible failed strategy: `~/mine/jerboa/data/anti-patterns.sexp` after
+  checking `jerboa_anti_pattern_lookup`
+- exact repeated error text: `~/mine/jerboa/data/error-fixes.sexp` via
+  `jerboa_error_fix_add`
+- missing harness or MCP capability: `~/mine/jerboa/data/features.sexp` via
+  `jerboa_suggest_feature`
+
 ### Automated Recommendations
 
 The summarizer should produce suggestions:
@@ -1082,22 +1094,25 @@ For `jerboa_failure_advisor`, support:
 On failing verify:
 
 1. Run internal classifiers.
-2. Call MCP failure advisor.
-3. Merge advice.
-4. Set required action if the diagnosis is concrete.
-5. Include compact explanation in model context.
+2. Add source call-site targets for runtime primitive failures when the failing
+   file or write-scope target is available.
+3. Call MCP failure advisor, error-fix lookup, and anti-pattern lookup.
+4. Merge advice.
+5. Set required action if the diagnosis is concrete.
+6. Include compact explanation in model context.
 
 Conflict rule:
 
 - Internal verifier diagnosis wins for exact line/range.
-- MCP can add anti-pattern guidance.
+- MCP can add failure, error-fix, and anti-pattern guidance.
 - If MCP suggests a different exact repair, log both and choose the safer one.
 
 ### Tests
 
 - structured MCP repair sets required action
 - internal repair overrides vague MCP advice
-- passing verify does not call failure advisor
+- passing verify does not call failure advisors/lookups
+- runtime primitive errors point at likely source call sites
 - malformed MCP response does not crash
 
 ### Acceptance Criteria
diff --git a/docs/verified.md b/docs/verified.md
index c2c1a9d..5fdcfc2 100644
--- a/docs/verified.md
+++ b/docs/verified.md
@@ -261,8 +261,9 @@ There are four current integration paths:
 
 1. Automatic preflight: for Jerboa-looking tasks, `jcode verified` calls a
    registered MCP `jerboa_request_advisor` before the first model turn.
-2. Failure repair: failed verifier output is augmented with
-   `jerboa_failure_advisor` when that MCP tool is available.
+2. Failure repair: failed verifier output is augmented with source target
+   call sites plus `jerboa_failure_advisor`, `jerboa_error_fix_lookup`, and
+   `jerboa_anti_pattern_lookup` when those MCP tools are available.
 3. Manual guidance: pre-generate a cookbook/task bundle and pass it with
    `--guidance-file`.
 4. Let the model call MCP tools during the verified workflow.
@@ -395,7 +396,10 @@ For Jerboa coding tasks, use this pattern:
    - the guidance file,
    - MCP enabled.
 4. Let the model repair against actual Scheme/Jerboa errors.
-5. If it fails, improve the cookbook with the failure pattern you saw.
+5. If it fails, save the lesson in the right knowledge base:
+   - working reusable pattern -> `cookbooks.sexp` / `jerboa_howto_add`
+   - plausible bad strategy -> `anti-patterns.sexp`
+   - exact error text with reusable repair -> `error-fixes.sexp` / `jerboa_error_fix_add`
 ```
 
 Example:
@@ -494,7 +498,7 @@ If this still loops:
 - narrow the task,
 - add a better `--guidance-file`,
 - use `--no-run-aliases`,
-- increase cookbook anti-pattern coverage for the failure you saw.
+- increase anti-pattern or error-fix coverage for the failure you saw.
 
 ### The run passes but the behavior is wrong
 
diff --git a/linux-check.ss b/linux-check.ss
index c0771ac..3b870b5 100644
--- a/linux-check.ss
+++ b/linux-check.ss
@@ -18,7 +18,7 @@
 ;;;   make linux-check
 ;;;
 ;;; Direct:
-;;;   scheme -q --libdirs "$JERBOA_HOME/lib:./lib:vendor/jerboa-sqlite/src" \
+;;;   scheme -q --libdirs "$JERBOA_HOME/lib:./lib:$HOME/mine/jsqlite/src:vendor/jerboa-websearch/src" \
 ;;;          --script linux-check.ss
 
 (import (chezscheme))
diff --git a/src/jcode/core/builtin-skills.ss b/src/jcode/core/builtin-skills.ss
index d7a740d..edb4728 100644
--- a/src/jcode/core/builtin-skills.ss
+++ b/src/jcode/core/builtin-skills.ss
@@ -15,13 +15,14 @@
 
 (def *save-discoveries-prompt*
   (string-append
-"Review what was learned during this session and save it in three ways.\n"
+"Review what was learned during this session and save it in five ways.\n"
 "\n"
-"All discoveries are written to the jerboa-mcp repository at\n"
-"~/mine/jerboa-mcp via the jerboa MCP tools (jerboa_howto_add,\n"
-"jerboa_suggest_feature, jerboa_security_pattern_add). Pass NO\n"
-"cookbook_path / features_path / rules_path arguments — let them default\n"
-"to the global jerboa-mcp paths.\n"
+"All discoveries are written to the Jerboa repository at ~/mine/jerboa.\n"
+"Use jerboa MCP writer tools when they exist (jerboa_howto_add,\n"
+"jerboa_anti_pattern_add, jerboa_error_fix_add, jerboa_suggest_feature,\n"
+"jerboa_security_pattern_add). Pass NO cookbook_path / anti_patterns_path /\n"
+"error_fixes_path / features_path / rules_path arguments —\n"
+"let them default to the global Jerboa data paths.\n"
 "\n"
 "## Step 1: Save Cookbook Recipes\n"
 "\n"
@@ -39,7 +40,44 @@
 "\n"
 "Skip trivial one-liners and project-specific business logic.\n"
 "\n"
-"## Step 2: Suggest Tooling Improvements\n"
+"## Step 2: Save Anti-Patterns\n"
+"\n"
+"For each plausible model mistake, failed strategy, weak verifier, or repeated\n"
+"bad edit pattern noticed during this session:\n"
+"\n"
+"1. Call `jerboa_anti_pattern_lookup` with relevant keywords to check if an entry already exists.\n"
+"2. If not found, call `jerboa_anti_pattern_add` with:\n"
+"   - `id`: kebab-case identifier\n"
+"   - `title`: human-readable title\n"
+"   - `kinds`: one or more of `all`, `script`, `module`, `debug-error`, `docs`, `test`, `security`, `ffi`\n"
+"   - `severity`: `high` | `medium` | `low`\n"
+"   - `tags`: 4-6 search keywords\n"
+"   - `pattern`: regex or compact text pattern that identifies the mistake or error\n"
+"   - `avoid`: what the model should stop doing\n"
+"   - `advice`: the concrete replacement behavior\n"
+"   - `tools`: MCP tools or workflow tools that help avoid or repair it\n"
+"\n"
+"Save the normalized reusable mistake, not the whole failed trace. For example,\n"
+"save upper-bound-only grid checks before vector-ref rather than a benchmark name.\n"
+"\n"
+"## Step 3: Save Error Fixes\n"
+"\n"
+"For each concrete compiler, verifier, runtime, or tool error where the repair\n"
+"is reusable:\n"
+"\n"
+"1. Call `jerboa_error_fix_lookup` with the exact error text to check for duplicates.\n"
+"2. If not found, call `jerboa_error_fix_add` with:\n"
+"   - `id`: kebab-case identifier\n"
+"   - `pattern`: regex matching the important error text\n"
+"   - `fix`: concise repair instruction\n"
+"   - Optional `type`: category such as `syntax`, `arity`, `runtime`, `module-resolution`, `vector-bounds`\n"
+"   - Optional `explanation`: why the error happens\n"
+"   - Optional `code_example`: minimal before/after or fixed snippet\n"
+"\n"
+"Save error fixes when the same error is likely to recur. Do not save one-off\n"
+"project business logic failures.\n"
+"\n"
+"## Step 4: Suggest Tooling Improvements\n"
 "\n"
 "For each workflow friction point or missing tool capability noticed\n"
 "during this session:\n"
@@ -56,7 +94,7 @@
 "   - `example_scenario`: concrete example of the problem\n"
 "   - `estimated_token_reduction`: e.g. \"~500 tokens per invocation\", \"eliminates 3 tool calls\"\n"
 "\n"
-"## Step 3: Add Security Patterns\n"
+"## Step 5: Add Security Patterns\n"
 "\n"
 "For each new vulnerability pattern, unsafe coding practice, or FFI misuse\n"
 "discovered during this session:\n"
@@ -84,6 +122,13 @@
 "- Arity or signature discoveries that weren't obvious\n"
 "- Module path conventions (e.g. `(std text json)` not `:std/text/json`)\n"
 "\n"
+"Anti-patterns to save:\n"
+"- Repeated local-model mistakes that look plausible but fail verification\n"
+"- Weak verifier patterns that allow false success\n"
+"- Failed repair loops such as broad reading after a concrete verifier error\n"
+"- Runtime mistakes such as missing lower-bound checks before vector access\n"
+"- Hidden benchmark-specific shortcuts that invalidate evaluation\n"
+"\n"
 "Features to suggest or vote for:\n"
 "- Multiple sequential tool calls that could be a single tool\n"
 "- Missing tool parameters or modes\n"
@@ -91,6 +136,12 @@
 "- Repeated cross-session patterns that could be automated\n"
 "- If the friction matches an existing feature suggestion, vote for it instead of creating a duplicate\n"
 "\n"
+"Error fixes to save:\n"
+"- Exact compiler/runtime/verifier messages with a repeatable repair\n"
+"- Error text that `jerboa_failure_advisor` could classify better next time\n"
+"- Errors from local-model generated code where a short diagnosis prevents another failed iteration\n"
+"- Tool-output failures that need a known workaround\n"
+"\n"
 "Security patterns to add:\n"
 "- New vulnerability patterns found during code review or debugging\n"
 "- Unsafe FFI calling conventions (missing null checks, type mismatches with `foreign-procedure`)\n"
@@ -98,7 +149,8 @@
 "- Resource leaks (ports, fds, mutexes) without `unwind-protect` / `dynamic-wind`\n"
 "- Unsafe C shim patterns (buffer overflows, static globals, missing error checks)\n"
 "\n"
-"Report what was saved, suggested, voted for, and security patterns added when done.\n"))
+"Report what recipes, anti-patterns, error fixes, feature suggestions/votes,\n"
+"and security patterns were saved when done.\n"))
 
 ;; ── Plan-lifecycle skills ────────────────────────────────────────────
 ;; Ported from opencode-processing-skills: a file-based plan workflow