Getting started
Quickstart
Run the engine locally or use the cloud, create a group, and connect an MCP client.
This guide takes you from nothing to a working group: you run the engine, create a group, add a database to it, and connect Claude Code over MCP. It takes about five minutes. The cloud variant is at the end.
1. Install the CLI
Install the prebuilt binary for macOS or Linux (x64 and arm64):
curl -fsSL https://useprimitives.com/install.sh | shThe script downloads the latest release from GitHub, verifies its SHA-256 checksum and installs primitives to ~/.primitives/bin. If that directory isn't on your PATH, it prints the line to add. Set PRIMITIVES_VERSION (for example v0.1.0) to pin a release, or PRIMITIVES_INSTALL_DIR to install somewhere else.
On other platforms, or to build from source, use a Rust toolchain:
git clone https://github.com/useprimitives/primitives
cd primitives
cargo install --path crates/primitives-cli2. Start the engine
primitives devprimitives dev serves the REST API and MCP on http://localhost:7777. Data lives in ./.primitives (change it with --data <dir>, and the port with --port). Secrets are encrypted with a master key taken from PRIMITIVES_MASTER_KEY, else your OS keychain, else <data>/.master-key.
On localhost there is no authentication. To require a root token for account-level calls, start it with primitives dev --token <secret> and pass the same value as token to the SDK.
3. Install an SDK
npm i @primitives/sdkpip install useprimitivesThe TypeScript SDK needs Node.js 18 or later. The Python distribution is useprimitives, the import is primitives, and it needs Python 3.10 or later.
4. Create a group, add a database and run SQL
import { Primitives } from '@primitives/sdk';
const p = new Primitives(); // defaults to PRIMITIVES_URL or http://localhost:7777
const group = await p.groups.create({ name: 'agent-42' }); // starts empty
const db = await group.db.create('main'); // a named database in the group
console.log(db.id); // its immutable id; p.db(db.id) reaches it from anywhere
await db.exec('create table notes (id integer primary key, body text)');
await db.sql`insert into notes (body) values (${'hello'})`;
const { rows } = await db.query('select id, body from notes');
console.log(rows); // [ { id: 1, body: 'hello' } ]npx tsx setup.mtsThe same in Python:
import asyncio
from primitives import Primitives
async def main():
async with Primitives() as p:
group = await p.groups.create(name="agent-42")
db = await group.db.create("main")
await db.exec("create table notes (id integer primary key, body text)")
await db.exec("insert into notes (body) values (?)", ["hello"])
result = await db.query("select id, body from notes")
print(result.rows)
asyncio.run(main())Group names are unique: run either script twice and create fails with already_exists. Use p.groups.get('agent-42') to open an existing one, and group.db('main') (by name in the group) or p.db(id) (by id) to reach a database that already exists. A group starts empty: create each database, filesystem, queue, memory, vault, key-value store or object store you need with a name, and add as many of each as you like.
5. Connect Claude Code
Locally there is no token to create. primitives dev serves each group at its own URL with every tool allowed:
claude mcp add --transport http primitives http://localhost:7777/mcp/agent-42To narrow the tools, add ?tools= with the same patterns as an API key's, such as "http://localhost:7777/mcp/agent-42?tools=db_*,fs_*".
Claude now has tools such as primitive_list, db_query and primitive_create, all scoped to agent-42. It calls primitive_list to see the group's primitives, then passes one's id or name as primitive; with a single database in the group, db_query uses main without being told. Ask it to list the notes table. For Cursor, stdio clients and others, see Connect a client.
6. Clean up
await group.destroy({ force: true }); // deletes the group and its primitives; cannot be undoneThe CLI
The same binary manages groups and primitives directly in the data directory:
primitives group create agent-43
primitives primitive create orders --type db --group agent-43 # prints the id; --type is db, fs, queue, memory, vault, kv or storage
primitives primitive create workspace --type fs --group agent-43
primitives primitive list --group agent-43 [--type db]
primitives group info agent-43
ID=01jbz3k8m5q2w7x9v4n6t0r1ce # the id printed by create
primitives primitive info $ID
primitives primitive snapshot $ID --label before-import
primitives primitive snapshots $ID
primitives primitive restore $ID before-import
primitives primitive fork $ID --name orders-try [--group other] [--snapshot before-import]
primitives primitive rename $ID orders-v1
primitives primitive move $ID --group agent-44
primitives primitive pause $ID
primitives primitive resume $ID
primitives primitive delete $ID
primitives group destroy agent-43 --force # without --force, only an empty groupPass the same --data directory you gave primitives dev.
Cloud
The cloud runs the same engine, so only the credentials and URLs change:
- Sign in at app.useprimitives.com and create an API key. Keys start with
pk_and are scoped to one group or the whole workspace, optionally limited to some tools. A workspace key belongs on your server, never in an agent. - Pass it to the SDK. With a
pk_key, the SDK defaults tohttps://api.useprimitives.com.
import { Primitives } from '@primitives/sdk';
const p = new Primitives({ token: process.env.PRIMITIVES_API_KEY }); // pk_…
const group = await p.groups.create({ name: 'agent-42' });
await group.db.create('main');- Connect Claude Code with only the URL. It opens a browser where you sign in, pick
agent-42and the tools, and click Allow:
claude mcp add --transport http primitives https://mcp.useprimitives.com/mcpFor an agent you run yourself, create a second API key scoped to agent-42 and the tools it needs, and send it as Authorization: Bearer pk_…. See Connect a client.
Next steps
- Learn how groups hold primitives, and how each one snapshots and forks.
- Read the MCP tools reference.
- Keep agent state in KV and share files with signed URLs from Storage.
- Fork and snapshot primitives before a risky change.