Caura / docs
Tutorials

Your first memories on Caura Cloud

The five-minute Cloud starter — sign up, mint a key, write three memories, recall them with completely different words, and see them in Prism.

Managed (Cloud) starter — the smallest end-to-end tutorial. You just signed up and want to see memory work before wiring up any agents. Ready for a real multi-agent build afterwards? That's Build an agent fleet on Caura Cloud. Prefer to run Caura yourself? Start with the self-hosted OSS series.

You just signed up at caura.ai — or you're about to. Before wiring up agents, fleets, or MCP configs, you should see the core trick with your own eyes: you write a plain sentence, and Caura turns it into enriched, searchable memory you can find again with completely different words.

That's this tutorial. No SDK, no install, no agent harness — just a terminal. Every command below has a bash and a PowerShell version, so Linux, macOS and Windows all work by copy-paste. In five minutes you will:

  1. Sign up and mint an API key
  2. Write three memories
  3. Recall them with words they don't contain
  4. See them in Prism, your hosted dashboard

Everything you do here by hand is exactly what an AI agent does automatically over MCP — so when you graduate to the fleet tutorial, nothing will feel like magic.


The idea in one picture

   "We chose PostgreSQL over MongoDB."      ← you write plain text


        ┌─────────────────────┐
        │    Caura Cloud    │
        │  classify · title   │
        │  entities · weight  │
        │  PII scan · embed   │
        └─────────────────────┘


   "database choice for the orders service" ← recalled by meaning,
                 │                            not by keywords

        your memory, ranked first

One raw sentence in; a classified, titled, embedded, governed memory out. Recall works on meaning — the word "database" appears nowhere in what you wrote.


Step 1 — Sign up & mint a key (2 minutes)

Sign up at caura.ai/get-started and create a project — that's your isolated tenant. In the project's API keys screen, mint a key (it starts with mc_). Treat the key like a password; it scopes every call to your project.

Export it so the commands below are copy-paste. Pick your shell and stay in that tab for the whole tutorial — every command below appears in both:

export CAURA_URL=https://caura.ai
export CAURA_KEY=mc_xxxxxxxxxxxxxxxxxxxx   # your project API key
$env:CAURA_URL = "https://caura.ai"
$env:CAURA_KEY = "mc_xxxxxxxxxxxxxxxxxxxx"   # your project API key

Names, for the avoidable confusion. These are ordinary shell variables — nothing on the platform reads them, so call them whatever you like. If you have followed older Caura docs you will have seen MEMCLAW_* instead; MemClaw is the former product name and the two are interchangeable here. API keys still carry the mc_ prefix on the wire, and the MCP server block near the bottom of this page is named caura. All expected.

Confirm the platform is reachable:

curl "$CAURA_URL/api/v1/health" -H "X-API-Key: $CAURA_KEY"
# {"status": "ok", "storage": "connected", "redis": "connected", "event_bus": "ok"}
Invoke-RestMethod "$env:CAURA_URL/api/v1/health" -Headers @{ "X-API-Key" = $env:CAURA_KEY }
# status storage   redis     event_bus
# ------ -------   -----     ---------
# ok     connected connected ok

REST calls name your project explicitly with a tenant_id. Ask the platform who your key is — whoami returns it:

curl "$CAURA_URL/api/v1/whoami" -H "X-API-Key: $CAURA_KEY"
Invoke-RestMethod "$env:CAURA_URL/api/v1/whoami" -Headers @{ "X-API-Key" = $env:CAURA_KEY }
{
  "tenant_id": "ten2-7c41f2",
  "agent_id": null,
  "auth_mode": "tenant",
  "auth_source": "gateway-header",
  "via_gateway": true,
  "readable_tenant_ids": ["ten2-7c41f2"],
  "capabilities": ["read", "write"]
}

Use your own tenant_id from that response, not the one above — every project gets its own, and your key only works against yours. The example just shows the shape: Cloud tenant ids are ten2- prefixed.

export CAURA_TENANT=ten2-7c41f2              # replace with YOUR tenant_id
$env:CAURA_TENANT = "ten2-7c41f2"            # replace with YOUR tenant_id

Step 2 — Write your first memory

A memory is natural-language content plus two identifiers: tenant_id (your project) and agent_id (whoever is writing). You're not an agent yet, so call yourself me:

curl -X POST "$CAURA_URL/api/v1/memories" \
  -H "X-API-Key: $CAURA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tenant_id": "'$CAURA_TENANT'", "agent_id": "me", "content": "I prefer concise answers, dark mode, and metric units."}'
