build: build secmon-agent with installed jerbuild (no ~/mine/jerboa)

ober

82a963c7413d9371e8adfcd33ebe40b1afe8ee3f

diff --git a/.gitignore b/.gitignore
index 7b820db..07d23d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
 *.so
 *.wpo
 *.o
+target/
+*-main.c
 keys/
 secmon-agent
 secmon-agent.sha256
diff --git a/.jerbuild b/.jerbuild
index a553708..2164dd3 100644
--- a/.jerbuild
+++ b/.jerbuild
@@ -2,8 +2,11 @@
 
 (entry "bin/agent.ss")
 (output "secmon-agent")
-(requires "cc" "cargo")
-(notes "Uses the jerbuild-bundled jerboa-native-rs crate with crypto and SQLite enabled.")
 (libdirs "lib")
+;; Statically register the linked-in jerboa-native symbols via Sforeign_symbol
+;; so the (std crypto native-rust) + (std db sqlite-native) FFI calls resolve
+;; in this static binary (dlsym(RTLD_DEFAULT) can't see dead-stripped archive
+;; symbols). The list also forces those archive members to be linked in.
+(ffi-symbols "support/ffi-symbols.list")
 (rust-crates
   ("@bundle/jerboa-native-rs/Cargo.toml" features: "crypto,sqlite"))
diff --git a/CLAUDE.md b/CLAUDE.md
index b52b0c9..dca8289 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,25 +1,28 @@
 # CLAUDE.md — jerboa-secmon
 
-## MANDATORY: Verify Docker Build
+## MANDATORY: Verify the jerbuild Build
 
-**ALWAYS run `make docker` after ANY change and verify the static binary works before committing.**
+**ALWAYS run `make binary` after ANY change and verify it builds before committing.**
 
-This is non-negotiable. Never commit without confirming:
-1. `make build` succeeds (all 33 modules compile)
-2. `make docker` succeeds (static binary builds in Docker)
-3. The resulting `secmon-agent` binary runs
+The build is self-contained: `jerbuild` bundles Chez + the jerboa stdlib + the
+jerboa-native Rust crate, so it needs only `jerbuild`, a C compiler, and cargo —
+no `~/mine/jerboa` checkout, no separately-built Chez, no Docker.
 
