Agent index (llms.txt) — fetch this first, then the page it names.

Quickstart

This takes you from nothing to a deployed site and a working database call. It assumes someone runs an Orama cluster you can reach (your own, see Install a cluster from scratch, or one you were given access to). You need its gateway URL, for example https://cluster.example.com.

1. Install the tools

bash
brew install DeBrosDAO/tap/orama      # the CLI
orama version
npm install @debros/orama             # the SDK, in your app

You also need a wallet that can sign. Install RootWallet (desktop, or the rw CLI), create a wallet, and leave it unlocked. Orama has no accounts and no passwords: your wallet address is your identity.

2. Tell the CLI which cluster to use

A fresh CLI knows no cluster. Add yours:

bash
orama network add mycluster https://cluster.example.com
orama network use mycluster

orama network list and orama network current show what is configured. If the cluster uses Let's Encrypt staging certificates, add --ca-file le-staging.pem (TLS and certificates).

3. Sign in

bash
orama auth login
orama auth whoami      # asks the gateway who you are and what you may do
orama auth status      # what is stored on this machine (asks nobody)

The CLI asks RootWallet to sign a challenge from the gateway. What it stores is a session: an access token that lasts 15 minutes and renews itself from a 30-day refresh token. This is the lobby sign-in: you are in, but you hold no namespace yet. On a machine with no wallet (a server over SSH, CI), orama auth login prints a code, and orama auth approve <code> on a machine that has your wallet approves it. See Sign-in and sessions.

4. Create a namespace

A namespace is your own small cluster: a database, a cache and a gateway on three nodes. You own what you create.

bash
orama namespace create myapp
orama auth login --namespace myapp

Creating a namespace does not sign you in to it; the second command does. Some clusters allow only their operators to create namespaces; if yours refuses, ask an operator (Cluster administration). See Namespaces.

5. Deploy something

bash
mkdir site && echo '<h1>Hello from Orama</h1>' > site/index.html
orama deploy static ./site --name www
orama app list
orama app get www

orama deploy static publishes a directory as a deployment and prints its URL, a name under the cluster's base domain. Other runtimes: Next.js, Go and Node.js backends (Deployments).

6. Use a database

bash
orama db create appdb
orama db query appdb "CREATE TABLE notes (id INTEGER PRIMARY KEY, text TEXT)"
orama db query appdb "INSERT INTO notes (text) VALUES ('hello')"
orama db query appdb "SELECT * FROM notes"

This is a per-namespace SQLite database, reached from the CLI. The namespace also has a replicated SQL database (RQLite) that your code reaches through the SDK, shown next. See Databases.

7. Call it from code

What a key may do depends on its grants. Two keys cover a typical app.

On a server, in CI or in a script: an admin key. It reaches the control plane, including the namespace's RQLite database, so it never goes in a browser or mobile bundle.

bash
orama namespace keys create --scope admin --label server

The command prints the key once, after a short report. Copy the line under API KEY into your secret store; it cannot be shown again.

ts
import { createClient } from "@debros/orama";

const server = createClient({
  baseURL: "https://ns-myapp.cluster.example.com",
  apiKey: process.env.ORAMA_API_KEY,
});

await server.db.createTable("CREATE TABLE messages (id INTEGER PRIMARY KEY, room TEXT, body TEXT)");
await server.db.exec("INSERT INTO messages (room, body) VALUES (?, ?)", ["general", "hi"]);
const rows = await server.db.query("SELECT * FROM messages WHERE room = ?", ["general"]);

In a browser or mobile app: a key with data-plane grants only, named explicitly. The app-runtime profile does not include pubsub or cache, so ask for them.

bash
orama namespace keys create --scope invoke,pubsub,cache --label web
ts
const client = createClient({
  baseURL: "https://ns-myapp.cluster.example.com",
  apiKey: process.env.ORAMA_WEB_KEY,      // injected at build time
});

await client.cache.put("sessions", "alice", { seen: Date.now() }, "1h");
await client.pubsub.publish("room:general", "hello");

Storage is different: the gateway refuses a key on its own and wants the signed-in user as well, so upload after the user has signed in with their wallet (Wallet login):