$body = @{
  tenant_id = $env:CAURA_TENANT
  agent_id  = "me"
  content   = "I prefer concise answers, dark mode, and metric units."
} | ConvertTo-Json

Invoke-RestMethod -Method Post "$env:CAURA_URL/api/v1/memories" `
  -Headers @{ "X-API-Key" = $env:CAURA_KEY } `
  -ContentType "application/json" -Body $body

Noteagent_id is required on Cloud. Leave it out and the write is rejected with a 422: "agent_id is required; only the standalone single-tenant deployment may omit it." Later, when real agents write memories, this identity is what governance hangs off.

The 201 comes back in about a second, and it is deliberately half-finished:

{
  "id": "3f6a1c9e-…",
  "memory_type": "fact",
  "title": null,
  "weight": 0.5,
  "status": "active",
  "metadata": { "enrichment_pending": true, "embedding_pending": true, "write_latency_ms": 74 }
}

That null title and default 0.5 weight are not a failure. Caura acknowledges the write as soon as it is durable — that's the write_latency_ms you see — and then classify, title, extract entities, scan for PII, and embed run asynchronously. The two *_pending flags tell you the second half is still in flight; they clear in roughly 3–5 seconds, and the fields above are exactly the ones that get upgraded.

Save that id. We'll fetch the finished object after the next step.


Step 3 — Write two more, then look at what Caura did

Memories get interesting in variety. Write a decision and a warning:

curl -X POST "$CAURA_URL/api/v1/memories" \
  -H "X-API-Key: $CAURA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tenant_id": "'$CAURA_TENANT'", "agent_id": "me", "content": "We chose PostgreSQL over MongoDB for the orders service because we need transactions."}'

curl -X POST "$CAURA_URL/api/v1/memories" \
  -H "X-API-Key: $CAURA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tenant_id": "'$CAURA_TENANT'", "agent_id": "me", "content": "Gotcha: the staging environment resets every Sunday night — do not leave test data there."}'
function New-CauraMemory($content) {
  $body = @{ tenant_id = $env:CAURA_TENANT; agent_id = "me"; content = $content } | ConvertTo-Json
  Invoke-RestMethod -Method Post "$env:CAURA_URL/api/v1/memories" `
    -Headers @{ "X-API-Key" = $env:CAURA_KEY } `
    -ContentType "application/json" -Body $body
}

New-CauraMemory "We chose PostgreSQL over MongoDB for the orders service because we need transactions."
New-CauraMemory "Gotcha: the staging environment resets every Sunday night — do not leave test data there."

Now wait for enrichment. Rather than guessing, poll the flag — metadata.enrichment_pending flips to false when the LLM pass has landed (typically 3–5 seconds; embedding follows a beat later, and until embedding_pending clears too the memory is findable by keyword but not yet by pure meaning):

curl "$CAURA_URL/api/v1/memories/YOUR_MEMORY_ID?tenant_id=$CAURA_TENANT" \
  -H "X-API-Key: $CAURA_KEY"
