Skip to content

Releases: openglacier/core

v2.0.2

Choose a tag to compare

@github-actions github-actions released this 02 Nov 17:05

openglacier Core v2.0.2 — antaa palaa

Writes that no longer fail because of another collection.


Highlights

  • Fix : A write conflicts only with a commit that changed what it read or wrote, no longer with any commit at all.
  • Fix : A write refused for a conflict runs again by itself, up to five attempts.
  • Fix : No durable event is lost in silence: one that cannot be stored is said in the ogd log.

Storage and writes

In v2.0.0 and v2.0.1, a transaction was refused as soon as any other commit happened between its start and its
commit, whatever that commit touched, and nothing ran it again. The Core itself writes in the background: the event
outbox deletes each event once delivered, just after the operation that published it (app.create, file.write,
an import…). The next write of the same client could then fail with
storage transaction conflict: Glacier generation changed before commit: data.mapping.save right after
app.create, imports right after their file was written, two users writing at the same time.

  • Conflicts per collection. A transaction notes the collections it reads (get, scan, count) and those it
    writes. Another commit makes it conflict only if it changed one of them, created it or emptied it since the
    transaction's snapshot. A listing of all the collections counts as reading every one of them.
    • The collection a write reads its rows from is watched too, though its rows come through another snapshot
      (StorageTransaction::watch_collection).
    • A collection read only by a lookup is not watched: this is snapshot isolation, as in PostgreSQL's
      REPEATABLE READ.
    • A transaction whose writes were moved out of memory (spilled) also needs each collection it writes to be exactly
      as in its snapshot, not even compacted since.
    • The in-memory backend follows the same rule. Its commit now installs only the collections it wrote, instead of
      its whole copy of the store.
  • Refused writes run again. A set, delete, load, into, insert or a group of writes run together that
    the storage refuses for a conflict is run again whole, on the state the other commit left, after 5, 10, 20 and
    40 ms (plus a random part of as much). A refused write committed nothing and sent nothing. The fifth refusal is
    returned. Other errors are not run again.
  • Events. Storing a durable event in the outbox benefits from the same retries. One that still fails is
    reported in the ogd log (ogd events: the event … is lost), not only under OGD_DEBUG.

The conflict message now reads a collection of the transaction changed before commit.

Upgrading from 2.0.1

Nothing to do.


Full Changelog: v2.0.1...v2.0.2

Small core, long life.

v2.0.1

Choose a tag to compare

@github-actions github-actions released this 30 Oct 11:27

openglacier Core v2.0.1 — antaa palaa

Formulas in imports, a Fabric that welcomes every node, and a lighter build.


Highlights

  • Import formulas are expressions of the language: ht - pam, but also if, substr, concat, dates.
  • Every Core can join the Fabric with an identity issued by the Authority, not only the one that enrolled
    the Gateway.
  • Mail through Microsoft 365 and other servers that do not offer AUTH PLAIN.
  • ogd --version and --help answer instead of starting a daemon.
  • Fewer dependencies: the default build goes from 124 crates to 70, with no known vulnerability.

Import

  • A calculated column of a mapping may be an expression of OGML
    ({"type": "formula", "target", "expression", "transform"}); the sums of signed terms stay accepted.
    • The expression is parsed once: one that does not parse stops the import (formula of <target>: …).
    • Columns are read under their own name, or, when it is not a name of the language, lower case without accents
      and _ for the rest (Code article → code_article, 2025 → _2025).
    • A cell that reads as a number is a number (1 234,50, (10)), but a code written with leading zeros stays
      text (01, 010178); a workbook date is its epoch milliseconds.
    • The result is converted as the target field is (month, date, datetime, text under its format). A row where the
      expression fails gets null and a warning; the import goes on.
    • The Python worker refuses expressions with a clear message: use the native worker (native-import).
  • data.mapping.save replaces the active mapping of the same format and table (state: "replaced"), and
    data.analyze returns the newest mappings first: a format mapped again is recognised with its last mapping.

Fabric

  • A Core joining the Fabric with an identity issued by the Authority accepts the enrolled Gateway. It used to
    look the Gateway's Device up in its own store, where only the Core that enrolled it holds it, and refused it in a
    loop. A Core that does not know the Gateway now keeps it once it proves its key, and refuses another key or a
    revoked Device afterwards; a Core without a store checks the key at each connection.
  • The node channels run on websockets of the Core's own (RFC 6455, TLS by rustls with the webpki roots as
    before) instead of tungstenite. Nothing changes on the wire: same handshake, same limits (64 MiB a message,
    16 MiB a frame), pings answered and closes echoed. Tested through the Gateway with a 1 GB file both ways, byte for
    byte.

