gmeow-gts — Rust GTS Engine
A whole graph in a single, verifiable file.
gmeow-gts is the Rust implementation of the Graph Transport Substrate (GTS) — a
single-file, language-independent transport for an RDF 1.2 graph (statements and
statement-level metadata) together with any content-addressed binary the graph references.
It is one of four interoperable engines (Python, Rust, Go, TypeScript) that gate against the
same frozen, language-neutral conformance corpus.
This crate provides a library and a command-line tool for reading, writing, verifying, composing, compacting, and projecting GTS files — with optional COSE signing and encryption. It is designed for systems that need portable, auditable, content-addressed graph packages: archives, evidence chains, local-first synchronization, dataset distribution, GMEOW packages, and agent memory.
Table of Contents
- What is GTS?
- What this crate provides
- Installation
- Quick start
- Library API
- Example: grounded agent memory
- Command-line reference
- The GTS file format
- Developer documentation
- Project and community
- Contributing
- Support
- License and copyright
What is GTS?
GTS is the Graph Transport Substrate: a CBOR-sequence, append-only, content-addressed file format for moving RDF 1.2 graphs and their evidence around. A GTS file is composed of one or more segments, each a header followed by frames chained by BLAKE3 content-id. Key properties:
- Append-only and composable. Concatenating valid GTS files (
cat) yields a valid GTS file whose fold is the value-union of the segment graphs. - Content-addressed. Frames and external binaries are referenced by BLAKE3 digests.
- Signable and verifiable. Frames can carry detached COSE_Sign1 signatures, and segments carry provenance metadata.
- Language-independent. The same file can be read and written by the Python, Rust, Go, and TypeScript engines.
For the authoritative specification, see docs/GTS-SPEC.md.
For the reference-implementation guide, see docs/gts-reference.md.
GTS is ontology-independent. GTS is the primary distribution method for GMEOW, but GTS does not depend on GMEOW. A reader does not need GMEOW vocabulary or tooling to parse, verify, fold, or transport a GTS file.
What this crate provides
gmeow_gts::reader— read a GTS byte slice into aGraph, verify chains, detect torn appends, decryptCOSE_Encrypt0frames when a content-key resolver is supplied, and handle opaque/degraded frames.gmeow_gts::writer— build frames and emit full GTS files, includingWriter::deterministic(&graph, profile)for reproducible graph authoring andFrameOptionsfor transformed, encrypted, explicitly signed, or recipient-addressed frames.gmeow_gts::cose— COSE_Sign1 signing and verification of frame ids (§9.2), plus COSE_Encrypt0 AES-256-GCM payload encryption (§9.3).gmeow_gts::openpgp— parse an embedded OpenPGP transport key to its fingerprint.gmeow_gts::verify— high-level embedded-key verification results for libraries, including fingerprint, visual hashes, signature counts, diagnostics, and profile findings.gmeow_gts::compact— compact a streamable GTS segment into a self-contained one.gmeow_gts::files— pack and unpack directory trees using the GTS files profile.gmeow_gts::nquads— project a folded graph to N-Quads.gmeow_gts::yamlld/gmeow_gts::from_yamlld— optional--features yaml-ldJSON-LD-star/YAML-LD-star transforms over the folded graph tables.gmeow_gts::model::Graph— consume raw quad-id rows withinto_quads()or lazily resolve them withquad_terms().gmeow_gts::rdf— optional--features rdfnative adapter foroxrdf::Datasetwithout an embedded graph-store dependency.gmeow_gts::oxigraph— optional--features oxigraph-adapterbridge between folded GTS graphs and Oxigraph's in-memoryStore, with GTS metadata kept in a sidecar.gmeow_gts::examples::agent_memory— a dependency-light grounded-memory example built on ordinary GTS frames.gmeow_gts::stream— stream-vocabulary constants and helpers.gmeow_gts::emojihash— re-export of thevisual-hashingcrate'semojihashandrandomartkey fingerprints.gtsbinary — a CLI for all of the above.
The crate gates against the identical frozen conformance corpus used by the Python, Go, and TypeScript engines; every engine must fold identical bytes to identical expectations.
Installation
As a command-line tool
The installed binary is named gts for ergonomics, even though the crate is gmeow-gts.
As a library
Add to Cargo.toml:
[]
= "0.9.5"
Verify a signed file with its embedded transport key:
let data = read?;
let result = verify_file;
assert!;
println!;
Sign new frames with either raw Ed25519 bytes or an unencrypted Ed25519 OpenPGP secret-key block:
use SigningKey;
use Writer;
let seed = ;
let mut raw = new;
raw.sign_with;
let armored = read_to_string?;
let mut openpgp = new;
// `None` uses the OpenPGP v4 fingerprint as the COSE key id.
openpgp.sign_with_openpgp_secret_key?;
Quick start
# Inspect a GTS file
# Fold it to N-Quads
# Verify chain integrity
# Compose two valid files
# Package a directory
# Extract it elsewhere
Library API
Read a GTS file and project it to N-Quads. reader::read is total: it never returns an
error — a damaged or undecodable frame degrades to an opaque node and surfaces as a diagnostic
on the returned Graph, so it always yields a usable (possibly partial) fold. The arguments are
(data, allow_segments, expected_head):
use fs;
Inline blob entries are content-addressed by digest and may remain transformed on the wire until
they are read. Use Graph::blob_entry to inspect presence without decoding, Graph::blob_bytes
or Graph::blob_bytes_cloned to decode and cache a single blob, and Graph::decoded_blobs to
materialize the insertion-ordered table. External blob records carry metadata and the declared
digest only; their bytes are intentionally out-of-band, so Graph::blob_bytes returns None
unless an inline payload frame is present.
Readers that hold content keys can use ReadOptions::with_content_key to decrypt
COSE_Encrypt0 frames during the same total fold. Missing or wrong keys still degrade to
opaque nodes with MissingKey diagnostics instead of aborting the read:
let key = ;
let resolver = ;
let graph = read_with_options;
Write a minimal graph. A Writer is created with a profile (e.g. "dist"), then frames are
appended: a terms frame interns the RDF terms by append-order id, and a quads frame
references them by those ids (the fourth tuple slot is the graph name, None for the default
graph):
use ;
use Writer;
Advanced frame authorship uses FrameOptions, matching the Python writer's transform and
encryption surface without adding new Rust dependencies:
use Value;
use ;
let key = ;
let mut writer = new;
writer.add_frame_with_options?;
For the full API, see docs.rs/gmeow-gts.
Example: grounded agent memory
The crate ships a small agent-memory example that mirrors the Python
gts.examples.agent_memory workflow without adding a database, SPARQL engine,
embedding model, or RDF toolkit dependency. It stores claims as reified RDF 1.2
statements, records tool-call provenance as ordinary quads, and revises claims
by appending suppressions plus gmeow:wasDerivedFrom audit links. The package
stays append-only and gts verify-able after every write.
Run the example:
Use it as a library example:
use ;
The example is a downstream application shape, not a requirement for parsing or transporting GTS. It uses only this crate's existing writer, reader, N-Quads, BLAKE3, and timestamp support.
Command-line reference
gts info <file>... per-segment composition ledger
gts fold <file> fold to N-Quads on stdout
gts from-nq <in.nq> [-o out] build a GTS from N-Quads (`-` reads stdin)
gts to-trig <file> fold to TriG on stdout
gts from-trig <in.trig> [-o out]
build a GTS from TriG (`-` reads stdin)
gts to-nt <file> fold the default graph to N-Triples (--features rdf-codecs)
gts from-nt <in.nt> [-o out] build a GTS from N-Triples (--features rdf-codecs)
gts to-rdfxml <file> fold the default graph to RDF/XML (--features rdf-codecs)
gts from-rdfxml <in.rdf> [-o out]
build a GTS from RDF/XML (--features rdf-codecs)
gts to-turtle <file> fold the default graph to Turtle (--features rdf-codecs)
gts from-turtle <in.ttl> [-o out]
build a GTS from Turtle (--features rdf-codecs)
gts to-yaml-ld <file> fold to YAML-LD-star (--features yaml-ld)
gts from-yaml-ld <in.yaml> [-o out]
build a GTS from YAML-LD-star (--features yaml-ld)
gts to-okf <file> --directory <dir>
export an OKF bundle (--features okf)
gts from-okf <dir> [-o out] build a GTS from an OKF bundle (--features okf)
gts from-tar <archive.tar[.gz|.zst]|-> [-o out.gts] [--allow-symlinks] [--allow-special] [--owner]
build a files-profile-v2 GTS from tar (--features tar)
gts to-tar <file.gts> [-o archive.tar|-] [-z|--gzip|--zstd] [--numeric-owner]
export a files-profile-v2 archive as tar (--features tar)
gts tar -c[z|--zstd]f <archive.gts|archive.tar[.gz|.zst]> <dir|file>...
create a GTS or tar archive by extension (--features tar)
gts tar -xf <archive.gts|archive.tar[.gz|.zst]> [-C dir]
extract with refuse-dangerous defaults (--features tar)
gts tar -tf <archive.gts|archive.tar[.gz|.zst]>
list files-profile entries (--features tar)
gts tar -df <archive.gts|archive.tar[.gz|.zst]> <dir>
compare archive entries to a directory (--features tar)
gts to-sqlite <file> <out> export to SQLite (requires sqlite3)
gts to-duckdb <file> <out> export to DuckDB (--features duckdb; requires duckdb)
gts to-parquet <file> <dir> export to Parquet (--features duckdb; requires duckdb)
gts verify <file>... [--key KID:HEXPUB]
verify chains + COSE signatures; exit 1 on any
gts prove <file> <frame-id> emit detached JSON proof from an index.mmr root
gts verify-proof <proof.json> verify detached proof JSON without the GTS file
gts heads <file> emit JSON segment heads and aggregate comparison digest
gts segments <file> emit JSON segment byte ranges and layout inventory
gts missing --from-head <head> <file>
emit JSON byte ranges needed after a peer head
gts resume --after <frame-id> <file>
emit bytes after a verified frame boundary
gts extract-key <file> print the embedded transport/verification key:
kid, OpenPGP fingerprint, emojihash, armored key
gts ls <file> list inline blobs: digest, size, media type
gts extract <file> <digest> write a single content-addressed blob
gts cat -o <out> <file>... validating composer: refuse degenerate inputs,
then byte-concatenate
gts compact <file> -o <out> --streamable
compact into the streamable layout state
gts pack <dir|file>... -o <out> package files/directories into a files profile
gts unpack <file> [-C <dir>] [--include-suppressed] [--allow-symlinks] [--allow-special]
extract a files profile (refuses path traversal)
gts diff <file> <directory> compare a files profile to a directory
gts dump <file> --directory <dir>
expand an archive into an inspection directory
Exit codes:
0— success / clean1— diagnostics or input refused2— usage or IO error
verify --key and extract-key are cross-engine: all four gts binaries parse the embedded
OpenPGP transport key to the same fingerprint and emojihash, and verify COSE signatures
identically. Library callers can use gmeow_gts::verify::verify_file for the same embedded-key
verification summary without duplicating CLI helper code. Rust also exposes the current
MMR/proof surface through Writer::add_index_with_mmr, gts prove, and gts verify-proof,
and the replication surface through gts heads, gts segments, gts missing, and gts resume,
without adding runtime JSON, Merkle-tree, or replication dependencies. Rust writers can sign with raw
Ed25519 keys or Writer::sign_with_openpgp_secret_key, which accepts the same narrow
unencrypted Ed25519 OpenPGP secret-key shape as Python Signer.from_gpg_secret_key without
adding a full OpenPGP crate dependency. gts dump writes a versioned inspection directory with
folded N-Quads, JSONL tables, unfolded frame views, blob indexes, and files-profile payloads
without duplicating large payload bytes by default. to-trig and from-trig provide a
readable TriG graph-block projection over the same folded RDF content as N-Quads. The optional
rdf-codecs feature adds RDF 1.2 text codecs through oxttl and oxrdfxml; with it,
to-trig and from-trig use the full codec path and to-nt/from-nt,
to-rdfxml/from-rdfxml, plus to-turtle/from-turtle provide default-graph RDF text
interchange. The optional
OKF profile (--features okf) imports and exports Markdown bundle directories with
content-addressed body blobs, link edges, a gts-okf-v1 manifest, and _unmapped.nq sidecars
for out-of-profile RDF. The optional tar bridge (--features tar) imports and exports
files-profile-v2 archives as tar streams, including stdin/stdout use, gzip/zstd wrapping,
link and special-file opt-ins, owner metadata, and unknown PAX records. gts tar wraps that
bridge in familiar -c/-x/-t/-d forms and chooses the GTS or tar path by extension.
from-tar and gts tar -cf out.gts ... author regular-file blob frames from bounded chunks
instead of retaining whole payloads in memory; tar input is decoded as a stream and regular
files are spooled while deterministic metadata is sorted. Folded to-tar export still depends
on the folded Graph, and zstd tar output remains a bounded-by-backend vector path until a
fallible streaming zstd Write encoder is available.
unpack and tar -x use refuse-dangerous defaults: ownership is restored only with
--same-owner or --numeric-owner, setuid/setgid/sticky bits are stripped unless
--preserve-setid is supplied, and links or special nodes are materialized only with
--allow-symlinks or --allow-special. Opted-in symlink targets are still checked so they
cannot escape the destination tree. from-nq and the relational
to-sqlite/to-duckdb/to-parquet exports are
implemented by the Rust and Python CLIs. The Rust relational commands use the same folded
integer table model as Python. to-sqlite is in the default build and requires sqlite3
on PATH; to-duckdb and to-parquet require the optional no-dependency duckdb
Cargo feature plus the duckdb binary on PATH. Rust streams SQL rows into those tools
instead of buffering all rows or a full SQL script; lazy transformed blobs stay lazy in the
folded Graph and are decoded transiently only when the stable blobs.bytes column is
emitted.
Default Cargo features are empty. The optional rdf feature enables
gmeow_gts::rdf::{to_oxrdf_dataset, from_oxrdf_dataset} through oxrdf's RDF
data-model crate. The optional oxigraph-adapter feature adds
gmeow_gts::oxigraph::{graph_to_store, store_to_writer} and
Writer::from_store using Oxigraph's in-memory store with Oxigraph defaults disabled.
The optional sophia-adapter feature adds
gmeow_gts::sophia::{to_sophia_dataset, from_sophia_dataset} using Sophia's
in-memory dataset plus N-Quads parser/serializer.
The optional policy-config feature adds JSON loading helpers for
gmeow_gts::policy::TrustPolicy and enables gts verify --policy <file> for
release/profile verification workflows. policy-config-yaml layers YAML parsing
on top for deployments that want YAML policy files.
The optional yaml-ld feature adds gmeow_gts::yamlld::{to_json_ld, to_json_ld_string, to_yaml_ld} and gmeow_gts::from_yamlld::{from_json_ld, from_yaml_ld} plus the matching CLI verbs. It is a Rust-only transform surface:
it uses the GTS Term model to preserve RDF 1.2 language-tagged literal base
direction (@direction) where present.
The optional tar feature adds gmeow_gts::from_tar and gmeow_gts::tar
plus the from-tar, to-tar, and tar CLI verbs. It is a Rust-first files-profile-v2 bridge surface;
Python, Go, and TypeScript parity can implement the same contract later.
The adapters and policy parsers are absent from ordinary default builds.
cat output is raw byte concatenation: validation is added, transformation never. It
refuses dirty inputs, contributes-nothing segments, and compositions whose suppressions
hide every folded quad.
The GTS file format
A GTS file is a CBOR Sequence (RFC 8742, application/cbor-seq) of one or more
segments — there are no framing bytes between items. Published GTS artifacts use
application/vnd.blackcat.gts+cbor-seq; the +cbor-seq suffix records that the file is a CBOR
Sequence, not a single CBOR item. Each segment is a Header CBOR map (optionally preceded by
the CBOR self-describe tag 55799, the human-recognizable magic) followed by zero or more
frames, each itself a CBOR map. Every frame carries its own "id" — the BLAKE3 content-id of
its canonical contents — and names its predecessor's id in "prev", so a segment is a git-style
content-addressed chain whose head transitively commits to all history.
The logical graph is the fold of the log: the deterministic replay of the frames into the
in-memory tables (terms, quads, reifier bindings, annotations, blobs, …). The fold is not a
hash — concatenating two valid GTS files (gts cat) yields a file whose fold is the
value-union of the inputs. "Deletion" is additive suppression, never physical removal.
Payloads carry a stackable codec chain; an unknown codec or a held-back key degrades a frame to an opaque node rather than failing the read — the reader is total. External binaries are referenced by content-id and may be omitted without invalidating the file.
For full details, read docs/GTS-SPEC.md.
Developer documentation
- GTS Specification — the authoritative, normative wire-format specification.
- GTS Reference Guide — the Python reference-implementation guide.
- GTS Ecosystem Integration Contract — RDF crate adapter status and deferrals.
CONTRIBUTING.md— development workflow.CODE_OF_CONDUCT.md— community standards.SECURITY.md— vulnerability reporting.CHANGELOG.md— release history.
Building and testing locally
The conformance tests compare this engine's output against the frozen corpus in
vectors/.
Project and community
gmeow-gts is developed by Blackcat Informatics® Inc..
GMEOW is a downstream ontology and tooling suite that uses GTS as a distribution substrate.
Related packages and engines:
Contributing
Contributions are welcome. Please read CONTRIBUTING.md
for the development workflow and CODE_OF_CONDUCT.md
before opening a PR. To report a vulnerability, follow SECURITY.md
(do not open a public issue).
All changes must pass cargo test, cargo fmt --check, and cargo clippy --all-targets -- -D warnings.
Support
- Open an issue: https://github.com/Blackcat-Informatics/gmeow-gts/issues
- Discussions: https://github.com/Blackcat-Informatics/gmeow-gts/discussions
License and copyright
Copyright © 2026 Blackcat Informatics® Inc.
Triple-licensed: MIT OR Apache-2.0 OR proprietary. You may use this crate under
the terms of MIT
or Apache-2.0,
at your option. A separate commercial/proprietary license is also available — see
LICENSING.md.