Turn text from ordinary Unix commands, logs, files, and scripts into schema-validated JSON without sending the data to a service.
some-command | glean --fields name,status | jq .glean is a local command-line extraction tool. It combines a small GGUF
language model with JSON Schema constrained decoding, so it can handle text
that is difficult to parse with regular expressions while still producing a
machine-checkable result.
Many useful data sources are neither APIs nor stable formats:
- A log line mixes timestamps, identifiers, and a free-form message.
- A command prints an aligned table whose spacing changes between versions.
- A support ticket contains a few facts buried in prose.
- A shell pipeline needs structured output but cannot depend on Python, credentials, a network service, or a separate application.
glean is intended for those gaps. A full release is a single executable with
the fast model included. It can run offline on a fresh machine, in an
air-gapped environment, or inside a small operational script. A thin release
is much smaller and downloads the model into a verified local cache on first
use.
The model is not a replacement for a deterministic parser when the input
format is already known and exact. For example, a purpose-built lsblk parser
is more reliable than any language model. glean is useful when writing and
maintaining that parser would be harder than describing the fields you need.
Extract fields from prose:
printf '%s\n' \
'Alice is 30 years old' \
'Bob is 25 years old' |
glean --fields name,age[
{"age":"30","name":"Alice"},
{"age":"25","name":"Bob"}
]Parse a log stream with one record per line:
journalctl -o short-iso --no-pager |
glean --fields timestamp,service,message --delimiter '\n' --compactRead directly from files:
glean --fields host,status logs/*.txtExtract a summary object with the built-in schema:
glean incident-notes.txtThe successful output is one JSON document on stdout. Normal progress is
silent. Errors go to stderr. Use --verbose for model, backend, timing,
chunking diagnostics.
Install the small thin release on Linux or macOS:
curl -fsSL https://raw.githubusercontent.com/duffy1001/glean/master/install.sh | shInstall the offline full release:
curl -fsSL https://raw.githubusercontent.com/duffy1001/glean/master/install.sh |
GLEAN_VARIANT=full shBoth installers place the selected executable at glean, verify its SHA-256
checksum, and install to /usr/local/bin when writable or ~/.local/bin
otherwise. Set GLEAN_INSTALL_DIR to choose another directory. Set
GLEAN_FORCE=1 for a noninteractive replacement.
Windows PowerShell:
irm https://raw.githubusercontent.com/duffy1001/glean/master/install.ps1 | iexThe thin edition downloads the model on first use. The full edition contains the model and extracts a verified copy to the model cache on first use so llama.cpp can memory-map it. Neither edition embeds a network dependency.
--fields creates a root array of objects with exactly the named string fields:
printf '%s\n' \
'db-01 is up' \
'db-02 is down' |
glean --fields host,statusFor integers, booleans, enums, nested objects, or stricter contracts, provide a JSON Schema:
{
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"age": {"type": "integer"},
"active": {"type": "boolean"}
},
"required": ["name", "age", "active"],
"additionalProperties": false
}
}glean --schema people.schema.json people.txtThe schema is used twice:
- llama.cpp converts it to a grammar that constrains generation.
gleanvalidates the final generated document against the original schema.
The supported grammar is the JSON Schema subset implemented by the pinned
llama.cpp revision, not full JSON Schema. A schema accepted by the validator
may still be rejected during grammar conversion. --no-grammar disables
constrained generation but does not disable final validation.
Grammar guarantees output shape, not factual accuracy. Review extracted data when correctness is important.
Root-array schemas are processed incrementally. Records are split on
--delimiter, packed into context-sized chunks, extracted, validated, and
written as soon as each chunk completes.
Use --delimiter '\n' for line-oriented input, --delimiter '\0' for
NUL-delimited input, or any other string, including multi-character separators
like ||.
Use --atomic when downstream tools require a complete JSON array on stdout.
It buffers array items and emits nothing unless the full extraction succeeds.
cat application.log |
glean --fields timestamp,level,message --delimiter '\n'Use NUL-delimited input when records can contain newlines:
git ls-files -z |
glean --delimiter '\0' --fields path --compactOversized records are split and retried. Output is one JSON array, but its items
are written incrementally by default. If a later chunk fails, the command exits
nonzero and stdout may contain a partial JSON stream unless --atomic is used.
Release binaries include CPU support and an optional platform accelerator:
- Linux and Windows: Vulkan
- macOS: Metal with embedded shader source
GPU drivers and the Vulkan loader are optional system capabilities. If they are
missing, glean continues on CPU. Inspect what the binary can see:
glean --reportBy default, --device auto uses a detected GPU or integrated GPU. If no
accelerator is available, it uses CPU. Force a mode when needed:
glean --device gpu --fields name,status input.txt
glean --device cpu --fields name,status input.txtAutomatic GPU initialization failures retry on CPU. --device gpu is strict
and fails when no usable accelerator is detected. --gpu-layers 0 disables
offload; --gpu-layers -1 means all available layers.
For the small fast model, GPU startup and dispatch overhead can outweigh the benefit on tiny inputs. On one local machine, a 40-record workload measured:
| Device | Generation speed | Generation time |
|---|---|---|
| 13th-gen Intel CPU | 26.9 tok/s | 48.1 seconds |
| RTX 4070 Ti via Vulkan | 47.1 tok/s | 27.5 seconds |
These are representative measurements, not guarantees. Workload size, driver, backend, CPU, and model output length all matter.
The supported model is Qwen3 0.6B Q4_K_M:
| Edition | Executable size | Model behavior |
|---|---|---|
thin-fast |
about 15 MB | Downloads the model on first use |
full-fast |
about 400 MB | Includes the model for offline use |
Release assets are named:
glean-thin-fast-<os>-<arch>
glean-full-fast-<os>-<arch>
The release workflow uploads these binaries and checksums.txt to GitHub
Releases, so users can download them from the release page.
The installer renames the selected asset to glean. Published SHA-256 values
are in checksums.txt. Current release targets are Linux amd64/arm64, macOS
arm64, and Windows amd64.
Models are cached under:
$XDG_CACHE_HOME/glean/modelswhenXDG_CACHE_HOMEis set~/Library/Caches/glean/modelson macOS~/.cache/glean/modelson other platforms
| Option | Default | Description |
|---|---|---|
--schema FILE |
JSON Schema used for generation and validation | |
--fields LIST |
Comma-separated string fields for array extraction; names must be unique and non-empty | |
--model NAME |
fast |
Supported model: fast |
--max-tokens N |
2048 |
Maximum generated tokens per inference chunk |
--ctx N |
8192 |
Model context window |
--atomic |
false |
Buffer array output and only emit it after all chunks succeed |
--delimiter STRING |
\n |
Record separator for array extraction; supports \n, \t, \r, \0, \\, and multi-character strings |
--threads N |
4 |
CPU inference threads |
--device NAME |
auto |
Device policy: auto, cpu, or gpu |
--gpu-layers N |
-1 |
Layers to offload when GPU inference is selected |
--compact |
false |
Print compact rather than indented JSON |
--no-grammar |
false |
Disable grammar constraints; validation remains enabled |
--verbose |
false |
Write diagnostics to stderr |
--version |
false |
Print version and build variant |
--report |
false |
Print detected backends, devices, memory, and default selection |
--schema takes precedence over --fields. Positional arguments are input
file paths. With no positional arguments, glean reads stdin.
Requirements:
- Go 1.26 or newer
- Git and Make
- CMake
- A C compiler and a C++17 compiler
- CGO enabled
- Vulkan headers,
glslc, and SPIR-V headers on Linux/Windows build hosts
cd glean
make setup
make
./bin/glean --reportRun tests:
make testBuild the two local editions:
make build-thin-fast
make build-full-fastBuild release assets for the current Linux or macOS platform:
./release.sh allThe native build disables network support, examples, tests, server components, shared libraries, and OpenMP in llama.cpp. Runtime GPU drivers remain optional.