Mail

AUTH is negotiated from the server's EHLO reply (the one after STARTTLS): PLAIN when offered, else LOGIN
(inside TLS), else a clear mail.auth error naming what the server offers (XOAUTH2 only, or no AUTH at all).


ogd, glacierdb and ogcli

  • ogd and glacierdb answer --version (-V, -v, version) with their version and code name and --help
    (-h, -?, help) with their commands, and refuse any other argument (exit code 2). They used to start a
    daemon in the current directory, which could write its bootstrap/admin.ogid there.
  • data-worker is accepted only by builds with native-import.
  • The terminal workspace of ogcli --tui is drawn with crossterm alone; keys and behaviour are unchanged.

Builds

Build Crates in 2.0.0 Crates in 2.0.1
default 124 70
cli-tui 124 85
full 164 156

Distinct crates and versions of the normal dependencies on Linux (cargo tree -e normal), the Core included.

  • search-documents leaves the default build and stays in full: the default ogd searches values, files by
    path, plain text files and Apps, but no longer reads the text of PDF and office documents. Build with
    --features search-documents, or use og-core-full, to keep it.
  • ratatui and tungstenite are no longer dependencies. The text of PDF files is read by lopdf 0.46 itself instead
    of pdf-extract, which held lopdf at 0.42 and its unmaintained font parser ttf-parser (RUSTSEC-2026-0192).

Security

zstd 0.14.3 (zstd-safe 8.2) for RUSTSEC-2026-0391, -0398 and -0403 and the unsound advisories of
zstd-safe 7. sha1 0.11. ttf-parser (unmaintained, RUSTSEC-2026-0192) is gone with pdf-extract, and
clipboard-win 5.4.1, yanked, is now 5.4.3. cargo audit reports neither vulnerability nor warning.


Upgrading from 2.0.0

Replace the binaries; stores, backups, identities and Apps stay as they are. Two things to check:

  • if you rely on the text of PDF and office documents in place.search, run og-core-full or a build with
    search-documents;
  • mappings that use formula expressions need the native data worker (the default when native-import is
    compiled).

Full Changelog: v2.0.0...v2.0.1

Small core, long life.

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 14:44

openglacier Core v2.0.0 — antaa palaa, continued

Glacier 6 goes public, Places become searchable, and the Core learns to run a whole organisation.

openglacier Core v2.0.0 carries on the antaa palaa line opened by v1.0: same code name, same promise. The
architecture stays the one you can build on; what changes is how much of it is now in your hands.

The major version moves for one reason: the storage format changes. Every public 1.0.x build stored its
data with Glacier 5. v2.0.0 publishes Glacier 6, the column-segment store the Core has been developed and
tested on, and reads format 6 only. Upgrading is one backup and one restore (see Upgrading from 1.0.x).


Highlights

  • Glacier 6, a column-segment storage engine, now in the public tree.
  • Backups of their own: OGB2, columnar and compressed, with diffs, chains and full history.
  • Place search: place.search over values, files and Apps, including the text of PDF and office documents.
  • Native data import: CSV, text and Excel without Python, streamed batch by batch.
  • OGML without |: stages separated by line breaks or ;, and expressions directly in group and pivot.
  • A scheduler instead of rejections: light and heavy pools, a waiting queue, admission by learned memory peak.
  • Policies and pools: enrollment by policy token, usage accounting, enforced limits, App offers.
  • Durable machine access, mail, public Places on demand.
  • Base Apps read from a file, so a distribution can ship its own set.
  • New release archives: og-core-full and og-cli-tui, with build provenance attestations.

Glacier 6

Glacier is a column-segment store, on-disk format version 6. A store is a directory:

<store>/
  MANIFEST            live segments, deleted rows, field facts, at one generation
  0000000000000005.g6 immutable column segments, one collection each
  wal-00000007.log    commits after the manifest generation
  LOCK                held by the one process that has the store open
  • Rows are sorted by identifier and split into row groups of up to 65,536 rows, with one chunk per top-level
    field. Scalar leaves of object fields are stored as their own columns.
  • Each stream picks its smallest encoding: frame of reference and bit packing, sorted dictionaries, scaled
    decimals that stay bit-exact, string dictionaries.
  • Per-chunk statistics (kinds present, smallest and largest value) feed the planner, which uses them to prove
    expressions total and to skip row groups that leading filters drop.
  • Typed blocks decode straight into the query engine's batches: filters, groups, distinct, pivot and Top-N run on
    typed columns and dictionary codes instead of documents.

