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 | sh

The 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-cli

2. Start the engine

primitives dev

primitives 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/sdk
pip install useprimitives

The 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

setup.mts
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.mts

The same in Python:

setup.py
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-42

To 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 undone

The 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 group

Pass the same --data directory you gave primitives dev.

Cloud

The cloud runs the same engine, so only the credentials and URLs change:

  1. 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.
  2. Pass it to the SDK. With a pk_ key, the SDK defaults to https://api.useprimitives.com.
cloud.mts
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');
  1. Connect Claude Code with only the URL. It opens a browser where you sign in, pick agent-42 and the tools, and click Allow:
claude mcp add --transport http primitives https://mcp.useprimitives.com/mcp

For 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