Skip to content

xdb-dev/xdb

Repository files navigation

XDB

XDB is an agent-first data layer. Model once, store anywhere. Simple URIs, structured tuples, and a pipe-friendly CLI that agents and humans both get right on the first try.

Why XDB?

Read about the motivation behind XDB in Introducing XDB.

Core Concepts

For in-depth documentation on each concept, see docs/concepts.

The XDB data model can be visualized as a tree of Namespaces, Schemas, Records, and Tuples.

┌─────────────────────────────────┐
│            Namespace            │
└────────────────┬────────────────┘
                 ↓
┌─────────────────────────────────┐
│             Schema              │
└────────────────┬────────────────┘
                 ↓
┌─────────────────────────────────┐
│             Record              │
└────────────────┬────────────────┘
                 ↓
┌─────────────────────────────────┐
│             Tuple               │
├─────────────────────────────────┤
│   ID | Attr | Value | Options   │
└─────────────────────────────────┘

Tuple

A Tuple is the fundamental building block in XDB. It combines:

  • ID: a string that uniquely identifies the record
  • Attr: a string that identifies the attribute. It supports dot-separated nesting.
  • Value: The attribute's value
  • Options: Key-value pairs for metadata

tuple.png

Record

One or more Tuples, with the same ID, make up a Record. Records are similar to objects, structs, or rows in a database. Records typically represent a single entity or object of domain data.

Namespace

A Namespace (NS) groups one or more Schemas. Namespaces are typically used to organize schemas by domain, application, or tenant.

Schema

A Schema defines the structure of records and groups them together. Schemas can be "strict" or "flexible". Strict schemas enforce a predefined structure on the data, while flexible schemas allow for arbitrary data. Each schema is uniquely identified by its name within a namespace.

URI

XDB URIs are valid Uniform Resource Identifiers (URI) according to RFC 3986. URIs are used to uniquely identify resources in XDB.

The general format of a URI is:

    [SCHEME]://[DOMAIN] [ "/" PATH] [ "?" QUERY] [ "#" FRAGMENT]

XDB URIs follow the following format:

    xdb:// NS [ "/" SCHEMA ] [ "/" ID ] [ "#" ATTRIBUTE ]
    xdb://com.example/posts/123-456-789#author.id
    └─┬──┘└────┬────┘└──┬─┘└─────┬─────┘└─────┬─────┘
   scheme     NS    SCHEMA      ID        ATTRIBUTE
              └───────────┬───────────┘
                       path