It is also stricter about what it accepts:

  • data without a manifest is refused;
  • the store is locked by one process;
  • corruption in the middle of the log is refused instead of being silently truncated;
  • segment chunks are verified against their checksum on first read;
  • a store of another format, or a manifest written by a newer ogd, is reported as such, not as corrupt data:
... is a Glacier store of format 5 (ogd 1.x): this ogd reads format 6 only

The format is documented in src/storage/backend/GLACIER.md.


Backups: OGB2, diffs and history

Backups now have a format of their own, independent of the storage files.

  • OGB2 writes each collection in blocks of 65,536 documents laid out by field (identifiers and integers as
    deltas, strings through a block dictionary, exact types kept), compressed with zstd. On a 6.2 M-document store,
    a backup went from 1.52 GB to 73.6 MB, and its restore from 54.8 s to 21.7 s. A store restored then backed up
    again gives the same bytes.
  • Diffs: backup.create with a parent writes only what changed since the parent. Restoring a diff
    restores its whole chain, which is found and checked before the store is touched. Diffs need the history
    (OGD_HISTORY=on) or the lighter backup journal (OGD_HISTORY=journal), which keeps the commits since the last
    full backup.
  • Full backups with history: backup.create {"history": true} writes the state, then the history of every
    collection and the timeline of commit times and authors. ogd restore-backup <backup.ogb> <new-store-directory>
    rebuilds that history offline, with its original generations, times and authors, so as of and history
    answer as they did on the source.
  • OGB1 backups written by 1.0.x are still read.

Place search

place.search finds what a Place holds by its words (feature search, in the default and full builds):

  • the distinct text values of its collections, with their row count;
  • its files and folders, by path;
  • its App instances and tables.

Accents, case, plurals and acronyms are folded, prefixes match, and a typo is accepted only when no entry holds
the word as typed; scores weigh rare words higher. Scope keys narrow a search: app:, collection:, field:,
folder:. A search reads only what the caller may read (visible Apps, row filters).

With search-documents (default and full), the text of files is searched too: plain text, PDF, spreadsheets
(xlsx, xls, ods) and office documents (docx, pptx, odt, odp), cut into passages of about 1,000 characters. A file
that cannot be read is still found by its name; files over 32 MB are not read.

The index is made of parts, one per source, each read again only when its collection or file changes: after a
first search of about a second on a large Place, the next ones answer in milliseconds.


Native data import

data.import no longer needs Python.

  • ogd data-worker (feature native-import, included in full) reads CSV, text and Excel files in a
    process of its own and answers the same protocol as the Python worker. When it is compiled, it is the worker;
    OG_DATA_WORKER=python asks for the Python one instead.
  • It reproduces the Python worker's fingerprints, separators, headers, column profiles and date rules, and goes
    further: UTF-16, workbooks recognised by their content, named Excel tables, several tables per sheet, merged
    cells and group headers. A doubtful date becomes null instead of stopping the whole import.
  • Imports are streamed batch by batch (5,000 rows or about 1 MB each): a file of any size goes through,
    and no step holds it whole. One million rows through a Gateway: 113 s and 1.39 GiB, where it took 9.85 GiB
    before.
  • The last step of an import, moving the staged rows into their collection, now stays within the query's memory.

OGML

Without |

A query that holds no top-level | may separate its stages with line breaks and ;, and reads as the
same stages:

on sales
where amount > 100
group
  by region
  sum amount as total
end
sort total desc
on sales; where amount > 100; count

| stays exactly as it was: a query holding one reads as before. A line break ends a stage when brackets are
balanced, the line does not end on a continuation, and the next line starts with a stage word or a directive of
its block. One style per query; errors give the line.

Also new

  • Expressions with an alias as compact group items, group keys and pivot rows and columns:
    on sales | group region, revenue - cost as margin sums the margin per region.
  • Functions: median, percentile, stddev, month_end, days_in, and half_even rounding.
  • Values of different kinds sort by kind instead of failing.
  • Materialized views follow the views they read, at any depth, and are computed again when one of them is
    redefined.

Running under load

  • Light and heavy pools with a waiting queue: queries wait for their turn instead of being rejected. Heavy
    queries are admitted by their learned memory peak rather than a fixed count; operators that cannot spill
    wait for released memory, and pivot cells now spill and merge back. On a 1 GB node, every level of the
    concurrent load campaign completes, with twice the throughput and no errors down to 256 MB.
  • Result cache of Place reads (OGD_RESULT_CACHE, on by default): rows are kept under the prepared text,
    the Place, the caller's access filters and the change tokens of everything the read touches, so they are never
    stale. Identical reads arriving together wait for one execution. Five simultaneous logins on a demo stack:
    32.2 s → 1.3 s.
  • OGD_QUERY_TRACE writes one JSON line per query.execute.
  • Node channels relay as soon as they can: an exchange through a Gateway channel takes 74 µs instead of
    27 ms, and 100 MiB move at 1,480 MiB/s instead of 266.

