# Memory & Observability

> How to connect memory and observability to agents in the browser, from the CLI, or via MCP — same grant model on every surface.

Part of the jurniti developer docs — canonical page: https://www.jurniti.com/docs/memory-observability · full docs index: https://www.jurniti.com/docs/llms.txt

## What “connected” means

Your agents run in isolated microVMs. **Memory** and **Observability** are
optional **sidecar** microVMs you buy, then **connect (grant)** to agents you
own. Until you connect them, the agent does not see that sidecar.

| Sidecar | Providers | After you connect |
| --- | --- | --- |
| **Memory** | Obsidian, gbrain, mem0 | Agent can read/write that memory over MCP |
| **Observability** | Latitude, Langfuse | Agent emits traces into that sidecar |

**Buy** and **connect** are separate steps:

1. **Buy** — provision the sidecar VM (usually in the dashboard).
2. **Connect** — grant that sidecar to a specific **agent** VM (dashboard, CLI,
   or MCP).

A connection from the UI shows up in `jurniti memory ls`. A CLI grant shows up
on the Memories page. Same control plane.

---

## How to connect memory

### A. In the browser (dashboard)

You need at least one **agent** already running (see [Quickstart](/docs/quickstart)).

      ### Open Memories

    Go to **[Memories](https://app.jurniti.com/dashboard/memories)**  
    (`app.jurniti.com` → left nav **Memories**, or `/dashboard/memories`).

    Sign in with your magic link if you are not already logged in.
        ### Buy a memory (if you do not have one yet)

    Under the provider picker, choose **Obsidian**, **gbrain**, or **mem0**,
    complete Stripe checkout. jurniti provisions a memory microVM (~3 minutes).

    When it is ready, it appears under **Your memories** on the same page.
    The platform also auto-creates the MCP connection for that memory (you
    never paste a token).
        ### Connect it to an agent

    On the memory’s card, find **Connected agents** (count like `0/N` or
    `1/N`).

    Each of **your agent VMs** is listed as a row. For the agent you want:

    - Click **Connect** (or the plug control on that row).
    - The row switches to connected; the label becomes **Disconnect**.

    That is the grant. Repeat for other agents if you want several wired to
    the same memory.

    To disconnect: click **Disconnect** on that agent’s row.
        ### Confirm it worked

    - On the card, **Connected agents** should show the agent as connected.
    - Or from a terminal (optional): `jurniti memory ls` — that agent’s id
      appears under `GRANTED_VMS`.

    The platform injects MCP config into the agent guest. The agent can use
    the memory on the next session that loads MCP clients (restart the
    agent process if it was already mid-session).
  
> **What you cannot connect:** Only **agent** VMs appear as connect targets. You cannot connect a memory into another memory or an observability sidecar — the API returns `invalid_agent`.

---

### B. From the CLI

Prerequisites:

- [CLI installed and logged in](/docs/installation) (`jurniti login`)
- A **read-write** API key (read-only keys can list, not connect)
- A memory already bought (step A.2, or any existing connection from
  `jurniti memory ls`)

```bash
# 1. See connections (ids look like mcpc_…) and which agents already have them
jurniti memory ls

# 2. Find the agent VM id
jurniti vms ls
# pick a row that is an agent (Hermes, Claude Code, …), not the memory VM

# 3. Connect
jurniti memory grant --connection mcpc_YOUR_ID --vm vm-YOUR_AGENT_ID
# → granted connection mcpc_… to agent vm-…

# 4. Confirm
jurniti memory ls
# GRANTED_VMS column should list vm-YOUR_AGENT_ID

# Disconnect later
jurniti memory revoke --connection mcpc_YOUR_ID --vm vm-YOUR_AGENT_ID
```

Example shape:

```bash
jurniti memory ls
# ID                             NAME              PROVIDER         GRANTED_VMS
# mcpc_19ef3c3cc443ea7dea465a68  memory-vm-…       memoryobsidian   -

jurniti memory grant \
  --connection mcpc_19ef3c3cc443ea7dea465a68 \
  --vm vm-68648d6a5722293cc9f7c740
# granted connection mcpc_19ef3c3cc443ea7dea465a68 to agent vm-68648d6a5722293cc9f7c740
```

Buying the memory VM itself is still done in the **dashboard** today; the CLI
covers list / connect / disconnect.

---

### C. From MCP (your coding agent)

Mount the CLI once so your agent inherits your login — see [MCP](/docs/mcp):

```bash
claude mcp add jurniti -- jurniti mcp
# or: codex mcp add jurniti -- jurniti mcp
```

Then use these tools (same outcomes as the CLI / UI):

| Goal | MCP tool | Required args |
| --- | --- | --- |
| List memories / connections | `mcp_connections_list` | — |
| **Connect** memory → agent | `mcp_connection_grant` | `connection_id`, `vm_id` |
| **Disconnect** | `mcp_connection_revoke` | `connection_id`, `vm_id` |

Example tool call to connect:

```json
{
  "connection_id": "mcpc_19ef3c3cc443ea7dea465a68",
  "vm_id": "vm-68648d6a5722293cc9f7c740"
}
```

- Discover `connection_id` with `mcp_connections_list` (or `jurniti memory ls`).
- Discover `vm_id` with `vms_list` (or `jurniti vms ls`).
- Use a **read-write** key for grant/revoke; list works with read-only.

Your agent operates as **you** (tenant-scoped). Wrong-role targets fail with
the same `invalid_agent` error as the dashboard.

---

## How to connect observability

Same pattern as memory: buy sidecar → grant to agent.

### Browser

1. Open **[Observability](https://app.jurniti.com/dashboard/observability)**  
   (`/dashboard/observability`).
2. Buy **Latitude** or **Langfuse** (checkout → sidecar microVM).
3. On the sidecar card, connect agents with the grant controls (same idea as
   Memories’ **Connect** / **Disconnect**).
4. v1 keeps **one active observability grant per agent**.

### CLI

```bash
jurniti observability ls

# --sidecar = observability VM id; --vm = agent VM id
jurniti observability grant --sidecar vm-SIDE --vm vm-AGENT
jurniti observability revoke --sidecar vm-SIDE --vm vm-AGENT
```

### MCP

| Goal | Tool | Args |
| --- | --- | --- |
| List grants | `observability_grants_list` | — |
| Connect | `observability_grant` | `sidecar_vm_id`, `agent_vm_id` |
| Disconnect | `observability_revoke` | `sidecar_vm_id`, `agent_vm_id` |

```json
{
  "sidecar_vm_id": "vm-…",
  "agent_vm_id": "vm-…"
}
```

---

## Quick comparison

| Step | Browser | CLI | MCP |
| --- | --- | --- | --- |
| Buy memory | Memories page → pick provider → checkout | — (use UI) | — |
| Buy observability | Observability page → checkout | — (use UI) | — |
| **Connect memory to agent** | Memory card → **Connected agents** → **Connect** | `jurniti memory grant --connection … --vm …` | `mcp_connection_grant` |
| Disconnect memory | Same row → **Disconnect** | `jurniti memory revoke …` | `mcp_connection_revoke` |
| **Connect observability** | Observability card → grant to agent | `jurniti observability grant --sidecar … --vm …` | `observability_grant` |
| List what is connected | Same pages | `jurniti memory ls` / `observability ls` | `*_list` tools |

---

## After you connect

1. Control plane stores the grant (tenant-scoped).
2. Platform **injects** config into the agent guest (memory: MCP connections
   file; observability: observability / OTEL file).
3. The harness applies its native config when it supports auto-wire (Hermes,
   Claude Code, Codex, OpenClaw, OpenCode, OpenHands, Goose, DeepAgents,
   Gemini CLI, …).

You do **not** SSH in to paste tokens for the platform-managed path.

### Which agents auto-wire memory MCP?

**Buy** is dashboard-only for memory and observability SKUs. **Connect** works
from the dashboard, `jurniti memory` / `jurniti observability`, and customer
MCP tools — same grants.

Auto-wire (guest config written from the inject file) requires a real
`MCPClientConfigurer` (or telemetry configurer for observability). Agents that
have **no file-based remote MCP config** today are listed with reasons in the
test inventory `unsupportedMCPClients` in
`internal/harness/mcp_client_configurer_test.go` (examples: pi, grok,
paperclip, aider, and similar). That list is the single source of truth — we
do **not** stub empty configurers to green a matrix cell. Closing a gap means
implementing a real merge script and removing the harness from that map.

Telemetry (observability) is separate: agent harnesses implement
`TelemetryConfigurer` (or use the default apply script); sidecar engines never
consume grants as agents.

---

## CLI demo

Live attach recording (list → grant → list + MCP help):

- GIF: [`jurniti-memory-attach-demo.gif`](https://github.com/zlapp/hermes-managed/blob/main/docs/assets/demos/jurniti-memory-attach-demo.gif)
- MP4: [`jurniti-memory-attach-demo.mp4`](https://github.com/zlapp/hermes-managed/blob/main/docs/assets/demos/jurniti-memory-attach-demo.mp4)

## Related

  - [Dashboard](/docs/dashboard): Browser path for agents and billing.
  - [CLI reference](/docs/cli-reference): All verbs, including memory and observability.
  - [MCP](/docs/mcp): Mount jurniti so your agent can grant connects.
  - [Quickstart](/docs/quickstart): Create an agent before you connect a sidecar.