-If the Docker build fails, fix it before doing anything else.
+1. `make binary` succeeds (`jerbuild build` → static `secmon-agent`)
+2. The resulting `secmon-agent` binary runs (on a Linux/FreeBSD target)
+
+Note: the agent links jerboa-native (crypto+sqlite) statically; its FFI symbols
+are registered from `support/ffi-symbols.list` (regenerate with
+`nm -gjU` on the bundled `libjerboa_native.a` if the feature set changes).
+secmon targets Linux/FreeBSD; the bundled stdlib's `load-shared-object "libc.so"`
+paths mean it does not run on macOS, but it builds there.
 
 ## Build Commands
 
 ```bash
-make                     # Show help / list targets
-make build               # Compile all .sls → .so modules
-make secmon-static       # Build static binary on FreeBSD
-make docker              # Build fully static binary in Docker (Linux)
-make secmon-musl-local   # Build static binary locally (Linux, needs musl)
+make binary              # Build the standalone secmon-agent via jerbuild
 make clean               # Remove all build artifacts
+make agent | keygen | collector | analyze | test   # Run from source (jerbuild exec)
 ```
 
 ## Project Overview
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 4293942..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,112 +0,0 @@
-# Dockerfile — Build secmon-agent as a fully static binary
-#
-# All source repos are cloned and built inside the container under /build/mine,
-# with HOME=/build so no real usernames or home directories leak into the binary.
-#
-# Usage:
-#   docker build -t secmon-builder .
-#   id=$(docker create secmon-builder)
-#   docker cp $id:/out/secmon-agent ./secmon-agent
-#   docker rm $id
-
-FROM ubuntu:24.04 AS builder
-
-ARG DEBIAN_FRONTEND=noninteractive
-
-# ── System dependencies ──────────────────────────────────────────────────────
-RUN apt-get update && apt-get install -y --no-install-recommends \
-    build-essential \
-    musl-tools \
-    musl-dev \
-    git \
-    ca-certificates \
-    curl \
-    libncurses-dev \
-    uuid-dev \
-    pkg-config \
-    file \
-    && rm -rf /var/lib/apt/lists/*
-
-# ── Rust toolchain (for jerboa-native-rs) ────────────────────────────────────
-RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | \
-    sh -s -- -y --default-toolchain stable --profile minimal && \
-    . /root/.cargo/env && \
-    rustup target add x86_64-unknown-linux-musl
-
-ENV PATH="/root/.cargo/bin:${PATH}"
-ENV RUSTUP_HOME="/root/.rustup"
-
-# Set HOME early — everything under /build so paths are clean
-ENV HOME=/build
-WORKDIR /build
-
-# ── Build Chez Scheme (stock glibc, for compilation steps) ───────────────────
-# Chez is now vendored inside jerboa at vendor/ChezScheme.
-RUN git clone --depth 1 https://git.sr.ht/~lisp/jerboa /tmp/jerboa-src && \
-    cd /tmp/jerboa-src/vendor/ChezScheme && \
-    ./configure --threads --disable-x11 --installprefix=/usr/local && \
-    make -j$(nproc) && \
-    make install && \
-    cd /build && rm -rf /tmp/jerboa-src
-
-# ── Build Chez Scheme (musl, for static linking) ────────────────────────────
-# Two passes: glibc for boot files, then musl for libkernel.a
-RUN git clone https://git.sr.ht/~lisp/jerboa /tmp/jerboa-musl-src && \
-    cd /tmp/jerboa-musl-src/vendor/ChezScheme && \
-    ./configure --threads --disable-x11 --installprefix=/build/chez-musl && \
-    make -j$(nproc) && \
-    cp ta6le/boot/ta6le/petite.boot /tmp/petite.boot && \
-    cp ta6le/boot/ta6le/scheme.boot /tmp/scheme.boot && \
-    make clean && \
-    ./configure --threads --disable-x11 --static CC=musl-gcc --installprefix=/build/chez-musl && \
-    mkdir -p ta6le/boot/ta6le && \
-    cp /tmp/petite.boot ta6le/boot/ta6le/ && \
-    cp /tmp/scheme.boot ta6le/boot/ta6le/ && \
-    make -j$(nproc) kernel && \
-    make install && \
-    cd /build && rm -rf /tmp/jerboa-musl-src /tmp/petite.boot /tmp/scheme.boot
-
-# ── Clone jerboa framework ──────────────────────────────────────────────────
-WORKDIR /build/mine
-ARG JERBOA_CACHE_BUST=1
-RUN git clone --depth 1 https://git.sr.ht/~lisp/jerboa && echo "bust=$JERBOA_CACHE_BUST"
-
-# ── Patch jerboa-native-rs with files not yet pushed to remote ──────────────
-# x25519.rs, process_ctl.rs, updated Cargo.toml/lib.rs needed for secmon
-COPY patches/jerboa-native-rs/ /build/mine/jerboa/jerboa-native-rs/
-
-# ── Build Rust native library (static, musl target) ─────────────────────────
-RUN cd /build/mine/jerboa/jerboa-native-rs && \
-    CARGO_HOME=/build/.cargo \
-    RUSTFLAGS="--remap-path-prefix /build/.cargo/registry/src=crate --remap-path-prefix /build/mine=src" \
-    cargo build --release --target x86_64-unknown-linux-musl && \
-    strip -S target/x86_64-unknown-linux-musl/release/libjerboa_native.a
-
-# ── Copy secmon source ───────────────────────────────────────────────────────
-COPY . /build/mine/jerboa-secmon
-
-# ── Set environment for build ────────────────────────────────────────────────
-ENV JERBOA_MUSL_CHEZ_PREFIX=/build/chez-musl
-ENV JERBOA=/build/mine/jerboa/lib
-
-# ── Build secmon-agent ───────────────────────────────────────────────────────
-WORKDIR /build/mine/jerboa-secmon
-RUN make secmon-musl-local
-
-# ── Verify ───────────────────────────────────────────────────────────────────
-RUN echo "--- Binary info ---" && \
-    ls -lh secmon-agent && \
-    file secmon-agent && \
-    echo "--- Hardening checks ---" && \
-    (file secmon-agent | grep -qE 'stripped|no section header') && echo "  PASS: stripped" || echo "  FAIL: not stripped" && \
-    test -f secmon-agent.sha256 && echo "  PASS: integrity hash present" || echo "  FAIL: no hash" && \
-    echo "--- Username leak check ---" && \
-    count=$(strings secmon-agent | grep -c '/home/jafourni' || true) && \
-    echo "Occurrences of username path: $count" && \
-    if [ "$count" -gt 0 ]; then echo "WARNING: username still present"; fi
-
-# ── Output ───────────────────────────────────────────────────────────────────
-FROM ubuntu:24.04
-COPY --from=builder /build/mine/jerboa-secmon/secmon-agent /out/secmon-agent
-COPY --from=builder /build/mine/jerboa-secmon/secmon-agent.sha256 /out/secmon-agent.sha256
-CMD ["cat", "/out/secmon-agent"]
diff --git a/Makefile b/Makefile
index 5c09665..20b3fae 100644
--- a/Makefile
+++ b/Makefile
@@ -1,121 +1,65 @@
-SCHEME ?= scheme
-JERBOA ?= $(HOME)/jerboa/lib
-LIBDIRS = lib:$(JERBOA)
-NATIVE_RS ?= $(HOME)/mine/jerboa/jerboa-native-rs/target/release
-export LD_LIBRARY_PATH := $(NATIVE_RS):$(LD_LIBRARY_PATH)
+# jerbuild bundles Chez Scheme + the jerboa stdlib + the jerboa-native Rust
+# crate, so building secmon-agent needs only `jerbuild`, a C compiler, and
+# cargo — no jerboa source checkout and no separately-built Chez/native lib.
+JERBUILD ?= jerbuild
+JH := $(shell $(JERBUILD) --jerboa-home 2>/dev/null)
+ifeq ($(JH),)
+$(error jerbuild not found on PATH (or '$(JERBUILD) --jerboa-home' failed). Install jerbuild, or set JERBUILD=/path/to/jerbuild)
+endif
 
-.PHONY: all help build compile clean test keygen agent collector analyze docker secmon-musl secmon-musl-local secmon-static verify-harden
+LIBDIRS := --libdirs lib:$(JH)/lib
+JEXEC   := $(JERBUILD) exec $(LIBDIRS)
+BIN     := secmon-agent
+BIN_DIR := $(HOME)/.local/bin
 
-all: help
+.PHONY: all help build binary keygen agent collector analyze test install clean
+.DEFAULT_GOAL := help
+
+all: binary
 
 help:
-	@echo "jerboa-secmon — Security monitoring agent (Scheme)"
+	@echo "jerboa-secmon — Security monitoring agent (Jerboa)"
 	@echo ""
-	@echo "Build:"
-	@echo "  make build             Compile all .sls → .so modules"
-	@echo "  make secmon-static     Build static binary on FreeBSD"
-	@echo "  make docker            Build fully static binary in Docker (Linux)"
-	@echo "  make secmon-musl-local Build static binary locally (Linux, needs musl)"
-	@echo "  make clean             Remove all build artifacts"
+	@echo "Build (needs only jerbuild + cc + cargo):"
+	@echo "  make binary            Build the standalone ./secmon-agent (.jerbuild)"
+	@echo "  make clean             Remove build artifacts"
 	@echo ""
-	@echo "Run:"
-	@echo "  make keygen            Generate ECIES keypair + PSK"
+	@echo "Run from source (Linux/FreeBSD target):"
 	@echo "  make agent             Run the monitoring agent"
+	@echo "  make keygen            Generate ECIES keypair + PSK"
 	@echo "  make collector ARGS=.. Run the event collector"
 	@echo "  make analyze ARGS=..   Run the offline analyzer"
-	@echo ""
-	@echo "Verify:"
-	@echo "  make test              Run test suite"
-	@echo "  make verify-harden     Check binary hardening (strip, leaks, hash)"
-
-# ─── Compilation ─────────────────────────────────────────────────────────────
+	@echo "  make test              Run the test suite"
 
-build: compile
+# Standalone native binary via .jerbuild (entry bin/agent.ss -> secmon-agent).
+# Cargo-builds jerboa-native (crypto+sqlite) from jerbuild's bundled crate and
+# registers its FFI symbols (support/ffi-symbols.list) into the static binary.
+binary:
+	$(JERBUILD) build
 
-compile:
-	@echo "=== Compiling .sls → .so ==="
-	$(SCHEME) -q --libdirs $(LIBDIRS) --compile-imported-libraries < build-all.ss
+build: binary
 
-# ─── Run Targets ─────────────────────────────────────────────────────────────
+agent:
+	$(JEXEC) bin/agent.ss
 
 keygen:
-	$(SCHEME) --libdirs $(LIBDIRS) --script bin/keygen.ss
-
-agent:
-	$(SCHEME) --libdirs $(LIBDIRS) --script bin/agent.ss
+	$(JEXEC) bin/keygen.ss
 
 collector:
-	$(SCHEME) --libdirs $(LIBDIRS) --script bin/collector.ss $(ARGS)
+	$(JEXEC) bin/collector.ss $(ARGS)
 
 analyze:
-	$(SCHEME) --libdirs $(LIBDIRS) --script bin/analyze.ss $(ARGS)
-
-# ─── FreeBSD Static Binary ───────────────────────────────────────────────────
-
-secmon-static:
-	@echo "=== Building static secmon-agent for FreeBSD ==="
-	./build-secmon-static.sh
-
-# ─── musl Static Binary ─────────────────────────────────────────────────────
-# Default: build via Docker for reproducibility and correct toolchain deps.
-# Use `make secmon-musl-local` to build directly on the host (requires musl-gcc,
-# Rust musl target, and all dependencies installed locally).
-
-secmon-musl: docker
-
-secmon-musl-local:
-	@echo "=== Building static secmon-agent with musl (local) ==="
-	./build-secmon-musl.sh
-
-# ─── Docker Build ────────────────────────────────────────────────────────────
-
-docker:
-	@echo "=== Building secmon-agent in Docker ==="
-	docker build -t secmon-builder .
-	@id=$$(docker create secmon-builder) && \
-	docker cp $$id:/out/secmon-agent ./secmon-agent && \
-	docker cp $$id:/out/secmon-agent.sha256 ./secmon-agent.sha256 && \
-	docker rm $$id >/dev/null && \
-	chmod +x secmon-agent
-	@echo "=== Docker build complete ==="
-	@ls -lh secmon-agent
-	@file secmon-agent
-
-# ─── Hardening Verification ─────────────────────────────────────────────────
-
-verify-harden: secmon-agent
-	@echo "=== Verifying binary hardening ==="
-	@echo "--- Symbol check (should show 'stripped') ---"
-	@(file secmon-agent | grep -qE 'stripped|no section header') && echo "  PASS: binary is stripped" || echo "  FAIL: binary not stripped"
-	@echo "--- Build path leak check ---"
-	@if strings secmon-agent | grep -q "$(HOME)"; then \
-		echo "  WARN: home directory path found in binary"; \
-	else \
-		echo "  PASS: no home directory paths leaked"; \
-	fi
-	@echo "--- Integrity hash check ---"
-	@if [ -f secmon-agent.sha256 ]; then \
-		echo "  PASS: secmon-agent.sha256 exists ($$(wc -c < secmon-agent.sha256) bytes)"; \
-	else \
-		echo "  FAIL: secmon-agent.sha256 not found"; \
-	fi
-	@echo "=== Hardening verification complete ==="
-
-# ─── Testing ─────────────────────────────────────────────────────────────────
+	$(JEXEC) bin/analyze.ss $(ARGS)
 
 test:
-	@echo "=== Running tests ==="
-	@for f in tests/*-test.ss; do \
-		echo "Testing $$f..."; \
-		$(SCHEME) --libdirs $(LIBDIRS) --script $$f || exit 1; \
-	done
+	@for f in tests/*-test.ss; do echo "== $$f =="; $(JEXEC) $$f || exit 1; done
 	@echo "All tests passed."
 
-# ─── Cleanup ─────────────────────────────────────────────────────────────────
+install: binary
+	mkdir -p $(BIN_DIR)
+	install -m 0755 $(BIN) $(BIN_DIR)/$(BIN)
+	@echo "Installed $(BIN) to $(BIN_DIR)/$(BIN)"
 
 clean:
-	find lib -name '*.so' -delete
-	find lib -name '*.wpo' -delete
-	rm -f secmon-agent secmon-agent.sha256
-	rm -f secmon-program.c secmon-program.o secmon-agent.boot
-	rm -rf jerboa-stage/
+	find lib \( -name '*.so' -o -name '*.wpo' \) -delete 2>/dev/null || true
+	rm -f $(BIN) $(BIN).sha256 $(BIN)-main.c
diff --git a/build-all.ss b/build-all.ss
deleted file mode 100644
index 0994f2e..0000000
--- a/build-all.ss
+++ /dev/null
@@ -1,45 +0,0 @@
-;; build-all.ss — Import all modules to trigger --compile-imported-libraries
-(import
-  ;; Crypto
-  (secmon crypto keys)
-  (secmon crypto ecies)
-  (secmon crypto psk)
-  ;; Monitor core
-  (secmon monitor events)
-  (secmon monitor suspicious)
-  ;; Platform
-  (secmon platform provider)
-  (secmon platform freebsd)
-  ;; Buffer
-  (secmon buffer ring)
-  ;; Server
-  (secmon server protocol)
-  (secmon server listener)
-  ;; Config
-  (secmon config)
-  ;; Storage
-  (secmon storage store)
-  ;; Monitors
-  (secmon monitor process)
-  (secmon monitor network)
-  (secmon monitor files)
-  (secmon monitor auth)
-  (secmon monitor kernel)
-  (secmon monitor cron)
-  (secmon monitor container)
-  (secmon monitor dns)
-  (secmon monitor rootkit)
-  (secmon monitor persistence)
-  (secmon monitor revshell)
-  (secmon monitor lateral)
-  (secmon monitor logtamper)
-  (secmon monitor webshell)
-  (secmon monitor podman)
-  (secmon monitor selinux)
-  ;; Stealth
-  (secmon stealth obfuscate)
-  (secmon stealth anti-debug)
-  (secmon stealth masquerade)
-  (secmon stealth env-sanitize)
-  (secmon stealth integrity)
-  (secmon stealth init))
diff --git a/build-secmon-musl.sh b/build-secmon-musl.sh
deleted file mode 100755
index 0812256..0000000
--- a/build-secmon-musl.sh
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/bin/bash
-# build-secmon-musl.sh — Build secmon-agent as a fully static binary using musl libc
-#
-# Prerequisites:
-#   - musl-gcc installed (apt install musl-tools)
-#   - Chez Scheme built with: ./configure --threads --static CC=musl-gcc
-#     and installed to ~/chez-musl (or set JERBOA_MUSL_CHEZ_PREFIX)
-#   - Jerboa libraries compiled
-#   - libjerboa_native.a built for x86_64-unknown-linux-musl
-set -euo pipefail
-
-JERBOA_DIR="${JERBOA_DIR:-$HOME/mine/jerboa}"
-JERBOA_LIB="${JERBOA_DIR}/lib"
-
-echo "==================================="
-echo "Building secmon-agent with musl libc (static)"
-echo "==================================="
-echo ""
-echo "Jerboa: $JERBOA_LIB"
-echo ""
-
-# Check musl availability
-if ! command -v musl-gcc &>/dev/null; then
-	echo "ERROR: musl-gcc not found"
-	echo "Install: sudo apt install musl-tools"
-	exit 1
-fi
-
-# Use jerboa's musl module to validate
-echo "[1/2] Validating musl toolchain via jerboa..."
-scheme -q --libdirs "lib:${JERBOA_LIB}" <<'VALIDATE'
-(import (chezscheme) (jerboa build musl))
-(let ([result (validate-musl-setup)])
-  (printf "  ~a: ~a~n" (car result) (cdr result))
-  (unless (eq? (car result) 'ok)
-    (exit 1)))
-VALIDATE
-
-echo ""
-echo "[2/2] Running musl build..."
-NATIVE_RS="${NATIVE_RS:-$HOME/mine/jerboa/jerboa-native-rs/target/x86_64-unknown-linux-musl/release}"
-LD_LIBRARY_PATH="${NATIVE_RS}:${LD_LIBRARY_PATH:-}" \
-  scheme -q --libdirs "lib:${JERBOA_LIB}" \
-  <build-secmon-musl.ss
-
-# Verify
-if [ -f "secmon-agent" ]; then
-	echo ""
-	echo "==================================="
-	echo "secmon-agent built successfully!"
-	echo "==================================="
-	ls -lh secmon-agent
-	echo ""
-	file secmon-agent
-	echo ""
-	ldd secmon-agent 2>&1 || echo "  (Fully static - no dependencies)"
-else
-	echo "ERROR: secmon-agent not created"
-	exit 1
-fi
diff --git a/build-secmon-musl.ss b/build-secmon-musl.ss
deleted file mode 100644
index aa44c4e..0000000
--- a/build-secmon-musl.ss
+++ /dev/null
@@ -1,507 +0,0 @@
-#!chezscheme
-;;; build-secmon-musl.ss — Build a fully static secmon-agent binary using musl libc
-;;;
-;;; Usage: scheme -q --libdirs lib:<jerboa-lib> < build-secmon-musl.ss
-;;;
-;;; This script:
-;;;   1. Stages jerboa modules with load-shared-object patched out
-;;;   2. Compiles all jerboa + secmon modules from staged/patched sources
-;;;   3. Creates boot file + optimized program .so
-;;;   4. Generates C files with embedded boot data + FFI symbol registration
-;;;   5. Compiles C with musl-gcc against musl-built Chez's scheme.h
-;;;   6. Links fully static binary with libkernel.a + libjerboa_native.a
-;;;
-;;; The resulting secmon-agent binary has zero runtime dependencies.
-
-(import
-  (except (chezscheme) void box box? unbox set-box!
-          andmap ormap iota last-pair find
-          1+ 1- fx/ fx1+ fx1-
-          error error? raise with-exception-handler identifier?
-          hash-table? make-hash-table)
-  (jerboa build)
-  (jerboa build musl))
-
-;; ========== Validate musl setup ==========
-
-(let ([result (validate-musl-setup)])
-  (unless (eq? (car result) 'ok)
-    (printf "Error: ~a~n" (cdr result))
-    (exit 1)))
-
-(printf "musl Chez found: ~a~n~n" (musl-chez-lib-dir))
-
-;; ========== Locate directories ==========
-
-(define jerboa-dir
-  (or (getenv "JERBOA_DIR")
-      (format "~a/mine/jerboa/lib" (getenv "HOME"))))
-
-(define native-lib-path
-  (format "~a/mine/jerboa/jerboa-native-rs/target/x86_64-unknown-linux-musl/release/libjerboa_native.a"
-          (getenv "HOME")))
-
-(define has-native-lib? (file-exists? native-lib-path))
-(unless has-native-lib?
-  (printf "ERROR: libjerboa_native.a not found at ~a~n" native-lib-path)
-  (printf "Build with: cd ~/mine/jerboa/jerboa-native-rs && cargo build --release --target x86_64-unknown-linux-musl~n")
-  (exit 1))
-
-(printf "Native lib: ~a~n~n" native-lib-path)
-
-;; ========== Step 0: Stage and patch jerboa modules for static builds ==========
-;; Modules that call (load-shared-object ...) need to be patched to (void)
-;; since dlopen is unavailable in static musl builds. FFI symbols are
-;; pre-registered via Sforeign_symbol() in the C bootstrap.
-
-(printf "[0/7] Patching jerboa modules for static build (no dlopen)...~n")
-
-(define jerboa-stage (format "~a/jerboa-stage" (current-directory)))
-(system (format "rm -rf '~a'" jerboa-stage))
-(system (format "mkdir -p '~a'" jerboa-stage))
-
-;; Copy the jerboa lib tree contents to staging
-(system (format "cp -a '~a/.' '~a/'" jerboa-dir jerboa-stage))
-
-;; Patch all load-shared-object calls in staged copies
-;; NOTE: Space after "load-shared-object" prevents matching "(load-shared-object* name)"
-;; in jerboa/ffi.sls which would corrupt the define form
-(system (format "find '~a' -name '*.sls' -exec sed -i 's/(load-shared-object [^)]*)/(void)/g' {} +" jerboa-stage))
-;; Delete pre-compiled .so/.wpo files to force recompilation from patched sources
-(system (format "find '~a' -name '*.so' -delete" jerboa-stage))
-(system (format "find '~a' -name '*.wpo' -delete" jerboa-stage))
-
-(printf "  Patched jerboa sources staged in ~a~n" jerboa-stage)
-
-;; ========== Override library-directories ==========
-;; CRITICAL: Use ONLY the stage dir for jerboa, NOT the original.
-;; The original jerboa dir has unpatched load-shared-object calls that would
-;; fail during compilation (no .so to dlopen in static builds).
-;; We set this globally so ALL compilation steps use the right paths.
-
-(define build-lib-dirs
-  (list (cons "lib" "lib")
-        (cons jerboa-stage jerboa-stage)))
-
-;; ========== Step 1: Compile jerboa boot modules from staged sources ==========
-
-(printf "~n[1/7] Compiling jerboa modules (patched, from stage)...~n")
-
-(define jerboa-boot-modules
-  '("jerboa/core" "jerboa/runtime"
-    "std/error" "std/format" "std/sort" "std/pregexp" "std/sugar"
-    "std/misc/string" "std/misc/list" "std/misc/alist" "std/misc/thread"
-    "std/misc/ports"
-    "std/foreign"
-    "std/os/path" "std/os/file-info"
-    "std/text/hex" "std/text/json"
-    "std/match2"
-    "std/crypto/native-rust"
-    "std/db/sqlite-native"
-    "std/gambit-compat"
-    "jerboa/ffi"
-    "jerboa/prelude/clean"))
-
-(parameterize ([compile-imported-libraries #t]
-               [optimize-level 2]
-               [generate-inspector-information #f]
-               [library-directories build-lib-dirs])
-  (for-each
-    (lambda (m)
-      (let ([sls (format "~a/~a.sls" jerboa-stage m)])
-        (when (file-exists? sls)
-          (printf "  Compiling ~a~n" m)
-          (compile-library sls))))
-    jerboa-boot-modules))
-
-;; ========== Step 2: Compile all secmon modules ==========
-
-(printf "~n[2/7] Compiling secmon modules...~n")
-
-(parameterize ([optimize-level 2]
-               [generate-inspector-information #f]
-               [compile-imported-libraries #t]
-               [library-directories build-lib-dirs])
-  ;; Obfuscate macro (needed by many modules — compile first)
-  (printf "  Compiling lib/secmon/stealth/obfuscate.sls~n")
-  (compile-library "lib/secmon/stealth/obfuscate.sls")
-
-  ;; Crypto modules (dependency order)
-  (for-each
-    (lambda (m)
-      (let ([path (format "lib/secmon/crypto/~a.sls" m)])
-        (printf "  Compiling ~a~n" path)
-        (compile-library path)))
-    '("keys" "ecies" "psk"))
-
-  ;; Monitor events (base types first)
-  (printf "  Compiling lib/secmon/monitor/events.sls~n")
-  (compile-library "lib/secmon/monitor/events.sls")
-  (printf "  Compiling lib/secmon/monitor/suspicious.sls~n")
-  (compile-library "lib/secmon/monitor/suspicious.sls")
-
-  ;; Platform
-  (for-each
-    (lambda (m)
-      (let ([path (format "lib/secmon/platform/~a.sls" m)])
-        (printf "  Compiling ~a~n" path)
-        (compile-library path)))
-    '("provider" "linux"))
-
-  ;; Buffer
-  (printf "  Compiling lib/secmon/buffer/ring.sls~n")
-  (compile-library "lib/secmon/buffer/ring.sls")
-
-  ;; Server
-  (for-each
-    (lambda (m)
-      (let ([path (format "lib/secmon/server/~a.sls" m)])
-        (printf "  Compiling ~a~n" path)
-        (compile-library path)))
-    '("protocol" "listener"))
-
-  ;; Config
-  (printf "  Compiling lib/secmon/config.sls~n")
-  (compile-library "lib/secmon/config.sls")
-
-  ;; Storage
-  (printf "  Compiling lib/secmon/storage/store.sls~n")
-  (compile-library "lib/secmon/storage/store.sls")
-
-  ;; All monitor modules
-  (for-each
-    (lambda (m)
-      (let ([path (format "lib/secmon/monitor/~a.sls" m)])
-        (printf "  Compiling ~a~n" path)
-        (compile-library path)))
-    '("process" "network" "files" "auth" "kernel" "cron"
-      "container" "dns" "rootkit" "persistence" "revshell"
-      "lateral" "logtamper" "webshell" "podman" "selinux"))
-
-  ;; Stealth modules
-  (for-each
-    (lambda (m)
-      (let ([path (format "lib/secmon/stealth/~a.sls" m)])
-        (printf "  Compiling ~a~n" path)
-        (compile-library path)))
-    '("anti-debug" "masquerade" "env-sanitize" "integrity" "init")))
-
-;; ========== Step 3: Compile agent program ==========
-
-(printf "~n[3/7] Compiling bin/agent.ss (optimize-level 3)...~n")
-
-(parameterize ([compile-imported-libraries #t]
-               [optimize-level 3]
-               [cp0-effort-limit 500]
-               [cp0-score-limit 50]
-               [cp0-outer-unroll-limit 1]
-               [commonization-level 4]
-               [enable-unsafe-application #t]
-               [enable-unsafe-variable-reference #t]
-               [enable-arithmetic-left-associative #t]
-               [debug-level 0]
-               [generate-inspector-information #f]
-               [library-directories build-lib-dirs])
-  (compile-program "bin/agent.ss"))
-
-;; ========== Step 4: Create libs-only boot file ==========
-
-(printf "~n[4/7] Creating boot file...~n")
-
-(define boot-libs
-  (append
-    ;; Jerboa runtime + stdlib (from STAGE dir — patched, no load-shared-object)
-    (map (lambda (m) (format "~a/~a.so" jerboa-stage m))
-      '("jerboa/core"
-        "jerboa/runtime"
-        "jerboa/ffi"
-        "jerboa/prelude/clean"
-        "std/error"
-        "std/format"
-        "std/sort"
-        "std/pregexp"
-        "std/sugar"
-        "std/match2"
-        "std/misc/string"
-        "std/misc/list"
-        "std/misc/alist"
-        "std/misc/thread"
-        "std/misc/ports"
-        "std/foreign"
-        "std/os/path"
-        "std/os/file-info"
-        "std/text/hex"
-        "std/text/json"
-        "std/gambit-compat"
-        "std/crypto/native-rust"
-        "std/db/sqlite-native"))
-    ;; Secmon modules (obfuscate first — many modules depend on it)
-    (list "lib/secmon/stealth/obfuscate.so")
-    (map (lambda (m) (format "lib/secmon/crypto/~a.so" m))
-      '("keys" "ecies" "psk"))
-    (list "lib/secmon/monitor/events.so"
-          "lib/secmon/monitor/suspicious.so")
-    (map (lambda (m) (format "lib/secmon/platform/~a.so" m))
-      '("provider" "linux"))
-    (list "lib/secmon/buffer/ring.so"
-          "lib/secmon/server/protocol.so"
-          "lib/secmon/server/listener.so"
-          "lib/secmon/config.so"
-          "lib/secmon/storage/store.so")
-    (map (lambda (m) (format "lib/secmon/monitor/~a.so" m))
-      '("process" "network" "files" "auth" "kernel" "cron"
-        "container" "dns" "rootkit" "persistence" "revshell"
-        "lateral" "logtamper" "webshell" "podman" "selinux"))
-    (map (lambda (m) (format "lib/secmon/stealth/~a.so" m))
-      '("anti-debug" "masquerade" "env-sanitize" "integrity" "init"))))
-
-;; Verify all .so files exist
-(for-each
-  (lambda (so)
-    (unless (file-exists? so)
-      (printf "ERROR: Missing boot file dependency: ~a~n" so)
-      (exit 1)))
-  boot-libs)
-
-(apply make-boot-file "secmon-agent.boot" '("scheme" "petite") boot-libs)
-(printf "  Created secmon-agent.boot~n")
-
-;; ========== Step 5: Generate C code ==========
-
-(printf "~n[5/7] Generating C code with embedded boot files + FFI symbols...~n")
-
-(define musl-lib-dir (musl-chez-lib-dir))
-(define petite-boot-path (format "~a/petite.boot" musl-lib-dir))
-(define scheme-boot-path (format "~a/scheme.boot" musl-lib-dir))
-
-;; Generate the C source
-(call-with-output-file "secmon-program.c"
-  (lambda (out)
-    ;; Headers — _GNU_SOURCE must come before any includes for memfd_create
-    (display "#define _GNU_SOURCE\n" out)
-    (display "#include \"scheme.h\"\n" out)
-    (display "#include <string.h>\n" out)
-    (display "#include <stdlib.h>\n" out)
-    (display "#include <stdio.h>\n" out)
-    (display "#include <signal.h>\n" out)
-    (display "#include <unistd.h>\n" out)
-    (display "#include <errno.h>\n" out)
-    (display "#include <fcntl.h>\n" out)
-    (display "#include <sys/types.h>\n" out)
-    (display "#include <sys/socket.h>\n" out)
-    (display "#include <sys/wait.h>\n" out)
-    (display "#include <sys/mman.h>\n" out)
-    (display "#include <sys/prctl.h>\n" out)
-    (display "#include <sys/ptrace.h>\n" out)
-    (display "#include <netinet/in.h>\n" out)
-    (display "#include <arpa/inet.h>\n\n" out)
-
-    ;; Embed boot files as C arrays
-    (display (file->c-array petite-boot-path "petite_boot") out)
-    (newline out)
-    (display (file->c-array scheme-boot-path "scheme_boot") out)
-    (newline out)
-    (display (file->c-array "secmon-agent.boot" "app_boot") out)
-    (newline out)
-
-    ;; Embed the compiled program
-    (display (file->c-array "bin/agent.so" "program_so") out)
-    (newline out)
-
-    ;; Extern declarations for Rust native library symbols
-    (display "/* Rust native library symbols (libjerboa_native.a) */\n" out)
-    (for-each
-      (lambda (sym)
-        (fprintf out "extern int ~a();\n" sym))
-      '("jerboa_last_error"
-        "jerboa_sha1" "jerboa_sha256" "jerboa_sha384" "jerboa_sha512"
-        "jerboa_random_bytes"
-        "jerboa_hmac_sha256" "jerboa_hmac_sha256_verify"
-        "jerboa_timing_safe_equal"
-        "jerboa_aead_seal" "jerboa_aead_open"
-        "jerboa_chacha20_seal" "jerboa_chacha20_open"
-        "jerboa_scrypt"
-        "jerboa_pbkdf2_derive" "jerboa_pbkdf2_verify"
-        "jerboa_x25519_generate_keypair"
-        "jerboa_x25519_public_from_private"
-        "jerboa_x25519_diffie_hellman"
-        "jerboa_hkdf_sha256"
-        ;; SQLite
-        "jerboa_sqlite_open" "jerboa_sqlite_close" "jerboa_sqlite_exec"
-        "jerboa_sqlite_prepare" "jerboa_sqlite_finalize" "jerboa_sqlite_reset"
-        "jerboa_sqlite_bind_int" "jerboa_sqlite_bind_double"
-        "jerboa_sqlite_bind_text" "jerboa_sqlite_bind_blob"
-        "jerboa_sqlite_bind_null"
-        "jerboa_sqlite_step"
-        "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_sqlite_last_insert_rowid" "jerboa_sqlite_changes"
-        "jerboa_sqlite_errmsg"))
-    (newline out)
-
-    ;; FFI symbol registration function
-    (display "static void register_ffi_symbols(void) {\n" out)
-    ;; libc symbols (needed by secmon monitors and jerboa std)
-    (for-each
-      (lambda (sym)
-        (fprintf out "    Sforeign_symbol(\"~a\", (void*)~a);\n" sym sym))
-      '("socket" "connect" "setsockopt" "bind" "listen" "accept"
-        "fork" "ptrace" "waitpid" "_exit" "kill"
-        "getpid" "getppid" "prctl" "mlockall"
-        "readlink" "unsetenv" "access"
-        "__errno_location"
-        "read" "write" "close"))
-    ;; Rust native symbols
-    (for-each
-      (lambda (sym)
-        (fprintf out "    Sforeign_symbol(\"~a\", (void*)~a);\n" sym sym))
-      '("jerboa_last_error"
-        "jerboa_sha1" "jerboa_sha256" "jerboa_sha384" "jerboa_sha512"
-        "jerboa_random_bytes"
-        "jerboa_hmac_sha256" "jerboa_hmac_sha256_verify"
-        "jerboa_timing_safe_equal"
-        "jerboa_aead_seal" "jerboa_aead_open"
-        "jerboa_chacha20_seal" "jerboa_chacha20_open"
-        "jerboa_scrypt"
-        "jerboa_pbkdf2_derive" "jerboa_pbkdf2_verify"
-        "jerboa_x25519_generate_keypair"
-        "jerboa_x25519_public_from_private"
-        "jerboa_x25519_diffie_hellman"
-        "jerboa_hkdf_sha256"
-        "jerboa_sqlite_open" "jerboa_sqlite_close" "jerboa_sqlite_exec"
-        "jerboa_sqlite_prepare" "jerboa_sqlite_finalize" "jerboa_sqlite_reset"
-        "jerboa_sqlite_bind_int" "jerboa_sqlite_bind_double"
-        "jerboa_sqlite_bind_text" "jerboa_sqlite_bind_blob"
-        "jerboa_sqlite_bind_null"
-        "jerboa_sqlite_step"
-        "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_sqlite_last_insert_rowid" "jerboa_sqlite_changes"
-        "jerboa_sqlite_errmsg"))
-    (display "}\n\n" out)
-
-    ;; dlopen/dlsym stubs — needed because Chez tries to use them
-    ;; even when all symbols are pre-registered
-    (display "/* dlopen/dlsym stubs for static musl builds */\n" out)
-    (display "void *dlopen(const char *file, int mode) {\n" out)
-    (display "    (void)file; (void)mode;\n" out)
-    (display "    return (void*)1; /* non-NULL = success */\n" out)
-    (display "}\n\n" out)
-
-    (display "void *dlsym(void *handle, const char *name) {\n" out)
-    (display "    (void)handle; (void)name;\n" out)
-    (display "    return NULL;\n" out)
-    (display "}\n\n" out)
-
-    (display "int dlclose(void *handle) {\n" out)
-    (display "    (void)handle;\n" out)
-    (display "    return 0;\n" out)
-    (display "}\n\n" out)
-
-    (display "char *dlerror(void) {\n" out)
-    (display "    return \"dlopen not supported in static build\";\n" out)
-    (display "}\n\n" out)
-
-    ;; _dl_find_object — referenced by libgcc_eh.a unwinding code (from Rust static lib)
-    ;; Not available in musl; stub returns failure (unwinding falls back to frame pointers)
-    (display "int _dl_find_object(void *a, void *b) { (void)a; (void)b; return -1; }\n\n" out)
-
-    ;; Main function: bootstrap Chez and run the agent
-    ;; Uses Sscheme_script for threading support (unlike Sscheme_program
-    ;; which evaluates at heap build time before threads are ready)
-    (display "int main(int argc, const char *argv[]) {\n" out)
-    (display "    Sscheme_init(NULL);\n" out)
-    (display "    Sregister_boot_file_bytes(\"petite\", petite_boot, petite_boot_len);\n" out)
-    (display "    Sregister_boot_file_bytes(\"scheme\", scheme_boot, scheme_boot_len);\n" out)
-    (display "    Sregister_boot_file_bytes(\"secmon\", app_boot, app_boot_len);\n" out)
-    (display "    Sbuild_heap(NULL, NULL);\n\n" out)
-    (display "    /* Register FFI symbols after heap is built */\n" out)
-    (display "    register_ffi_symbols();\n\n" out)
-    ;; Write program .so to a temp memfd and load via Sscheme_script
-    ;; This allows the program to run with threading support
-    (display "    /* Load program via memfd for threading support */\n" out)
-    (display "    int fd = memfd_create(\"secmon\", 1 /* MFD_CLOEXEC */);\n" out)
-    (display "    if (fd < 0) { fd = memfd_create(\"secmon\", 0); }\n" out)
-    (display "    if (fd >= 0) {\n" out)
-    (display "        write(fd, program_so, program_so_len);\n" out)
-    (display "        char fdpath[64];\n" out)
-    (display "        snprintf(fdpath, sizeof(fdpath), \"/proc/self/fd/%d\", fd);\n" out)
-    (display "        const char *script_args[] = { argv[0] };\n" out)
-    (display "        Sscheme_script(fdpath, 1, script_args);\n" out)
-    (display "        close(fd);\n" out)
-    (display "    } else {\n" out)
-    (display "        /* Fallback: write to /tmp */\n" out)
-    (display "        FILE *f = fopen(\"/tmp/.secmon-program.so\", \"wb\");\n" out)
-    (display "        if (f) {\n" out)
-    (display "            fwrite(program_so, 1, program_so_len, f);\n" out)
-    (display "            fclose(f);\n" out)
-    (display "            const char *script_args[] = { argv[0] };\n" out)
-    (display "            Sscheme_script(\"/tmp/.secmon-program.so\", 1, script_args);\n" out)
-    (display "            unlink(\"/tmp/.secmon-program.so\");\n" out)
-    (display "        }\n" out)
-    (display "    }\n\n" out)
-    (display "    Sscheme_deinit();\n" out)
-    (display "    return 0;\n" out)
-    (display "}\n" out))
-  'replace)
-
-(printf "  Generated secmon-program.c~n")
-
-;; ========== Step 6: Compile C with musl-gcc ==========
-
-(printf "~n[6/7] Compiling C with musl-gcc...~n")
-
-(define gcc (musl-gcc-path))
-(define scheme-h-dir musl-lib-dir)
-
-(let ([cmd (format "~a -c -O2 -I'~a' -o secmon-program.o secmon-program.c" gcc scheme-h-dir)])
-  (printf "  ~a~n" cmd)
-  (unless (= (system cmd) 0)
-    (printf "ERROR: C compilation failed~n")
-    (exit 1)))
-
-;; ========== Step 7: Link static binary ==========
-
-(printf "~n[7/7] Linking static binary...~n")
-
-(define main-o (format "~a/main.o" musl-lib-dir))
-(define libkernel (format "~a/libkernel.a" musl-lib-dir))
-(define libz (let ([p (format "~a/libz.a" musl-lib-dir)])
-               (if (file-exists? p) p #f)))
-(define liblz4 (let ([p (format "~a/liblz4.a" musl-lib-dir)])
-                 (if (file-exists? p) p #f)))
-
-(let* ([libs (filter values
-               (list libkernel libz liblz4 native-lib-path))]
-       [lib-flags (apply string-append
-                    (map (lambda (l) (format " '~a'" l)) libs))]
-       [cmd (format "~a -static secmon-program.o~a -lm -lrt -lpthread -o secmon-agent"
-                    gcc lib-flags)])
-  (printf "  ~a~n" cmd)
-  (unless (= (system cmd) 0)
-    (printf "ERROR: Linking failed~n")
-    (exit 1)))
-
-;; Strip the binary
-(printf "~n  Stripping...~n")
-(system "strip secmon-agent")
-
-;; Generate integrity hash
-(printf "  Generating SHA256 hash...~n")
-(system "sha256sum secmon-agent > secmon-agent.sha256")
-
-;; Verify
-(printf "~n=== Build complete ===~n")
-(system "ls -lh secmon-agent")
-(system "file secmon-agent")
-
-;; Cleanup
-(printf "~n  Cleaning up staging directory...~n")
-(system (format "rm -rf '~a'" jerboa-stage))
-(system "rm -f secmon-program.c secmon-program.o secmon-agent.boot")
-
-(printf "~nDone.~n")
diff --git a/build-secmon-static.sh b/build-secmon-static.sh
deleted file mode 100755
index 83e54f2..0000000
--- a/build-secmon-static.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-# build-secmon-static.sh — Build static secmon-agent binary on FreeBSD
-set -eu
-
-JERBOA_LIB="${JERBOA_DIR:-$HOME/jerboa/lib}"
-NATIVE_RS="${NATIVE_RS:-$HOME/jerboa/jerboa-native-rs/target/release}"
-
-echo "=== Building secmon-agent (FreeBSD static) ==="
-echo "  Jerboa lib: $JERBOA_LIB"
-echo "  Native RS:  $NATIVE_RS"
-echo ""
-
-export LD_LIBRARY_PATH="${NATIVE_RS}:${LD_LIBRARY_PATH:-}"
-
-scheme -q --libdirs "lib:${JERBOA_LIB}" < build-secmon-static.ss
-
-echo ""
-echo "=== Build complete ==="
-if [ -f secmon-agent ]; then
-    echo "  Size: $(ls -lh secmon-agent | awk '{print $5}')"
-    file secmon-agent
-fi
diff --git a/build-secmon-static.ss b/build-secmon-static.ss
deleted file mode 100644
index 64048b7..0000000
--- a/build-secmon-static.ss
+++ /dev/null
@@ -1,490 +0,0 @@
-#!chezscheme
-;;; build-secmon-static.ss — Build a fully static secmon-agent binary on FreeBSD
-;;;
-;;; Usage: scheme -q --libdirs lib:<jerboa-lib> < build-secmon-static.ss
-;;;
-;;; This script:
-;;;   1. Stages jerboa modules with load-shared-object patched out
-;;;   2. Compiles all jerboa + secmon modules from staged/patched sources
-;;;   3. Creates boot file + optimized program .so
-;;;   4. Generates C files with embedded boot data + FFI symbol registration