AuditeDB
the db that listens. Powered by the Elastik L5 Engine. Bytes at paths + versions + HMAC audit chain
- four-tier auth + change subscriptions. Five verbs (read · replace · append · delete · subscribe), one SQLite store.
Two ways to use it:
- Binary (
elastik-core): HTTP + CoAP server withcurlas the control surface. This skill covers this mode. - Library (
elastik_corecrate,unstable-enginefeature): embed the protocol-neutralEnginedirectly in a Rust process; bring your own wire shape. In minimal library-only builds it has no HTTP, no CoAP, no env vars, no sockets — see the crate-level rustdoc andcore/src/engine.rsfor the public surface.
AuditeDB (the elastik-core binary) is a flat HTTP key-value store with an introspection
plane. The key prefix is policy.
home/ etc/ lib/ boot/ usr/ var/ -> durable SQLite-backed values
tmp/ dev/ sys/ -> transient memory-backed values
proc/ -> generated introspection
Worlds are not files. A world is one HTTP key-value entry: a canonical key, body bytes, HTTP metadata, and an ETag/version identity. Slashes in the key are naming convention, not directory structure.
The user-facing operation set:
GET read body
HEAD read metadata
PUT replace world
POST append (where supported)
DELETE remove world
LISTEN subscribe to events (wire = GET /listen/<pattern>, SSE)
Disk contract: paths are authority boundaries; status codes must tell the truth; durable mutation verifies before write; auth, audit, proc, and static serving are shared primitives, not adapter-local reinventions.
Curl is the portable control surface. The browser is the HTML client. ETags
are version clocks. /proc/* is the status surface.
First moves
- If no AuditeDB instance is running, deploy one first. Startup verifies all
durable audit chains before the process listens; see
references/deployment.mdif boot fails with a chain-broken error. - Set
ELASTIK_BASE, usuallyhttp://127.0.0.1:3105. - Probe with
curl -i "$ELASTIK_BASE/proc/version". No read token needed. - The bare root
GET /returns a hint, e.g.elastik-core <version> (rust)\ntry: curl /proc/worlds\n. - Use HTTP primitives directly: method, path, headers, body, status.
- Do not invent JSON envelopes for core world operations.
- When serving UI, PUT HTML/CSS/JS as worlds.
Curl cookbook:
scripts/curl-cases.sh: runnable bash examples for probe, PUT, HEAD, GET, Range, CAS, audit verify, and listen.scripts/curl-cases.ps1: PowerShell version for Windows users without a working bash.
Canonical key
HTTP wire path carries a leading slash; the HTTP adapter canonicalises it into an Engine world path.
HTTP wire: /home/a /tmp/x
Engine canonical: home/a tmp/x
The canonical form is deliberately MQTT-like: no leading slash, slash-separated hierarchy, no query string. The MQTT adapter projects client topics onto the same validated world grammar instead of adding a second naming system.
Unprefixed paths fall under the bare-path rule and are prepended with home/:
/log/foo -> home/log/foo
/jobs/x -> home/jobs/x
/channel/me -> home/channel/me
Reserved roots (cannot be written as the world itself, only as a prefix):
home tmp dev sys proc etc lib boot usr var var/log
The entire proc/* subtree is reserved for generated introspection and is not
user-writable.
Reference routing
Load only the reference needed for the task:
references/deployment.md: start AuditeDB, configure environment variables, bind address, tokens, data path, and safety checks.references/flexible-deployment.md: choose local, LAN, overlay, NAS-backed, or public-proxy deployment shapes without changing the HTTP world model.references/http-worlds.md: HTTP method semantics, namespace policy, path validation, header policy, ETag/CAS,/proc/*,/listen/*SSE, browser caching, and safe curl patterns.references/navigation.md: list, find, inspect, and search worlds with/proc/worldsand text filters; thels/find/treesubstitute.references/projection-theorem.md: the maximum-common-denominator rule for deciding when an HTTP subsystem should reuse AuditeDB instead of building a parallel control plane.references/ui-worlds.md: flat HTML world topology, no-JS fallbacks, HTML/CSS/JS splitting, and X-Meta-Summary conventions.references/async-client.md: synchronous storage vs asynchronous workflows; JavaScript and Python client patterns, SSE, polling, sidecar daemons.references/e2e-auth.md: end-to-end encryption with self-signed certificates; using AuditeDB as a zero-knowledge relay between client and sidecar.
Deploy workflow
- Pick a data directory with
ELASTIK_DATA. - Generate
ELASTIK_KEY. - Decide tokens: read, write, approve.
- Start the
elastik-coreprocess from source, installed binary, or Python package. - Verify
/proc/version. - PUT a small test world and HEAD it.
Use workflow
When publishing a file into AuditeDB:
- Choose the world path explicitly. Use
home/(or another reserved prefix) rather than relying on bare-path canonicalisation, so the key is obvious. - Pick an accurate
Content-Type. - Add
Content-Languagefor human-readable pages. - Add
X-Meta-Summaryonly when custom metadata is enabled withELASTIK_PERSIST_HEADERS=x-meta-*. - Use
Cache-Control: no-cachefor mutable HTML pages. - PUT with the write token from the environment, never hardcode tokens.
- Verify with
HEAD(orcurl -I).
Token gates by namespace:
write token home/* tmp/* dev/* sys/* var/* (non-log)
approve token etc/* lib/* boot/* usr/* var/log/* + all DELETE
read token reads (when configured)
public /proc/version, root /
The PUT below illustrates the typical write shape. X-Meta-Summary only
round-trips when the instance is started with ELASTIK_PERSIST_HEADERS=x-meta-*;
otherwise omit it or treat it as non-persistent write-time advice.
export ELASTIK_BASE="http://127.0.0.1:3105"
export ELASTIK_WORLD="/home/report.html"
export ELASTIK_WRITE_TOKEN="$TOKEN"
curl -i -X PUT "$ELASTIK_BASE$ELASTIK_WORLD" \
-H "Authorization: Bearer $ELASTIK_WRITE_TOKEN" \
-H "Content-Type: text/html; charset=utf-8" \
-H "Content-Language: en" \
-H "Cache-Control: no-cache" \
-H "X-Meta-Summary: Report stored as an AuditeDB world." \
--data-binary @report.html
Status triage
401 missing or wrong Authorization Bearer token
403 token tier too low for this namespace
404 world missing or wrong namespace
412 stale If-Match ETag (CAS lost a race); re-read then retry
413 body exceeds ELASTIK_MAX_WORLD_BYTES (64 MiB default)
416 Range starts past EOF
503 transient listen/SQLite busy condition; respect Retry-After when present
507 durable quota, memory quota, or filesystem full
UI workflow
For browser pages:
- Use a shallow topology. Split structure, presentation, and behaviour into sibling worlds.
- Let
/proc/worldsbe the source of truth for navigation or discovery. - Use plain text fetches when possible. Do not require JSON unless the page is intentionally a JSON tool.
- No-JS pages should use links, forms, tables, and
meta refresh. - Do not ship mock data as if it were real. If an endpoint does not exist, render an empty state.
Projection rule
If a user asks for a small HTTP gateway, PLC bridge, operator panel, static file server, metrics route, health route, version route, audit route, or auth gate, first ask whether it is just an AuditeDB world, proc surface, token gate, or HTML page.
AuditeDB is the maximum common denominator. Domain adapters should supply domain semantics; AuditeDB supplies the shared HTTP key-value store and control plane.
Browser reality
Use curl for bare-metal HTTP checks. Browsers are policy stacks.
- Firefox usually preserves
If-None-Matchand shows normal 304 behaviour. - Brave may strip
If-None-Matchto reduce ETag fingerprinting, producing 200 instead of 304. - Dillo does not execute JavaScript; use explicit no-JS pages instead of user-agent sniffing.
- Native
EventSourcecannot set theAuthorizationheader; if reads require a token, usefetch+ReadableStreamand parse SSE manually, or use the SDK'slisten().
Source: rangersui/Elastik — distributed by TomeVault.