Skip to main content

Quickstart

From nothing to a live sidecar handling KV, Episodic, Semantic, Artifact, Lease, and Graph, over gRPC and HTTP, in a couple of minutes. Two paths: Docker Compose (nothing to install) or a local Go build. If you would rather grab a released binary or the published image, see Install.

This page uses a publicly known keypair

The PASETO keypair below is a development key whose private half is committed to this repository. It appears in configs/example.yaml, configs/compose.yaml, docker-compose.yml, README.md, examples/README.md and on this page.

Anyone who has read the repository can mint a valid token for any tenant, any namespace and any op against a server that trusts it. Use it on your own machine and nowhere else.

For anything past a laptop, generate your own:

mindctl token gen-keypair

Put the public_key_hex in your config and keep the secret_key_hex with whatever issues your tokens. See Security.

Fastest: Docker Compose

Brings up mindD backed by Postgres (pgvector) and MinIO (S3), with helpers to mint a token and drive the data plane. No Go or buf toolchain needed.

git clone https://github.com/vibed-project/mindD.git
cd mindD
docker compose up --build -d # gRPC :7777, HTTP :8080, metrics :9090

# Mint a dev capability token (-T keeps the output clean).
export MINDD_TOKEN=$(docker compose run --rm -T token)

# Talk to it. No grpcurl needed, just mindctl:
docker compose run --rm -T mindctl kv put scratchpad hello world --token "$MINDD_TOKEN"
docker compose run --rm -T mindctl kv get scratchpad hello --token "$MINDD_TOKEN"
docker compose run --rm -T mindctl ns ls --token "$MINDD_TOKEN"

docker compose down -v tears it all down.

The token helper signs with the dev private key set in docker-compose.yml (the x-paseto-secret anchor); the server trusts its public half from configs/compose.yaml. Local use only.

Or: local build

Prerequisites

  • Go 1.26+
  • buf, only if you want to regenerate the stubs; the checked-in gen/ already has them.
brew install bufbuild/buf/buf

Build and run

git clone https://github.com/vibed-project/mindD.git
cd mindD
make build # produces bin/mindd and bin/mindctl
./bin/mindd --config configs/example.yaml

--config is required; there is no default path in the binary. (The container image supplies /etc/mindd/config.yaml through its CMD.)

You'll see structured JSON logs on stderr reporting each listener:

{"msg":"listening","transport":"tcp","addr":"127.0.0.1:7777","security":"plaintext"}
{"msg":"listening","transport":"unix","addr":"/tmp/mindd.sock"}
{"msg":"mindd ready","version":"v0.1.0","commit":"..."}

Mint a capability token

The dev keypair shipped in configs/example.yaml is for local use only. See the warning at the top of this page.

export MINDD_PASETO_SECRET_HEX=38fb82e74985d41969ce39904d7cbe01dd31ea0b573dc8fc35c5689b8212ccc961a2d0067233cf8d6570c76f37573cbc31d33032ab256fe0c8032c0987d0fbf9

export MINDD_TOKEN=$(./bin/mindctl token issue \
--tenant acme --agent agent-1 \
--ns 'kv/*,episodic/events,semantic/notes,artifact/blobs,lease/locks,graph/knowledge' \
--ops '*' --ttl 1h)

--ops '*' is a development shortcut. In real deployments, mint fully-qualified ops (kv.get, kv.put), never bare verbs: a bare verb matches across every block, so --ops inspect also grants admin.inspect, which is not namespace scoped. See Capability tokens.

Talk to it with mindctl

mindctl speaks part of the data plane too, using the token you just issued. It reads $MINDD_TOKEN and $MINDD_ADDR (default 127.0.0.1:7777), and takes --token, --addr and --tls on every data-plane command:

mindctl kv put scratchpad hello world --ttl 5m
mindctl kv get scratchpad hello
mindctl semantic search notes "capital of France" --top-k 3
mindctl graph neighbors knowledge paris
mindctl episodic tail events --historical # live stream; Ctrl-C to stop
mindctl ns ls # namespaces + live item counts

That is the whole data-plane surface of the CLI in v0.1.0: kv get, kv put, semantic search, episodic tail, graph neighbors and ns ls. Everything else (artifact, lease, kv scan and delete, episodic append and range) goes through the SDKs, raw gRPC, or the HTTP gateway.

HTTP/JSON gateway

Unary RPCs on kv, episodic, semantic, artifact and lease are also reachable over HTTP, same service, different transport:

curl -sS -X POST http://127.0.0.1:8080/mindd.kv.v1.KV/Put \
-H "x-mindd-capability: Bearer $MINDD_TOKEN" \
-H "Content-Type: application/json" \
-d '{"namespace":"scratchpad","key":"hello","value":"d29ybGQ="}'

graph and admin are not registered on the gateway; use gRPC or an SDK for those. See HTTP / JSON gateway.

Python

import datetime as dt
from mindd import MindD

with MindD("127.0.0.1:7777", token=TOKEN) as m:
m.kv.put("scratchpad", "hello", b"world", ttl=dt.timedelta(minutes=5))
print(m.kv.get("scratchpad", "hello").value) # b"world"

Install the SDK with pip install ./sdk/python, then take the whole tour:

python examples/agent_tour.py # exercises every block as one agent turn

agent_tour.py reads $MINDD_TOKEN and $MINDD_TARGET (default 127.0.0.1:7777).

TypeScript

import { MindD } from "@mindd/client";

const m = new MindD("127.0.0.1:7777", { token: process.env.MINDD_TOKEN! });
await m.kv.put("scratchpad", "hello", new TextEncoder().encode("world"));
const rec = await m.kv.get("scratchpad", "hello");

See examples/, Python SDK and TypeScript SDK.

What just happened

Every request you fired went through the same interceptor chain:

recovery -> observability -> auth -> policy -> service

auth decoded the PASETO token and attached the capability to the request context. policy consulted the YAML rules in your config (configs/example.yaml sets default: allow plus a deny, a rate limit and a cap rule). service checked the capability again against the namespace and op, then dispatched to the per-block driver.

Next steps