File size: 14,707 Bytes
3b70664 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | #+TITLE: Nekomata Architecture
#+SUBTITLE: Five Layers of a Living Container Engine
#+AUTHOR: SnapKitty Systems
#+DATE: 2026
#+OPTIONS: toc:3 num:t
#+STARTUP: content
* Overview
Nekomata is a five-layer system. Each layer has a single responsibility
and a clean interface to the layer above and below it. The layers are
not microservices -- they are modules in a single Lisp image. The
interfaces are function calls, not HTTP requests.
#+BEGIN_EXAMPLE
Layer 5: LLM -> ASM (intent compilation)
|
Layer 4: Regex Math (formal policy algebra)
|
Layer 3: MoE Router (sparse expert activation)
|
Layer 2: Docker Socket (raw container operations)
|
Layer 1: Core Image (Lisp image-based persistence)
#+END_EXAMPLE
Data flows down (intent -> bytes) and up (telemetry -> fitness signal).
Control flows down (intent -> execution). State is horizontal (every
layer can read the Lisp image).
* Layer 1: Core (Lisp Image-Based Persistence)
** What It Is
The Core layer is a persistent Common Lisp image. All Nekomata state
lives here: running container registry, evolutionary population, hot-swap
log, snapshot store, policy tables.
When Nekomata starts, it restores from the last saved image. When it
stops, it saves the image. The image is not a database dump -- it is
the entire live Lisp process state, including compiled functions,
hash tables, and all in-memory data.
** Why This Matters
Most container engines lose all in-memory state on restart. They
reconstruct state by replaying events from a persistent log (etcd in
Kubernetes). This requires:
- A separate storage system (etcd)
- A reconciliation loop (the control plane rebuilds desired state)
- A startup latency (the control plane must catch up)
Nekomata eliminates all three by persisting the Lisp image directly.
The image is the database. Restart is image restore. There is no
reconciliation loop because there is no gap between desired state and
actual state -- the image already contains the actual state of the
previous session.
** Key Files
| File | Responsibility |
|------|----------------|
| =core/package.lisp= | Package and export declarations |
| =core/sexpr-infra.lisp= | Container spec DSL and =define-container= macro |
| =core/eval-loop.lisp= | REPL and infrastructure eval loop |
| =core/image-persist.lisp= | Lisp image save/restore |
| =core/conditions.lisp= | Condition hierarchy |
| =core/nekomata.lisp= | Daemon entry point and container registry |
** Core Data Model
#+BEGIN_SRC lisp
(defstruct container-spec
name
image
ports ; list of (host-port . container-port)
env ; alist of (KEY . "value")
volumes ; list of (host-path . container-path)
healthcheck ; lambda or nil
labels ; alist
restart-policy ; :always :on-failure :never
command) ; list of strings or nil
#+END_SRC
The =define-container= macro expands to a =defvar= that installs a
=container-spec= in the image and registers it in =*running-containers*=.
** Persistence Protocol
#+BEGIN_SRC lisp
;; Save
(save-nekod-image "/var/lib/nekod/nekod.image")
;; Restore
(restore-nekod-image "/var/lib/nekod/nekod.image")
#+END_SRC
Image saves happen: on clean shutdown, on SIGTERM, on explicit REPL
call, and after every evolutionary generation (configurable).
* Layer 2: Docker (Raw Socket, No Abstraction Layer)
** What It Is
The Docker layer communicates with the Docker daemon over a Unix domain
socket using raw HTTP/1.1 requests. There is no Docker SDK dependency.
There are no generated client bindings. There is a function that writes
bytes to a socket and a function that reads bytes from a socket.
** Why No Abstraction Layer
Every Docker SDK (Python dockerpy, Go docker/client, Java docker-java)
wraps the same HTTP API in a language-specific object model. This adds:
- Dependency chains (transitive dependencies on JSON parsers, HTTP
clients, TLS libraries)
- Version coupling (the SDK version must match the Docker API version)
- Abstraction leakage (the SDK exposes Docker's internal concepts
without the option to hide them)
Nekomata talks to Docker the same way curl does: raw TCP, HTTP/1.1
framing, JSON bodies assembled by =format=. This means zero dependencies
beyond a working Lisp and a running Docker daemon.
** Key Files
| File | Responsibility |
|------|----------------|
| =docker/unix-sock.lisp= | Raw Unix socket I/O |
| =docker/protocol.lisp= | HTTP/1.1 request/response framing |
| =docker/container.lisp= | Container lifecycle (create/start/stop/kill) |
| =docker/image.lisp= | Image pull and inspect |
| =docker/network.lisp= | Network create/connect/disconnect |
| =docker/volume.lisp= | Volume create/mount/remove |
| =docker/inspect.lisp= | Container state and stats polling |
** API Surface
#+BEGIN_SRC lisp
;; The full public interface of the Docker layer
(docker-get "/containers/json") ; list containers
(docker-post "/containers/create" body-json) ; create container
(start-container id) ; POST /containers/{id}/start
(stop-container id) ; POST /containers/{id}/stop
(kill-container id) ; POST /containers/{id}/kill
(inspect-container id) ; GET /containers/{id}/json
#+END_SRC
All functions return parsed JSON as Lisp association lists.
* Layer 3: MoE Router (Sparse Expert Activation)
** What It Is
The MoE (Mixture of Experts) router matches an infrastructure intent
to the minimal set of expert modules required to handle it. Experts are
Common Lisp functions registered in a routing table with capability
descriptors.
** Architecture
#+BEGIN_EXAMPLE
Intent string
|
[Tokenizer] -> token list with intent classes
|
[Router] -> score each expert against token list
|
[Threshold] -> keep experts with score > 0.5
|
[Dispatch] -> call each activated expert with the intent AST
|
[Aggregate] -> merge expert outputs into a single action
#+END_EXAMPLE
** Expert Registration
#+BEGIN_SRC lisp
(register-expert :placement
:capabilities '(:schedule :place :deploy :run)
:weight 1.0
:handler #'placement-expert)
(register-expert :routing
:capabilities '(:route :traffic :proxy :forward)
:weight 0.9
:handler #'routing-expert)
#+END_SRC
** Sparse Activation
Given N registered experts and intent I:
1. Compute score(e, I) for all e in E using token overlap + semantic
similarity against capability keywords
2. Activate A = {e : score(e, I) > threshold}
3. |A| is typically 1-2 for most intents, never all of E
This is the same sparsity property as a sparse MoE language model.
Only the relevant experts burn compute for each token (intent).
** Key Files
| File | Responsibility |
|------|----------------|
| =moe/router.lisp= | Expert registry and routing algorithm |
| =moe/sparse-activate.lisp= | Scoring and threshold gating |
| =moe/experts/= | Directory of expert module implementations |
* Layer 4: Regex Math (Formal Pattern Algebra)
** What It Is
The regex-math layer implements a Kleene algebra over container
identity strings, port patterns, and operation codes. This algebra
is the formal policy language for Nekomata.
** Kleene Algebra Primitives
The algebra has five operations:
- =re-literal= :: match a literal string
- =re-concat= :: sequential composition (A then B)
- =re-union= :: disjunction (A or B)
- =re-star= :: Kleene star (A zero or more times)
- =re-not= :: complement (everything that is not A)
These compose to express any regular policy:
#+BEGIN_SRC lisp
;; Allow traffic from any api-* container to db-* on ports 5432-5435
(define-policy db-access
:from (re-concat (re-literal "api-") (re-star re-any))
:to (re-concat (re-literal "db-") (re-star re-any))
:port (re-union (re-literal "5432") (re-literal "5433")
(re-literal "5434") (re-literal "5435")))
#+END_SRC
** Formal Properties
Because the policy language is a Kleene algebra:
1. *Equivalence checking*: Two policies P1 and P2 are equivalent iff
their DFA representations accept the same language. Decidable in
O(n^2 * m) where n, m are state counts.
2. *Subsumption*: P1 subsumes P2 iff L(P2) ⊆ L(P1). Check by
computing L(P2) \ L(P1) and verifying it is empty.
3. *Conflict detection*: Policies P_allow and P_deny conflict iff
L(P_allow) ∩ L(P_deny) ≠ ∅. Compute the intersection NFA and
check emptiness.
** Key Files
| File | Responsibility |
|------|----------------|
| =regex-math/= | Kleene algebra engine, NFA/DFA, policy compiler |
* Layer 5: LLM to ASM (Intent Compilation)
** What It Is
The llm2asm layer is the compilation pipeline from natural language
intent to raw machine code bytes. It is the outermost interface of
Nekomata: the point at which human language enters the system and
machine instructions exit.
** Compilation Pipeline
#+BEGIN_EXAMPLE
"deploy the API server"
|
[Tokenizer] tokenize-intent
-> list of intent-token structs
|
[AST Extractor] extract-ast
-> infra-ast with type :place, target "API"
|
[Constraint Builder] extract-constraints-from-tokens
-> list of constraint structs
|
[Code Generator] codegen
-> raw x86-64 or ARM64 bytes
|
[Verifier] verify-bytes
-> check: ends with RET, valid prologue, no
orphan REX prefixes
|
[JIT Linker] jit-link
-> function pointer in executable memory
#+END_EXAMPLE
** Intent Types
Five intent types map to five kernel primitives:
| Intent Type | Trigger Words | Kernel Primitive |
|-------------|---------------|------------------|
| =:place= | PLACE SCHEDULE DEPLOY RUN | ADD (scheduling arithmetic) |
| =:route= | ROUTE TRAFFIC PROXY FORWARD | XOR (packet classification) |
| =:scale= | SCALE REPLICATE EXPAND SHRINK | LOOP (replica iteration) |
| =:heal= | HEAL RESTART RECOVER FIX | MEMCPY (state snapshot) |
| =:secure= | SECURE ISOLATE LOCK PROTECT | MEMSET (zero-fill) |
** Backend Architecture
The codegen layer has two backends:
| Backend | File | Target |
|---------|------|--------|
| x86-64 | =llm2asm/backends/x86-64.lisp= | AMD64 / Intel 64-bit |
| ARM64 | =llm2asm/backends/arm64.lisp= | Apple Silicon / Graviton |
Backends share the same AST input. The same intent compiles to
native bytes for both architectures. Backend selection is automatic
based on the detected host architecture.
** Formal Verification
Before any generated byte sequence is JIT-linked, it passes through
=verify-bytes=:
#+BEGIN_SRC lisp
;; Checks:
;; 1. Non-empty sequence
;; 2. Terminates with RET (0xC3 on x86-64, 0xd65f03c0 on ARM64)
;; 3. Valid first byte (prologue or known REX prefix)
;; 4. No orphan REX prefixes (each REX must precede a valid instruction)
(verify-bytes generated-bytes) ; => (values t "ok") or (values nil reason)
#+END_SRC
** Key Files
| File | Responsibility |
|------|----------------|
| =llm2asm/tokenizer.lisp= | Intent tokenization and kernel map |
| =llm2asm/ast-extract.lisp= | AST extraction from token stream |
| =llm2asm/codegen.lisp= | Code generation: AST -> bytes |
| =llm2asm/verify.lisp= | Formal byte sequence verification |
| =llm2asm/jit-link.lisp= | JIT linking via mmap/CFFI |
| =llm2asm/constraint-build.lisp= | Constraint algebra and extraction |
| =llm2asm/backends/x86-64.lisp= | Raw x86-64 instruction encoders |
| =llm2asm/backends/arm64.lisp= | Raw AArch64 instruction encoders |
* Self-Modification Layer (selfmod/)
The selfmod layer sits across all five layers. It provides:
** Hot-Swap (hot-swap.lisp)
Redefine any function in the running Nekomata process without
restarting. The old definition is preserved in =*hot-swap-log*= for
rollback. Thread-safe via =bt:with-lock-held=.
** State Capture (state-capture.lisp)
Snapshot the complete Nekomata runtime state: container registry,
evolutionary population, hot-swap log, generation counter. Snapshots
are serializable to S-expressions for WORM-sealed persistence.
** Evolutionary Optimization (gen-loop.lisp, evolve.lisp)
Run a genetic algorithm over the live container spec population.
Each generation:
1. Score all specs against runtime telemetry (fitness function)
2. Select survivors by tournament selection
3. Apply crossover and mutation
4. Replace the live population with the next generation
The scheduler keeps running throughout. Evolution is not a migration.
It is a continuous background optimization.
** Rollback (rollback.lisp)
Multi-level undo: function level (hot-swap log), state level
(snapshot store), generation level. The =with-rollback= macro
provides automatic rollback on error:
#+BEGIN_SRC lisp
(with-rollback ("before-risky-experiment")
(do-something-that-might-fail))
;; If an error signals, the checkpoint is automatically restored
#+END_SRC
* Data Flow Summary
#+BEGIN_EXAMPLE
User intent (NL string)
|
llm2asm/tokenizer [tokenize]
|
llm2asm/ast-extract [classify intent type]
|
llm2asm/constraint-build [extract resource constraints]
|
moe/router [activate relevant experts]
|
moe/experts/* [expert domain logic]
|
llm2asm/codegen [emit x86-64 / ARM64 bytes]
|
llm2asm/verify [formal safety check]
|
llm2asm/jit-link [map bytes as executable, get fn ptr]
|
docker/container [create/start via Unix socket]
|
selfmod/state-capture [snapshot new state]
|
selfmod/gen-loop [feed telemetry to evolution]
#+END_EXAMPLE
* System Requirements
- SBCL 2.3+ or CCL 1.12+ (any ANSI Common Lisp with UIOP)
- Docker daemon with Unix socket at =/var/run/docker.sock=
- CFFI (for production JIT mmap integration)
- Bordeaux-Threads (for hot-swap lock)
- Linux kernel 5.10+ or macOS 12+ (for mmap PROT_EXEC)
- x86-64 or ARM64 host (backends are host-architecture-specific)
* Build and Load
#+BEGIN_SRC shell
# Load the system
sbcl --load nekod.asd --eval "(asdf:load-system :nekod)"
# Start the daemon
sbcl --eval "(nekod:nekomata-main)"
# Or use the neko CLI
sbcl --script cli/neko.lisp run myapp.lisp
#+END_SRC
|