Documentation · Reproduce the tests
From a clone to a mounted layer.
MoobFS is an experimental kernel module for LLM-agent memory stored as plain files. This guide builds the tools, boots the disposable Linux VM that runs every test (the frozen M1 image, the stacked layer over ext4, btrfs and XFS, and the POSIX-authorized QUERY) and explains what each marker proves and does not prove.
Never load moobfs.ko or moobfs_layer.ko on your host: the harness boots a QEMU guest, and that is the only supported way to run the modules. Nothing has been released. Read the project goal and the division of responsibilities →
1. Build and test the host tools
You need a C11 compiler, Make and Python 3 on Linux or macOS. Run from the repository root:
git clone https://github.com/studiomoob/llmoobfs.git
cd llmoobfs
make test
printf 'A shared memory.\n' > build/memory.txt
build/host/mkfs.moobfs build/demo.img \
alpha.txt=build/memory.txt beta.txt=build/memory.txt
build/host/fsck.moobfs build/demo.imgmake test runs the unit tests of the typed attribute encoding shared by the module and the tools, plus nine image tests with 15 malformed variants. The verifier emits JSON: look for different inode numbers referencing the same object and physical offset. The creator refuses to overwrite an existing image. fsck.moobfs validates; it does not repair.
Compiling on macOS or on any Linux host tests nothing about the kernel code. The Linux-only xattr tools (moobfs-attr, moobfs-check, moobfs-index) are built by make attr-tools and used inside the VM.
2. Run the native Linux suite
Start Docker, then run:
make vm-testThe harness builds a Debian image pinned by digest with kernel 6.12.111+deb13-amd64 and its headers, compiles both modules and the test binaries against them, and boots that exact kernel in QEMU (TCG, no KVM, no privileged container, no network in the guest). The guest mounts the M1 image, then runs the layer suite over sparse ext4, btrfs and XFS disks: mount contract, pass-through tests, typed attribute tools, index and QUERY against the oracle, two-user isolation with ACLs, three fsx seeds, and the acceptance block with git, WAL-mode SQLite, dm-log-writes power-loss replay and dm-flakey error injection.
The first run downloads the Debian base and kernel packages. Apple Silicon uses x86 CPU emulation and is noticeably slower. The QEMU phase is bounded by a 600-second timeout; the CI job allows 35 minutes. Measured wall-clock times are not recorded yet.
Environment setup, the suite's variables and how to add a test: docs/development.md. Every marker, with what it proves and does not prove: docs/testing.md.
3. Read the markers
A run is read from build/vm/console.log. Success markers are printed only after the checks they summarize; a failure prints exactly one MOOBFS_VM_FAIL: <step> and stops. A successful run ends with:
SHARED: inode=2/3 physical=12288 length=16384
MOUNTED_READ_TESTS_PASS
WRITABLE_MOUNT_REJECTED
MOOBFS_VM_PASS: shared extents, independent inodes, reads,
readonly, remount, 15 malformed images
LAYER_LOWER_PASS: ext4 reflink=no
LAYER_LOWER_PASS: btrfs reflink=yes
LAYER_LOWER_PASS: xfs reflink=yes
MOOBFS_ACCEPTANCE_PASS: git, sqlite wal, memory client,
dm-log-writes replay, dm-flakey
MOOBFS_LAYER_PASS: pass-through over ext4, btrfs and xfs; ...Long markers are printed on a single line. Expected noise that is not a failure: “Invalid argument” for the 15 malformed M1 images and the remount,rw attempt, the three invalid layer mounts at the start of the suite, and unsigned-module taint messages.
| Marker | Proves | Does not prove |
|---|---|---|
MOOBFS_VM_PASS | M1 regression: two inodes share one physical extent (FIEMAP), reads match the fixture, read-write mounts and 15 malformed images are refused, module unloads cleanly. | Anything about writes or other kernels; KASAN (the Debian kernel has none). |
LAYER_LOWER_PASS: <fs> | Over that lower filesystem: mount contract, pass-through behaviour with the same inode numbers and bytes visible below, typed attribute validation, index and QUERY equal to moobfs-index for ten predicates and after rename, directory rename, unlink, removexattr and remount, noindex and index_budget, two-user isolation with chmod and POSIX ACLs, idmapped and user-namespace mounts refused, a 5-second race of chmod/rename/unlink against QUERY, three fsx seeds, nolinks. | Full POSIX conformance (xfstests has not been run), performance, behaviour with the index budget exhausted on large trees, timing channels. |
MOOBFS_ACCEPTANCE_PASS | Over ext4: git (three commits, fsck --strict), SQLite WAL with a concurrent reader keeps 200 of 200 rows, the memory-client convention works, power-loss replay to each mark shows every synced memory whole, write errors reach the caller and the tree is clean afterwards. | The same over btrfs or XFS; crash consistency without the client's sync; read-error paths. |
MOOBFS_LAYER_PASS | The three LAYER_LOWER_PASS lines, acceptance, module unload and a clean dmesg scan. | KASAN/lockdep when printed by the Debian harness. |
| Evidence in build/vm/ | What it tells you |
|---|---|
console.log | Every marker, every failure, the dmesg tail on failure. |
environment.txt | Kernel, compiler, QEMU and package versions; SHA-256 of what was booted. |
kernel.config | The exact kernel configuration that ran. |
image-report.json | The fsck.moobfs report of the M1 fixture. |
Journal entries record each phase: 0014 (index and QUERY), 0015 (acceptance and the two layer bugs it found), 0020 (QUERY authorization). CI results are visible in the Actions runs.
4. KASAN, UBSAN and lockdep
The Debian kernel has no sanitizers. A second workflow builds upstream 6.12.112 with vm/kasan.config (KASAN, UBSAN bounds, PROVE_LOCKING and related debug options) under virtme-ng and runs the same vm/suite.sh; success is MOOBFS_KASAN_PASS with no BUG, WARNING, KASAN, UBSAN or lockdep line in dmesg. It runs weekly, on demand and on pull requests touching layer/ or vm/. This harness found the third kernel-side defect (an uninitialized lock on an early mount failure, journal 0016). Step-by-step local reproduction is in docs/development.md, section 6. It covers the layer suite, not the M1 module.
Know the boundary of the result
- One kernel series (Debian 6.12.111, upstream 6.12.112), x86-64, in a VM. Other kernels are unverified; kernel APIs are version-specific.
- Three lower filesystems; acceptance runs over ext4 only. xfstests has not been run;
fsxis the only POSIX-conformance exercise. - The index lives only in RAM, bounded by
index_budget(default 128 MiB), rebuilt at every mount; saturation on large trees is untested. QUERYis a conjunction of at most four attribute predicates; no OR, sorting, full-text or vector search. Authorization holds at query time (TOCTOU contract).- No performance, latency or memory measurement exists. No syzkaller, no threat-model document, no external audit.
- M1 limits: flat namespace, at most 128 files/objects and 64 KiB per object, printable ASCII names up to 63 bytes, read-only images that must stay unchanged while mounted; separate inodes may have separate cached pages.
What is delegated to the lower filesystem (journaling, reflink, dedupe, ACL evaluation) is not a property of MoobFS. See the architecture overview and the comparison.