The components of the URI are:

  • NS: The namespace.
  • SCHEMA: The schema name.
  • ID: The unique identifier of the record.
  • ATTRIBUTE: The name of the attribute.
  • path: NS, SCHEMA, and ID combined uniquely identify a record (URI without xdb://)

Valid examples:

Namespace:  xdb://com.example
Schema:     xdb://com.example/posts
Record:     xdb://com.example/posts/123-456-789
Attribute:  xdb://com.example/posts/123-456-789#author.id

Supported Types

Type PostgreSQL SQLite Description
String TEXT TEXT UTF-8 string
Integer BIGINT INTEGER 64-bit signed integer
Float DOUBLE PRECISION REAL 64-bit floating point number
Boolean BOOLEAN INTEGER True or False
Timestamp TIMESTAMPZ INTEGER Date and time in UTC
JSON JSONB TEXT JSON data type
Bytes BYTEA BLOB Binary data
Array []T TEXT Array of T

Getting Started

Installation

go install github.com/xdb-dev/xdb/cmd/xdb@latest

Check Version

xdb --version

Quick Start

# Create schema
xdb make-schema xdb://com.example/posts --schema posts.json

# List schemas
xdb ls xdb://com.example

# Get schema
xdb get xdb://com.example/posts

# Remove schema
xdb rm xdb://com.example/posts

# Put record
xdb put xdb://com.example/posts/post-123 --file post.json

# Get record
xdb get xdb://com.example/posts/post-123

# List records
xdb ls xdb://com.example/posts

# Filter records
xdb ls xdb://com.example/posts --filter "title~Hello"

# Remove record
xdb rm xdb://com.example/posts/post-123

CLI Reference

Commands

Make Schema

# Create schema from definition file
xdb make-schema xdb://com.example/posts --schema ./posts.json

# Create flexible schema (no definition file)
xdb make-schema xdb://com.example/users

make-schema creates or updates a schema at the given URI. The URI must include both NS and Schema components (e.g., xdb://com.example/posts).

If no schema definition file is provided, a flexible schema is created. Flexible schemas allow arbitrary data without validation. Schema definitions enforce structure and types on all Tuple and Record operations.

Note: You can update a schema by calling make-schema again with the same URI and a new schema definition.

List

# List schemas in namespace
xdb ls xdb://com.example

# List with pagination
xdb ls xdb://com.example/users --limit 10
xdb ls xdb://com.example/users --limit 10 --offset 20

# List all (default limit is 100)
xdb ls xdb://com.example

# Filter records by attribute
xdb ls xdb://com.example/users --filter "age>30"
xdb ls xdb://com.example/users --filter "name=alice"

# Multiple filters (AND logic)
xdb ls xdb://com.example/users --filter "age>=25" --filter "status!=inactive"

# Contains filter
xdb ls xdb://com.example/posts --filter "title~hello"

# Combine filters with pagination
xdb ls xdb://com.example/users --filter "age>30" --limit 10

ls lists namespaces, schemas, or records depending on the URI. If no URI is provided, it lists all namespaces. Filters are only applied when listing records.

Flags:

  • --limit N: Maximum number of results to return (default: 100)
  • --offset N: Number of results to skip (default: 0)
  • --filter EXPR: Filter records by attribute (repeatable). Supported operators: =, !=, >, >=, <, <=, ~ (contains). Multiple filters are combined with AND logic. Filtering is applied before pagination.

Get

# Get Namespace
xdb get xdb://com.example

# Get Schema
xdb get xdb://com.example/posts

# Get Record
xdb get xdb://com.example/posts/post-123

# Get Attribute
xdb get xdb://com.example/posts/post-123#title

get retrieves a Namespace, Schema, Record, or Attribute from the given URI.

Put

# Put Record from JSON file
xdb put xdb://com.example/posts/post-123 --file post.json

# Put Record from stdin (JSON)
echo '{"title":"Hello","content":"World"}' | xdb put xdb://com.example/posts/post-123

# Put Record from YAML file
xdb put xdb://com.example/posts/post-123 --file post.yaml --format yaml

# Put with explicit format
echo 'title: Hello
content: World' | xdb put xdb://com.example/posts/post-123 --format yaml

put creates or updates a Record at the given URI from a JSON or YAML file, or from stdin.

Flags:

  • --file, -f: Path to file (reads from stdin if omitted)
  • --format: Input format: json (default) or yaml

Remove

# Remove record (with confirmation prompt)
xdb remove xdb://com.example/posts/post-123

# Remove without confirmation
xdb rm xdb://com.example/posts/post-123 --force

# Remove schema
xdb rm xdb://com.example/posts --force

remove (aliases: rm, delete) deletes a Record, Attribute, or Schema at the given URI.

Flags:

  • --force, -f: Skip confirmation prompt

Daemon

# Start the daemon
xdb daemon start

# Check daemon status
xdb daemon status

# Stop the daemon
xdb daemon stop

# Force stop the daemon
xdb daemon stop --force

# Restart the daemon
xdb daemon restart

The daemon runs an HTTP server that handles all XDB operations. By default it listens on localhost:8147 and a Unix socket at ~/.xdb/xdb.sock.

Global Flags

These flags are available for all commands:

  • --output, -o: Output format (json, table, yaml). Auto-detected by default (table for TTY, JSON for pipes)
  • --config, -c: Path to config file (defaults to ~/.xdb/config.json)
  • --verbose, -v: Enable verbose logging (INFO level)
  • --debug: Enable debug logging with source locations

Output Formats

Automatic Format Selection

By default, XDB automatically selects the appropriate format:

  • Table format: When output is a terminal (TTY) - human-readable tables
  • JSON format: When output is piped or redirected - machine-parseable

Available Formats

  • json: Indented JSON output (machine-readable)
  • table: Human-readable tables with borders
  • yaml: YAML output

Example

# Uses table format (interactive terminal)
xdb get xdb://com.example/users/123

# Uses JSON format (piped to jq)
xdb get xdb://com.example/users/123 | jq '.name'

# Force JSON output even in terminal
xdb get xdb://com.example/users/123 --output json

# Force table output even when piping
xdb ls xdb://com.example/users --output table

Piping and Automation

XDB commands work well with Unix pipes:

# Get record and pipe to jq
xdb get xdb://com.example/posts/post-123 | jq '.title'

# List schemas and count them
xdb ls xdb://com.example | jq '. | length'

# Export records to file
xdb get xdb://com.example/posts/post-123 --output json > backup.json

# Import from file
cat backup.json | xdb put xdb://com.example/posts/post-123

Configuration

XDB uses a JSON config file at ~/.xdb/config.json. A default config is created automatically on first run.

{
  "dir": "~/.xdb",
  "daemon": {
    "addr": "localhost:8147",
    "socket": "xdb.sock"
  },
  "log_level": "info",
  "store": {
    "backend": "memory"
  }
}

Store Backends

  • memory (default): In-memory store, data is lost on restart
  • sqlite: SQLite database, stored in <dir>/data/
  • redis: Redis server, requires addr to be configured
  • fs: Filesystem store, stored in <dir>/data/ by default

Example with SQLite:

{
  "store": {
    "backend": "sqlite",
    "sqlite": {
      "dir": "",
      "name": "xdb.db"
    }
  }
}

Example with Redis:

{
  "store": {
    "backend": "redis",
    "redis": {
      "addr": "localhost:6379"
    }
  }
}

See xdb.example.yaml for a full reference of all configuration options.

About

An agent-first data layer. Model once, store anywhere.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors