TessariDB
Get started

Get started

One binary, and a store in memory.

There is no server package to install beside a client package, no JVM, no separate agent, and no configuration file that has to exist before the process will start. The engine is a beta, and its repository is private while it is, but the published image is not, so the shortest path to a running node asks for no permission at all.

1 — Run one

The published image needs no repository access, no toolchain and no C++ compiler. It opens the wire protocol on 9080 and HTTP on 8000, from one process over one store.

A node, from nothingshell
docker run -d --name tessaridb \
  -p 9080:9080 -p 8000:8000 \
  -v tessaridb-data:/var/lib/tessaridb \
  -e TESSARIDB_INITIAL_USER=owner \
  -e TESSARIDB_INITIAL_PASSWORD='choose-a-real-one' \
  tessaridb/tessaridb

Those last two variables are the ones to get right. A store with no users is open — it runs anything for anybody who reaches the port, because the first user is what closes it, and nothing types that into a node that came up unattended. The node declares that user once, on a store that has none, and leaves an existing store alone every time after. Set only one of the pair and it refuses to start, rather than coming up open because a variable was misspelled.

The image carries no default credential on purpose: one would close every store that pulls it with a password the whole internet knows. In a container lists every variable it reads, the volume’s ownership, and what the image does and does not contain.

Then open http://localhost:8000. The web console is served by the binary itself — it is not a second thing to install, and it is already in the image.

2 — Access, for the source

Write to hello@tessaridb.com and say what you intend to build. The licence that comes with it is the one below — free to use in production, including commercially, with a single restriction on reselling it as a database service.

Two parts of the project are public today and need no permission: the wire specification with the conformance corpus every client is checked against, and the Rust client, which is Apache-2.0. Both are worth reading before you have a build — and so is the documentation, which describes the engine as it behaves today rather than as it is planned to behave.

3 — Build

Rust1.85 or newer — the crate’s declared minimum. Edition 2024.
A C++ toolchainThe storage layer builds a native library.
DiskA directory the process can write to — or nothing at all, for a store in memory.

Nothing else. No system libraries are loaded dynamically at run time, which is why the release binary can be copied to a machine that has none of the above.

The buildshell
cargo build --release
# the result is target/release/tessaridb

The first build takes a while, and most of that is the storage engine’s native library rather than the Rust.

4 — A store, three ways

The same binary is the shell, the server and the store. Which of those it is depends on the arguments, not on which package you installed.

One binary, and the argument list decides which of the three you get. The middle panel is the first one whose records outlive the process; the third adds a port and nothing else — the store underneath it is the same store, opened the same way.
Running itshell
tessaridb                                  # in memory, lost when it exits
tessaridb ./data                           # on disk
tessaridb ./data --serve 127.0.0.1:7654    # over the wire protocol
tessaridb ./data --http 127.0.0.1:8080     # over HTTP; may accompany --serve
tessaridb --at 127.0.0.1:7654              # a shell against a running node

With neither -e nor -f, statements are read from standard input — a prompt when that is a terminal, a script when it is a pipe. Which is what makes the next step a single line.

5 — The first answer

A namespace holds databases, a database holds tables, and a table holds records. USE selects where the statements after it apply and stays in force for the rest of the connection — a connection is a session, not a single round trip.

A table says what its columns are, and refuses a record carrying one it does not know — declaring which fields there are is the act that says which ones there are not. Where the shape is not fixed, the word is DEFINE COLLECTION, and every field is accepted.

From an empty process to a recordtessariql
DEFINE NAMESPACE demo;
USE NAMESPACE demo;
DEFINE DATABASE app;
USE DATABASE app;

DEFINE TABLE users (name string, email string);
CREATE users = { name: 'ada', email: 'ada@example.com' };

SELECT * FROM users:1;
the node answers
1: { email: 'ada@example.com', name: 'ada' }
(1 record(s), via record)

The write names no id, so the table’s counter supplies one and the write answers with it — 1, making the address users:1. The id is part of that address rather than a column inside the record, which is why that read needs no WHERE and no index — and why the node reports it as via record rather than via an index or a scan.

6 — With a coding agent

An agent writes TessariQL the way it writes any language it half knows: from memory, and confidently. The tessaridb plugin gives Claude Code and Codex the language as it is — every engine, transactions, the clients, running a node — and leads with the mistakes that run without an error. Its examples are run against the release it names. It needs no server.

Claude Codeshell
/plugin marketplace add tessaridb/tessaridb-agent-plugins
/plugin install tessaridb@tessaridb
Codexshell
codex plugin marketplace add tessaridb/tessaridb-agent-plugins
codex plugin add tessaridb@tessaridb

The same marketplace carries Agent Memory, a memory for the agent that is stored in TessariDB. What each plugin installs is in the documentation.