Policies and pools

A Core can now serve many organisations under explicit rules (OGD_ENROLLMENT_MODE=policy):

  • a pool is a client organisation; a policy belongs to a pool and carries optional limits, per-user
    limits, rights and an App selection;
  • identities enroll with a policy token (ogp_…, shown once, stored as a SHA-256);
  • usage is computed per Place, owner, policy and pool (usage.get, every OGD_USAGE_INTERVAL seconds);
  • limits are enforced: Places, storage (writes that add documents, imports and file writes are refused past
    the limit, while set and delete still pass), devices, public and external sharing;
  • Apps: a policy offers some Apps as included and others as add-ons; an instance whose App is no longer
    included turns read-only;
  • identities can be deactivated (identity.state.set), which frees their seat.

New operations: pool.*, policy.*, policy.token.*, identity.policy.set, identity.state.set,
usage.get. Without OGD_ENROLLMENT_MODE=policy, nothing changes.


Access

  • **Durable machine ...
Read more

v1.0.5

Choose a tag to compare

@github-actions github-actions released this 20 Oct 11:56

openglacier Core v1.0.5 — antaa palaa

Security update.

Dependencies updated after cargo audit. No change of behaviour; v1.0.4 stores and backups are used as they
are.

It is the last release before v2.0.0, which moves from Glacier 5 to Glacier 6 (upgrade through a backup).


Full Changelog: v1.0.4...v1.0.5

Small core, long life.

v1.0.4

Choose a tag to compare

@github-actions github-actions released this 10 Oct 14:17

openglacier Core v1.0.4 — antaa palaa

Time travel, views and windows: OGML grows up.

v1.0.4 gathers the work of the unpublished 1.0.3. Public 1.0.x builds keep storing their data with
Glacier 5; the column-segment store developed alongside arrives with v2.0.0.

Language

  • Past states and history: on c as of … reads a collection as it was, on c history reads its stored
    versions.
  • Views: define view and undefine view, versioned and read per Place. A view reads like a collection, as
    a source, a union branch or a lookup, with the caller's variables. Materialized views are kept per scope
    until a collection they read changes.
  • window: lag, lead, cumsum, first, last and row_number over ordered partitions.
  • fill adds the rows missing from a grid (fill month from 1 to 12 step 1 by region), so series have
    no holes.
  • Fiscal dates: fiscal_year, fiscal_month, fiscal_start and fiscal_end, for years that close at the end
    of any month.
  • let can hold the rows of a query, and takes defaults.
  • union branches and lookup stages run any pipeline; lookups match on prefixes; group collects values with
    list.
  • Sorting values of different kinds is refused with an error instead of stopping the daemon.

Engine

  • Filters move towards the source past stages that leave their fields and rows alone.
  • Comparisons, distinct, group, pivot and Top-N run on typed batches with a shared key table; Top-N keeps its
    rows in a heap.
  • Writes stream into one transaction behind a streamed read, and several writes can share one transaction.
  • Streaming responses are written in batches.
  • Every query stage is declared once, in a catalogue.

Apps

  • Apps can deliver standard views from their definitions.
  • An App opens only to the Place roles it lists.

Builds

  • Release builds align loops on 64 bytes, so performance no longer moves with unrelated changes of code
    layout.

Full Changelog: v1.0.2...v1.0.4

Small core, long life.

v1.0.2

Choose a tag to compare

@github-actions github-actions released this 30 Sep 15:23

openglacier Core v1.0.2 — antaa palaa

A faster query engine: typed batches, partial documents and smarter joins.

v1.0.2 is a performance release. Queries return the same rows; most of them do less work to get there.

Query engine

  • Typed batches: row-local stages, group, unwind and pivot cells run on batches of typed columns, with a
    typed group key and dense measure states.
  • Partial documents: a query decodes only the fields it reads; Top-N ranks on partial documents and hydrates
    the winners only.
  • Top-N is pushed through the stages that keep rows as they are.
  • Joins: a lookup on equality is served by a hash join, and a bounded lookup indexes only the joined rows
    it can match (semi-join).
  • Ordered scans stream from the resident primary index instead of sorting every entry; samples are drawn
    from the primary index.
  • Constant expressions are folded; row-local stages are compiled once; group measures fold from borrowed storage
    values; a same-collection union counts with one shared scan.
  • The memory governor reads available memory without sampling /proc.

Language

  • Several fields and expressions as pivot values.
  • \uXXXX escapes in strings.
  • null sorts like a missing field instead of failing.

Fixes

  • The connection queue.
  • A routing invariant violation answers an error instead of stopping the daemon.

Full Changelog: v1.0.1...v1.0.2

Small core, long life.

v1.0.1

Choose a tag to compare

@github-actions github-actions released this 25 Sep 13:43

openglacier Core v1.0.1 — antaa palaa

The Core as a library, one expression evaluator, and fixes.

Changes

  • openglacier-core is a library with the ogd and ogcli binaries on top: distributions such as
    GlacierDB build on it.
  • The llama.cpp common/chat bridge moves to a crate of its own, openglacier-llama-common-chat.
  • One expression evaluator for every stage, with its functions and bounded stages gathered in one place.
  • The daemon's query plumbing and the engine's virtual collections are smaller; shared helpers live in
    helpers.rs.

Fixes

  • Random bytes on Windows no longer read /dev/urandom.
  • A public Place behaves as expected on a Core without authentication.
  • A query ending in into is authorized on the collection it writes, and the collection it reads must be
    readable too.
  • The flow of rows between pipeline stages.

Full Changelog: v1.0.0...v1.0.1

Small core, long life.

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 20 Sep 10:52

openglacier Core v1.0.0 — antaa palaa

First stable release.

openglacier Core v1.0.0 carries the code name antaa palaa. It means one thing: the core architecture
is now stable enough to build on.

This milestone comes after an extended period of real-world use and hostile testing: continuous fuzzing,
sustained read/write workloads, failure injection, storage corruption and I/O failure testing, crash recovery,
backup and restore validation, and a large integration test suite.

It has also been exercised across architectures and generations of hardware, from the Raspberry Pi 3 and 4 to
the Odroid XU4 and a Fairphone 2. Resources are valuable.


In this release

  • Glacier, the native persistent storage engine (OGD_STORAGE=glacier); ogd still starts in memory when
    no storage is set, GlacierDB on Glacier.
  • One package name: the crate is openglacier-core, the binaries ogd and ogcli.
  • install.sh installs a release archive on Linux and macOS.
  • A default bootstrap password for a first local start, to be changed on any shared node.
  • Release builds for every target through cross, with one pinned image per target.
  • The code went through a 30-day consolidation pass: shared code staged, clippy clean, tests rewritten,
    dependencies audited.

Full Changelog: v0.80.2...v1.0.0

Small core, long life.

v0.80.2

Choose a tag to compare

@github-actions github-actions released this 09 Sep 08:12

openglacier Core v0.80.2

Native tool calling, GPU-aware local inference, and a much more deliberate Agent execution loop.

openglacier Core v0.80.2 deepens the local AI path introduced in v0.80.0.

The LLM runtime now integrates more directly with llama.cpp common/chat for tool-aware prompt rendering and response parsing, adds explicit CPU/CUDA device selection, exposes thinking policy, and can reuse prompt-prefix state across multi-step Agent runs.

The Agent also moves away from an ad-hoc model-output protocol toward structured tool definitions and native tool calls.

Database-oriented runs gain collection description, bounded evidence gathering, multiple read-only analysis queries, separate synthesis budgets, and more careful context management.


Highlights

Tool calling becomes a first-class LLM contract

llm.generate can now receive structured tool definitions and tool-choice policy.

The request model supports:

tools
toolChoice
messages[].toolCalls
messages[].toolCallId
cacheKey

and generation can emit structured:

toolCall

events alongside normal text.

The Agent no longer needs to instruct a model to manufacture a private JSON envelope for every tool invocation.


llama.cpp common/chat integration

v0.80.2 introduces a native bridge around the llama.cpp common/chat implementation.

The bridge is used to:

  • apply model chat templates;
  • pass structured tool definitions;
  • apply tool-choice policy;
  • preserve generation prompts;
  • expose stop conditions and parser metadata;
  • parse generated content;
  • extract native tool calls;
  • separate reasoning content when supported.

Conceptually:

OpenGlacier messages + tools
          │
          ▼
llama.cpp common/chat
          │
          ▼
model-specific prompt
          │
          ▼
generation
          │
          ▼
common/chat parser
          │
          ├── assistant content
          └── structured tool calls

This delegates model-specific chat behavior to the same machinery used by llama.cpp instead of rebuilding template conventions independently in Rust.


Structured tool calling

The LLM request contract now supports tool definitions containing:

name
description
parameters

Tool choice can be:

auto
none
required

Assistant history can also carry structured tool calls, while tool results are linked back through a tool-call id.

This makes multi-turn tool use representable as normal chat history rather than as opaque text.


Process-safe tool parsing

The current runtime uses common/chat for prompt rendering and native tool-call parsing.

For the pinned llama.cpp generation path in this release, token-level tool grammar installation is intentionally not relied upon when it can threaten process stability.

Tool-aware templates and the common/chat parser remain active.

The practical tradeoff is:

native tool format + parser

instead of:

unsafe in-process grammar enforcement

until the underlying grammar path is safe for the daemon.


Thinking policy

Local generation now has an explicit thinking policy:

auto
on
off

configured through:

OGD_LLM_THINKING

auto keeps the runtime policy tool-safe:

  • native/template behavior for ordinary turns;
  • thinking disabled for tool-oriented turns.

on and off can force the behavior when a model and template support it.

The selected policy is also exposed through LLM status.


CPU and CUDA device selection

The local LLM runtime can now choose its execution device explicitly.

Configuration is available through:

OGD_LLM_DEVICE

with:

auto
cpu
cuda

auto uses GPU offload when the runtime reports a usable CUDA device and otherwise falls back to CPU.

cpu disables GPU layers explicitly.

cuda requires a usable CUDA backend and visible CUDA device, and fails with an actionable error when that requirement cannot be satisfied.


GPU layer control

GPU offload can be tuned with:

OGD_LLM_GPU_LAYERS

Accepted values are:

auto
all
<number>

This allows deployments to leave layer placement to llama.cpp, offload the complete supported model, or request a specific layer count.


CUDA build features

CUDA support remains a compile-time choice.

New feature profiles include:

cuda
cuda-no-vmm
full-cuda

For example:

cargo build --release --features full-cuda

A binary built without a usable GPU backend can still run the LLM service on CPU.

Explicit:

OGD_LLM_DEVICE=cuda

is reserved for deployments that require CUDA rather than merely preferring it.


Prompt-prefix reuse

Multi-step Agent runs often send the same long prompt prefix repeatedly:

system instructions
conversation
previous tool history

followed by a relatively small new suffix.

v0.80.2 can snapshot and reuse ephemeral llama.cpp sequence state for these repeated prefixes.

Conceptually:

turn 1
[ stable prefix ][ new content ]
       │
       └── capture sequence state

turn 2
[ same stable prefix ][ different suffix ]
       │
       ├── restore cached state
       └── decode suffix only

This cache is designed for reuse inside an Agent run rather than as durable conversation memory.


Bounded prefix cache

The host-memory budget is controlled with:

OGD_LLM_PREFIX_CACHE_MAX_BYTES

The default budget is:

1 GiB

Setting it to:

0

disables prefix-state caching.

Generation statistics can report:

cachedPromptTokens

so callers can observe how much prompt work was reused.


A more capable Agent tool contract

The Agent tool set now contains:

database.collections
database.describe
database.query
files.list

The new:

database.describe

tool allows the Agent to inspect a schemaless collection before inventing field names.

It returns the scoped collection size together with field paths and JSON types observed from a bounded prefix of visible documents.

Observed fields are treated as evidence, not as a strict schema guarantee.


Better database analysis

The Agent now distinguishes between:

looking at a few rows

and:

reasoning about a collection

For summaries, distributions and analytical questions, it can:

  1. discover or describe the collection;
  2. issue targeted read-only queries;
  3. gather compact evidence;
  4. perform a final synthesis turn.

This avoids treating:

limit 20

as if those 20 documents represented the complete collection.


Native query discipline

Agent database access continues to use the openglacier pipeline language.

Queries must start from the native DSL shape:

on <collection>

For example:

on orders
| group status
| sort count desc
| limit 20

The Agent is explicitly guided away from:

SQL
MongoDB syntax
JSON query objects

and from mutating operations.

System collections remain inaccessible through Agent database tools.


Bounded analytical loops

Database analysis now has its own query budget.

The default maximum is:

4

and can be configured with:

OGD_AGENT_MAX_DATABASE_QUERIES

The upper accepted bound is deliberately finite.

This gives the Agent room to gather more than one piece of evidence without allowing an open-ended query loop.


Separate planning and synthesis budgets

Tool-selection turns and final-answer turns do not have identical needs.

v0.80.2 therefore adds a separate synthesis budget.

The default final synthesis allowance is larger than the normal planning budget and can be configured through:

