Embedded Datalog micro-kernel

MaelysDatalog

Engine v0.1.0-alpha.1 · deterministic logic

I do not predict.
I organize the possible.

A bounded Datalog policy engine in pure C for systems where every decision must remain understandable, reproducible, and auditable.

  • C11portable C core
  • 0 heapduring policy solve
  • Fixed-pointdeterministic evaluation
  • WASMbrowser-ready runtime

[ DETERMINISTIC ]

bounded fixed-point evaluation

  • semi-naive evaluation
  • stratified negation
  • reproducible results

[ ZERO-MALLOC ]

bounded memory discipline

  • stack-bounded solver
  • no heap on hot path
  • single result allocation
Subtle binary and UTF-8 terminal portrait of Maelys in cyan, blue, violet, and magenta.
Understand · Connect · Reason · Reveal

[ AUDITABLE ]

every decision is attributable

  • SHA-256 policy identity
  • fail-closed loading
  • receipts & diagnostics

[ PORTABLE ]

embed in your runtime

  • C11 static library
  • Python & JavaScript
  • WASM / WASI
7,573lines of C and headers
0heap allocations during solve
SMALL1,024 EDB fact capacity
LARGE2,048 EDB fact capacity
Engine

What's inside

EVALUATOR

Semi-naive evaluation

Delta-driven iteration with IDB current/delta/merge windows. Derives only what changed — no redundant recomputation.

allow(R) :- safe_source(R), has_text(R).
PLANNER

Static join-order O(B²)

Greedy deterministic body planner with uint64_t masks. For semi-naive variants, the delta literal is the fixed root.

build_static_join_order(rule, delta_idx, order, &count)
NEGATION

Stratified negation

Iterative stratum assignment, frozen lower-stratum IDB windows, bsearch lookup. Negative cycles rejected at load time.

deny(R) :- request(R), not(approved(R)).
MEMORY

Zero-malloc hot path

Solver, lexer, and parser use bounded stack arrays only. One calloc for the solve result — nothing on the decision path.

_Static_assert(sizeof(solve_result_t) <= BOUND, "...");
IDENTITY

SHA-256 policy identity

Every policy gets a cryptographic fingerprint at load time. Receipts carry the hash — decisions are fully attributable.

maelys_sha256_hex(policy_src, src_len, ruleset->sha256);
SAFETY

Fail-closed by design

No policy means deny. Parse errors deny. Solver errors deny. Unbound variables in not() rejected statically.

int maelys_datalog_ruleset_has_allow_all(...) { return 0; }
Quick start

Embed in three steps

01Link the library
# Static library
clang -o myapp main.c \
  -Imaelys-dl/include \
  libmaelys_datalog.a
02Load a policy
maelys_datalog_manifest_load_ex(
  "policies/main.json",
  0,
  &policy_set,
  &diag
);
03Solve and query
maelys_datalog_solve_once(
  &ruleset, &edb, &result
);
// Query the decision
bool allow = query_solved(
  result, "allow", terms, 1
);

Try it in your browser

Write a Datalog policy, add EDB facts, and watch the engine derive decisions — no install required.

Open playground →