Core concepts#

h5i-db rests on a handful of ideas. Once they click, every command and API method is predictable.

The database is a directory#

A database is one directory on disk; there is no server. Inside it, each table owns immutable Parquet segments (the data), immutable JSON manifests (one per version), and a single small mutable file, HEAD, that names the current version:

market.db/
  FORMAT
  catalog/  snapshots/
  tables/<table-uuid>/
    HEAD                       # the only mutable file per table
    manifests/<seq>.json       # one immutable manifest per version
    segments/<uuid>.parquet    # immutable, time-sorted data

Everything except HEAD is write-once. That single fact is what makes backups a file copy, crash recovery trivial, and old versions permanently readable. See the Operations guide.

Versions: every write is a commit#

Every write (append, full write, range replace/delete, restore, compact) produces a new version: a manifest listing exactly which segments make up the table at that point, plus statistics, a commit timestamp, and your optional --note. Publishing a version is an atomic compare-and-swap on HEAD:

Reading old versions is O(1), because a version is a manifest read:

SELECT * FROM h5i('trades', 42);                        -- exact version
SELECT * FROM h5i('trades', '2026-07-01T00:00:00Z');    -- as of commit time

restore makes an old version current by committing a new version with the old contents: history only moves forward, and nothing is erased.

The time axis#

Declaring --time-column at table creation is the schema decision with the widest consequences:

Raw units

APIs that take numeric time arguments (plan ranges, gapfill step, ASOF tolerance, read(time_start=…)) use raw integers in the time column's unit. For the common timestamp[us] column, that is microseconds: 60_000_000 is one minute. The CLI's --start/--end accept RFC3339 strings and convert for you.

Snapshots#

A snapshot pins the current version of one or more tables under a name:

$ h5i-db snapshot create market.db eod-2026-07-18
SELECT * FROM h5i('trades', 'eod-2026-07-18');

A snapshot is a tiny checksummed JSON map {table → version}: O(1) to create, free to keep. Snapshots make backtests reproducible ("run against eod-2026-07-18, forever") and answer audit questions ("what did we know at close on date X?"). A table pinned by a snapshot cannot be dropped.

Previewable mutations: plan / apply#

Destructive operations (delete-range, replace-range) can run in two modes:

$ h5i-db delete-range market.db trades --start  --end  --plan
$ h5i-db plan show market.db trades <plan-id>
$ h5i-db plan apply market.db trades <plan-id>     # metadata-only swap

apply is cheap and atomic; it fails with a conflict if the table head moved after the plan was made (re-plan, don't retry). discard drops the staged segments; abandoned plans expire after 7 days. Every manifest records whether it was committed directly or via a reviewed plan (execution_mode and the plan hash), so the history doubles as an audit trail.

The mutation policy#

The policy is a per-database set of boolean gates deciding which operations may commit without a reviewed plan:

$ h5i-db policy set market.db direct_delete=false direct_write=false

Flags: direct_append, direct_write, direct_replace, direct_delete, direct_restore, direct_compact. With a flag off, the direct form of that operation fails with a policy_violation; the plan/apply flow still works. This is the recommended guardrail when agents or shared pipelines write to the database: the write path is identical, only the review requirement changes.

Queries and sessions#

SQL runs on DataFusion with h5i-db's storage underneath:

Resource guards are built in: row caps, timeouts, and memory budgets with disk spilling are available as CLI flags and sql() keyword arguments. They raise clean, typed errors instead of truncating silently.

Maintenance in one paragraph#

verify re-checks structural integrity (checksums, object existence; --deep re-reads every segment). compact rewrites accumulations of small segments into target-sized ones; it is a query-speed tool, not a space reclaimer. vacuum deletes unreachable objects (crashed-writer debris, discarded plans), dry run by default. Committed history is never deleted. Cadence and disk-usage math: Operations guide.

Read more#