ts
const { cid } = await client.storage.upload(new Blob(["file contents"]), "hello.txt");

Where a key may live, and what each profile can do: Access control and keys. The full client: TypeScript SDK.

CI and scripts

Set ORAMA_TOKEN to an API key or a token. A key is exchanged for a session once per run. Mint the key once on your machine (add --expires-in-days to shorten its life, 90 days is the default), put it in your CI system's secret store, and expose it to the job:

bash
orama namespace keys create --scope admin --label ci      # prints the key once; store it
bash
export ORAMA_TOKEN="$CI_ORAMA_KEY"      # from the CI secret store
orama deploy static ./dist --name www --update

Sessions, API keys, members and audit

The CLI signs in with your wallet and stores a session, not a key: an access token that lasts 15 minutes and renews itself from a 30-day refresh token. orama auth login asks which namespace to sign in to; blank signs in without one. With no terminal to ask (a script, a pipe, CI) it does not prompt and signs in without one; pass --namespace <name> to choose.

Which machines are signed in

bash
orama auth sessions                  # every live session for this wallet
orama auth sessions revoke <id>      # end one
orama auth sessions revoke --all     # end all of them

Ending a session stops it minting new access tokens, and refuses the access tokens it already minted — and closes the sockets they hold open — within ten seconds. A session issued before sessions carried an id cannot be named that way: its access tokens work until they expire, at most 15 minutes, and the command says so.

Namespaces and environments

Creating a namespace is its own step, and the wallet that makes it owns it:

bash
orama namespace create myapp
orama auth login --namespace myapp

Signing in to a namespace that does not exist used to create it, so a typo made a namespace and one belonged to whoever happened to sign in first. It answers 404 now, naming the command above.

One machine can hold credentials for several environments. orama auth list shows them, orama auth switch changes the active one, and orama auth logout clears it. Which gateway a command talks to is decided by the active environment — see orama network — not by a flag on each command.

Every command and flag is in the CLI reference, which is generated from the command tree rather than written by hand.

API keys for your application

Deploying uses your own credentials. An application that talks to the gateway at runtime needs a key of its own, and which one depends on where the code runs:

bash
# Safe in a browser bundle: data-plane grants only
orama namespace keys create --scope app-runtime --label web

# Server-side only: the whole control plane
orama namespace keys create --scope admin --label ci

orama namespace keys list
orama namespace keys revoke --id <id>

A key carries a set of grants and the gateway refuses an operation whose grant the key does not hold, naming the one it needed. --scope takes a profile (invoke-only, app-runtime, admin) or an explicit grant list. See Where a key belongs.

Every key expires — 90 days by default, a year at most — and orama namespace keys rotate --id <id> mints a successor with the same grants while leaving the original alive for a week, so there is a window in which to deploy the new one.

Working with other people

A namespace has one owner and any number of members, and a member holds a role:

bash
orama members list
orama members add 0xabc… --role admin     # the control plane
orama members add 0xdef… --role runtime   # the data plane
orama members remove 0xabc…
orama members transfer 0xabc…             # hand the namespace over

admin is everything except ownership; runtime is invoke, storage, push, webrtc, proxy, pubsub and cache; reader is a member with no grant at all. Ownership is transferred rather than granted, and it is one step rather than a removal and a grant, so there is no moment where the namespace has no owner. You keep an admin grant, so handing a project over does not lock you out of it.

What happened, and who did it

bash
orama audit                 # oldest first
orama audit --follow        # and keep printing

Sign-ins, keys minted and revoked, grants given and taken away, deployments, functions, secrets and namespace changes, each with who did it and from where. Events are kept 90 days.

The whole model — identities, roles, grants, tokens, and what each refusal means — is in the technical reference's authorization chapter (docs/whitepaper/technical-reference/vol1/14-authorization.md).

Where next

You want toRead
Understand the unit you work inNamespaces
Let your users sign in with walletsSign-in and sessions, Devices
Invite teammates, scope a keyAccess control and keys
BuildDeployments, Databases, Functions, Storage, Pub/sub, WebRTC, Push
Look up a commandCLI overview
See what Orama is and is notHow you talk to the network