Invoke-RestMethod "$env:CAURA_URL/api/v1/memories/YOUR_MEMORY_ID?tenant_id=$env:CAURA_TENANT" `
  -Headers @{ "X-API-Key" = $env:CAURA_KEY }

Your one raw sentence now looks like this:

{
  "memory_type": "decision",
  "title": "Chose PostgreSQL over MongoDB for orders service",
  "weight": 0.85,
  "status": "confirmed",
  "entity_links": [
    { "canonical_name": "postgresql",     "entity_type": "technology" },
    { "canonical_name": "mongodb",        "entity_type": "technology" },
    { "canonical_name": "orders service", "entity_type": "project" },
    { "canonical_name": "transactions",   "entity_type": "concept" }
  ]
}

An LLM classified it as a decision, titled it, weighted its importance, and extracted four linked entities — from a sentence you typed in five seconds.

Fetch your other two memories and compare. The preference lands as preference with weight 0.7; the staging warning lands as fact with a title and tags of its own. The classifier picks from a fixed taxonomy — fact, episode, decision, preference, task, intention, plan, commitment, action, cancellation — and fact is where durable "this is how the world works" knowledge goes, warnings included. There is no gotcha type; the word in your sentence is content, not a label. What you should take from the comparison is the differentiated weight0.85 for the decision, 0.7 for the preference, 0.5 default — because that is what later shapes how each memory is ranked, maintained, and retired.

Re-running a write returns 409, not a silent no-op. If you re-run one of the curls above — after a typo, in a fresh shell, or just to check it worked — you get an error, not a second copy:

{ "detail": "Duplicate memory exists: 908f612d-…",
  "error": { "code": "CONFLICT", "message": "Duplicate memory exists: 908f612d-…" } }

This is by design: identical content is rejected rather than stored twice, and the response hands you the id of the memory that already holds it, so a client can treat the 409 as "already done" and carry on with that id. Worth knowing before you see red in your terminal.


Step 4 — Recall with different words

Here's the point of all this. Ask about the database decision without using the words you wrote:

curl -X POST "$CAURA_URL/api/v1/search" \
  -H "X-API-Key: $CAURA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"tenant_id": "'$CAURA_TENANT'", "query": "database choice for the orders service", "top_k": 5}'
$body = @{
  tenant_id = $env:CAURA_TENANT
  query     = "database choice for the orders service"
  top_k     = 5
} | ConvertTo-Json

Invoke-RestMethod -Method Post "$env:CAURA_URL/api/v1/search" `
  -Headers @{ "X-API-Key" = $env:CAURA_KEY } `
  -ContentType "application/json" -Body $body

The decision comes back first, under an items array with a similarity score:

{ "items": [ {
  "title": "Chose PostgreSQL over MongoDB for orders service",
  "memory_type": "decision", "similarity": 0.7263,
  "agent_id": "me", "visibility": "scope_team"
} ] }

Look at what just happened: the query says "database" — your memory never does, it says PostgreSQL and MongoDB. It says "choice" — you wrote "chose". Vector semantic similarity, blended with keyword matching and knowledge-graph expansion, bridges the gap.

Two more worth trying, both of which share no vocabulary at all with the memory they find:

"is it safe to leave data in the pre-production environment"   → your staging warning
"how should I format my replies to this user"                   → your dark-mode preference

Neither query contains "staging", "resets", "concise", or "dark" — and both land their memory at rank 1.

Phrasing matters more than it should today. Recall is strongest when your query names the things involved — the service, the system, the topic. Very short questions built mostly of filler ("which one did we pick and why") give the retriever almost nothing to anchor on: the words that carry meaning get filtered as stopwords before the query is ever scored, so the result set can come back weak or unranked. Name the subject and you get the behaviour above. We are actively improving this — see Memory pipeline concepts for what happens between write and recall.

A few limits worth knowing before you build on this:

  • top_k is capped at 20 on REST /search. Ask for 21 or more and you get a 422"Input should be less than or equal to 20". The default is 5. The caura_recall MCP tool agents use has no such cap.
  • Filtering by author is filter_agent_id, not agent_id. You wrote your memories with "agent_id": "me", but on /search that field is not a filter — the request schema's field is filter_agent_id, and an unrecognised agent_id key is currently accepted and ignored rather than rejected. Use {"filter_agent_id": "me"} to scope results to one author.
  • There is a similarity floor. Results scoring below it are dropped, so a query that is off-topic — or so vague it anchors on nothing — can legitimately return fewer items than your top_k.

Step 5 — See it in Prism

Open your dashboard at caura.ai. Prism is live from your very first write: your three memories are there with their inferred types, titles, and weights; the entities extracted from them (PostgreSQL, MongoDB, the orders service); and an audit entry for every call you just made.

That's the whole loop: write plain text → enriched automatically → recalled semantically → visible and governed in Prism.


Bonus — let your AI assistant do it

Everything above is what an AI agent does on its own over MCP. Each client keeps this config in a different file — follow the exact steps for Claude Desktop, Claude Code, Cursor, or Windsurf and any other MCP client — but the shape is always the same:

{
  "mcpServers": {
    "caura": {
      "url": "https://caura.ai/mcp",
      "headers": { "X-API-Key": "mc_xxxxxxxxxxxxxxxxxxxx" }
    }
  }
}

Restart the client, then say:

"Remember that I prefer concise answers and dark mode."

Later, in a fresh session:

"What do you know about my preferences?"

The agent calls caura_write and caura_recall for you — the same endpoints you just hit by hand. Same memories, same project, same dashboard.


Where to go from here

You've seen the primitive: plain text in, semantic recall out, everything visible in Prism. Next steps:

  • Build an agent fleet on Caura Cloud — the natural next step: three Claude Code agents sharing this same memory, with identities, trust tiers, and governance.
  • Memory pipeline concepts — what actually happens to a sentence between write and recall.
  • Mind the free tier — 10K memories, 5K writes, 5K searches, and 500 recalls per month (the /search calls you just made draw on the searches quota); Prism shows current usage.

Caura Cloud — managed, governed memory for agent fleets, operated for you, with the Prism dashboard included.

Your first three memories took five minutes. Your agents' next ten thousand will take none of your time at all.