OGD_AGENT_SYNTHESIS_MAX_TOKENS

An explicit request-level maxTokens remains a hard cap.

This lets short tool-planning turns stay compact while giving the final answer enough room to summarize the evidence.


Smaller tool context

The default maximum tool-result context is reduced from:

32 KiB

to:

8 KiB

Database evidence is compacted even more aggressively between analytical turns.

The Agent keeps a small evidence ledger instead of carrying every verbose tool response indefinitely.

This is particularly important for small local models with limited context windows.


Adaptive context handling

When a synthesis request exceeds the model context window, the Agent can now adapt.

It can:

  • reduce the generation budget;
  • compact database-derived evidence;
  • shrink retained tool output;
  • retry with a smaller context footprint.

Only tool-derived database context is compacted by these emergency paths.

The user conversation and execution scope remain conceptually distinct from this temporary evidence reduction.


More deliberate tool choice

The Agent can now narrow the tool set and tool-choice policy according to the request.

Examples include requiring:

database.collections

for collection discovery, or:

database.describe

before a schema-oriented answer.

Analytical requests can require actual:

database.query

execution before synthesis.

Final synthesis turns use:

toolChoice = none

so the model is asked to answer from evidence rather than start another tool loop.


Agent provider timeout

Delegated Agent capability calls can legitimately wait longer than ordinary requ...

Read more

v0.80.0

Choose a tag to compare

@github-actions github-actions released this 07 Sep 10:05

openglacier Core v0.80.0

Compile-time capability builds, local LLM and Agent services, and a more capable concurrent CLI.

openglacier Core v0.80.0 changes how the daemon is assembled.

The Core can now be built from explicit capability families instead of always carrying every service implementation in one binary.

The default build stays focused on the local database path:

  • database
  • auth
  • cli

while additional services can be compiled only when they are actually needed:

  • files
  • events
  • data-import
  • llm
  • agent
  • fabric
  • files-watch
  • cli-tui

This release also introduces a local GGUF LLM runtime backed by llama.cpp, a stateless Agent orchestration layer, streaming LLM and Agent operations, cancellation and queueing, and an optional terminal UI for concurrent interactive work.


Highlights

Build only the Core a node needs

Cargo features now describe which implementation families physically exist in a binary.

Runtime capabilities remain a separate concern.

Conceptually:

Cargo features
      │
      ▼
compiled services
      │
      ▼
OGD_NODE_CAPABILITIES
      │
      ▼
enabled services
      │
      ▼
published operations

A capability therefore has two distinct questions:

was it compiled?

and:

is it enabled on this node?

This makes small, purpose-specific binaries possible without changing the operation model.


Compile-time capability profiles

The default feature set is now:

database
auth
cli

This is intended for a local database node with authentication and the administrative CLI.

Additional service families are explicit opt-ins.

For example:

cargo build --release --features files,events

or:

cargo build --release --features llm,agent

A broad daemon build remains available through:

cargo build --release --features full

full compiles the historical service families together with the optional extension providers.

Compilation does not automatically enable every compiled service at runtime.

In particular, extension capabilities such as:

data.import
llm
agent

remain explicit runtime choices.


Build-aware operation catalogue

The canonical operation catalogue now understands build composition.

Operations can describe:

  • their provider capability;
  • the implementation family required to compile them;
  • whether they depend on the internal database engine;
  • whether the implementation exists in the current binary;
  • whether the operation should be published by the current node.

This keeps operation names and wire contracts centralized while allowing different binaries to expose different implementation sets.

Core operations such as:

ping
core.health
core.operations
node.status

remain independent from optional provider families.

The result is a cleaner separation between:

protocol contract
compiled implementation

and:

runtime publication

Local LLM capability

v0.80.0 introduces a local LLM provider backed by:

llama.cpp
GGUF

The capability is compile-time optional through:

llm

and exposes three operations:

llm.status
llm.generate
llm.cancel

llm.generate is streamed.

Generated text is emitted incrementally rather than being buffered until the complete answer is available.


LLM scheduling and cancellation

The local runtime includes a bounded scheduler.

Each generation receives a runId and can begin in either:

running

or:

queued

state.

The scheduler controls:

  • maximum parallel generations;
  • queue capacity;
  • ownership of runs;
  • queued cancellation;
  • active cancellation.

This prevents an embedded model from becoming an unbounded source of concurrent work.

A queued or running generation can be cancelled with:

llm.cancel

LLM configuration

The first local runtime can be configured through environment variables including:

OGD_LLM_MODEL
OGD_LLM_CONTEXT_SIZE
OGD_LLM_THREADS
OGD_LLM_MAX_TOKENS
OGD_LLM_SEED
OGD_LLM_MAX_PARALLEL
OGD_LLM_QUEUE_SIZE
OGD_LLM_CHAT_TEMPLATE

A model is optional at process startup.

Without OGD_LLM_MODEL, the capability can remain compiled while reporting itself as unconfigured.

When configured, the runtime loads the GGUF model locally and uses the model chat template, or an explicit template supplied through configuration.


Stateless Agent capability

v0.80.0 also introduces the first openglacier Agent service.

The Agent is deliberately stateless.

It owns the reasoning and tool loop, but it does not own the underlying capabilities.

Instead, it invokes services supplied by the host.

Conceptually:

Agent
  │
  ├── llm.generate
  │
  ├── database collections
  │
  ├── database query
  │
  └── files

The first tool set contains:

database.collections
database.query
files.list

Database queries issued by the Agent are restricted to read-only execution.

Mutating query plans are rejected before reaching the database capability.


Inherited execution scope

The Agent does not invent its own Place or AppInstance context.

The execution scope is inherited from the request.

That means tool calls do not carry arbitrary scope identifiers chosen by the model.

Conceptually:

request
  │
  ▼
validated Place / AppInstance
  │
  ▼
Agent run
  │
  ▼
tool calls inherit that scope

This keeps Agent orchestration inside the same authorization and execution model as the rest of the Core.


Local or delegated capabilities

The Agent does not assume that its tools are local.

A standalone daemon can invoke local capabilities directly.

A fabric node can delegate the same capability calls through Gateway.

The Agent loop therefore depends on operation contracts rather than concrete backend ownership.

This is important for keeping AI orchestration out of the database kernel itself.


New Agent operations

The Agent service exposes:

agent.status
agent.run

agent.run is streamed.

A run can emit progress around:

  • LLM steps;
  • tool calls;
  • tool results;
  • final messages.

Process-wide Agent limits can be configured with:

OGD_AGENT_MAX_STEPS
OGD_AGENT_LLM_MAX_TOKENS
OGD_AGENT_MAX_TOOL_BYTES

The service retains limits, not conversation state.


Concurrent ogcli

The interactive CLI can now run requests concurrently.

Long-running operations no longer have to monopolize the prompt while they stream output.

Background work is identified by a local job id and can continue while new commands are entered.

This is particularly useful for:

llm.generate
agent.run
long-running queries
streaming operations

The normal REPL remains intentionally thin: it speaks the daemon protocol and does not duplicate server behavior.


Optional terminal UI

A new optional TUI can be compiled with:

cli-tui

and started with:

ogcli --tui

The TUI uses the same concurrent request model as the regular CLI.

It adds:

  • multiple jobs;
  • tabs;
  • tiled views;
  • per-job status;
  • scrolling;
  • focus switching;
  • LLM cancellation.

The interface is therefore a view over the protocol rather than a second execution model.


Capability-oriented daemon composition

Service implementations are now explicitly grouped around capabilities.

Examples include:

database
auth
files
events
data.import
llm
agent

Infrastructure features such as:

fabric
files-watch
cli
cli-tui

remain distinct from published service capabilities.

This helps keep three concerns separate:

database kernel
service provider
user interface

A database-only build should not need to carry an LLM runtime.

An LLM provider should not need to become a database server.

A CLI should not define server semantics.


Compatibility

The operation protocol remains capability-oriented, but build composition changes materially in v0.80.0.

The default Cargo build now contains:

database
auth
cli

rather than every optional service family.

Applications or deployment scripts that require files, events, fabric, data import, LLM, Agent or TUI support should enable the corresponding Cargo features explicitly.

For a broad daemon build:

cargo build --release --features full

Runtime capability selection still applies after compilation.

An operation cannot be enabled if its implementation was not compiled into the binary.


Examples

Default local database build:

cargo build --release

Broad daemon build:

cargo build --release --features full

Local LLM and Agent build:

cargo build --release --features database,auth,cli,llm,agent

Start a configured local LLM provider:

OGD_LLM_MODEL=./models/model.gguf \
OGD_NODE_CAPABILITIES=database,llm,agent \
cargo run --release --features database,auth,cli,llm,agent --bin ogd

Inspect the compiled and published operation surface:

.core.operations

Start the optional terminal UI:

cargo run --release --features cli-tui --bin ogcli -- --tui

In short

v0.80.0 makes openglacier Core more modular at the binary level.

The visible additions are substantial:

compile-time capabilities · local LLM · stateless Agent · concurrent CLI · optional TUI

but th...

Read more