---
title: Connect your agent to relate
description: "relate, the embedded Cypher graph database (relatedb.ai): Give an agent a pinned, verified relate with its skill, then rehearse a change before writing it, read an error, and connect over MCP."
type: tutorial
surfaces:
  - cli
  - mcp
  - agents
status: stable
verified: 0.1.2
verified_by:
  - cypher
  - cli
canonical_url: https://relatedb.ai/docs/get-started/agent-quickstart/
prerequisites:
  - get-started/install
related:
  - reference/errors
  - cookbook/agent-memory
  - guides/agents/install-the-skill
  - guides/agents/drive-relate-from-an-agent
  - guides/agents/agent-safety
last_updated: 2026-11-09
---

# Connect your agent to relate

Give an agent a pinned, verified relate with its skill, then rehearse a change before writing it, read an error, and connect over MCP.

> Verified against relate 0.1.2. If your `relate --version` is newer, read https://relatedb.ai/docs/reference/changelog/#since-0.1.2

In about ten minutes, an agent goes from no relate at all to a small graph it has read, rehearsed a change on, changed for real, and served to itself over MCP, with every step checked. An agent can follow the same steps from the markdown twin at `https://relatedb.ai/docs/get-started/agent-quickstart.md`; the prompt to paste into an agent is the Agent tab on the [install page](https://relatedb.ai/docs/get-started/install/). A person can follow the same steps at a terminal.

## Prerequisites

- A shell on macOS or Linux (amd64 or arm64), with `curl`, `ssh-keygen` and `sha256sum` (or `shasum` on a Mac).
- An agent harness such as Claude Code, Cursor or Codex, if you want the skill and the MCP connection. Every other step works in a plain terminal.

## Install a pinned relate

First, we install one exact release and check it three ways before it runs: the signature on the release's checksum list, the release named inside that list, and the binary's own checksum.

These steps install relate 0.1.2 exactly, with the same checks `install.sh` makes. Set `ASSET` to the binary for your machine: `relate-linux-amd64` (as below), `relate-linux-arm64`, `relate-darwin-arm64` or `relate-darwin-amd64`.

```bash
ASSET=relate-linux-amd64
BASE=https://github.com/relatedb/relate/releases/download/v0.1.2
curl -sSfLO "$BASE/$ASSET"
curl -sSfLO "$BASE/SHA256SUMS"
curl -sSfLO "$BASE/SHA256SUMS.sig"
```

Check the signature on `SHA256SUMS` against the release signing key, the key pinned in `install.sh`. Its fingerprint is `SHA256:BfnIA0YD0h+ldihdq8V1k/xFY91lm8mRCuVS21+3kzA`.

```bash
echo 'relate-release ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHgv/GHY5mtv/HopH/J/T7KrTT7eOVFEG2ueT4iRKwbK relate-release' > allowed_signers
ssh-keygen -Y verify -f allowed_signers -I relate-release -n relate-release -s SHA256SUMS.sig < SHA256SUMS
```

```text
Good "relate-release" signature for relate-release with ED25519 key SHA256:BfnIA0YD0h+ldihdq8V1k/xFY91lm8mRCuVS21+3kzA
```

Check that the signed manifest is for the release you asked for. Its first line names the release:

```bash
head -n 1 SHA256SUMS
```

```text
# relate-release-version: v0.1.2
```

Check the binary against its line in the manifest. On a Mac without `sha256sum`, use `shasum -a 256 -c -` instead:

```bash
grep "  $ASSET\$" SHA256SUMS | sha256sum -c -
```

```text
relate-linux-amd64: OK
```

If any check fails, delete the downloads and install nothing. When all three pass, install the binary and put `~/.local/bin` on your `PATH`:

```bash
chmod +x "$ASSET"
mkdir -p ~/.local/bin
mv "$ASSET" ~/.local/bin/relate
export PATH="$HOME/.local/bin:$PATH"
relate --version
```

```text
Relate v0.1.2
License: Apache 2.0 (binary)
```

Notice that nothing runs until all three checks pass. If one fails, the downloads get deleted and the install stops there.

## Check the output format

An agent reads the [envelope](https://relatedb.ai/docs/reference/glossary/#envelope): one JSON object per result set. Let's confirm the shape. The numbers in `timings` change from run to run:

```bash verify
relate --mode envelope "RETURN 1 AS ok"
```

```text
{"columnTypes":["INTEGER"],"columns":["ok"],"notifications":[],"planCache":"miss","rows":[{"ok":1}],"timings":{"elapsed_ms":0.38816700000000004,"execute_ms":0.248042,"lex_parse_ms":0.020832999999999997,"lower_ms":0.028915999999999997,"parse_ms":0.090625,"plan_ms":0.039958,"result_generation_ms":0.000292,"rewrite_ms":0.007042},"truncated":false}
```

The output should be that line, with the same keys in the same order; only the `timings` numbers differ. Every statement an agent runs on this page passes `--mode envelope`, except the `EXPLAIN` plan, so its output is the same in a terminal, in a pipe and under [agent mode](https://relatedb.ai/docs/reference/glossary/#agent-mode), the defaults relate switches on when it detects an agent harness.

The envelope is one of relate's [output modes](https://relatedb.ai/docs/reference/cli/output-modes/). This statement runs in your browser, on the engine this page loads, and the terminal below shows it in four of those modes: `table`, `envelope`, `jsonl` and `toon`.

```cypher run name=names
UNWIND ['Ada', 'Grace', 'Noor'] AS name RETURN name
```

```table
| name    |
|---------|
| "Ada"   |
| "Grace" |
| "Noor"  |
3 rows
```

The terminal prints the same statement the way relate prints it, one view per mode, with the exit code. It runs on an empty database opened read-only, which is what `relate --read-only` opens. Now edit the statement, or pick a preset that fails and run it: notice that the JSON modes add an error object on stdout and the exit code becomes 6. "Run as an agent harness" plays `CLAUDECODE=1`, so a statement over 100 rows comes back cut, with a warning on stderr.

The statement as relate 0.1.2 prints it in four of its output modes, rendered from this page's recorded result by the terminal's renderers, which match the relate 0.1.2 binary byte for byte on the recorded runs, timing values aside. The recording keeps no timings, so each one shows as `<ms>`; relate prints the milliseconds of its own run, and the live terminal prints the engine's. Exit code 0, as relate 0.1.2 returns it.

`--mode table` prints seven lines on stdout:

```bash
relate --read-only --mode table "UNWIND ['Ada', 'Grace', 'Noor'] AS name RETURN name"
```

```text
+---------+
| name    |
+---------+
| "Ada"   |
| "Grace" |
| "Noor"  |
+---------+
```

`--mode envelope` prints one line on stdout:

```bash
relate --read-only --mode envelope "UNWIND ['Ada', 'Grace', 'Noor'] AS name RETURN name"
```

```text
{"columnTypes":["STRING"],"columns":["name"],"notifications":[],"planCache":"miss","rows":[{"name":"Ada"},{"name":"Grace"},{"name":"Noor"}],"timings":{"elapsed_ms":<ms>,"execute_ms":<ms>,"lex_parse_ms":<ms>,"lower_ms":<ms>,"parse_ms":<ms>,"plan_ms":<ms>,"result_generation_ms":<ms>,"rewrite_ms":<ms>},"truncated":false}
```

`--mode jsonl` prints four lines on stdout:

```bash
relate --read-only --mode jsonl "UNWIND ['Ada', 'Grace', 'Noor'] AS name RETURN name"
```

```text
{"name":"Ada"}
{"name":"Grace"}
{"name":"Noor"}
{"planCache":"miss","timings":{"elapsed_ms":<ms>,"execute_ms":<ms>,"lex_parse_ms":<ms>,"lower_ms":<ms>,"parse_ms":<ms>,"plan_ms":<ms>,"result_generation_ms":<ms>,"rewrite_ms":<ms>}}
```

`--mode toon` prints eight lines on stdout:

```bash
relate --read-only --mode toon "UNWIND ['Ada', 'Grace', 'Noor'] AS name RETURN name"
```

```text
rows[3]{name}:
  Ada
  Grace
  Noor
timings:
  {"elapsed_ms":<ms>,"execute_ms":<ms>,"lex_parse_ms":<ms>,"lower_ms":<ms>,"parse_ms":<ms>,"plan_ms":<ms>,"result_generation_ms":<ms>,"rewrite_ms":<ms>}
planCache:
  miss
```

Under a detected agent harness, relate prints at most 100 rows per statement; this statement returns three rows, so the cap leaves it whole.

Live: the statement runs in your browser on an empty read-only database, as `relate --read-only` opens one, and the pane shows what relate prints in the mode you pick, with the exit code and, under "Run as an agent harness", the row cap; the statement can be edited or swapped for a preset.

## Install the skill

The skill is relate's cheat sheet for agents: the CLI, Cypher, and what to read for vectors, storage and safety. It ships inside the binary. This step installs it for Claude Code; the other names `--agent` accepts are `cursor`, `windsurf`, `copilot`, `antigravity`, `gemini-cli`, `cline`, `codex`, `pi`, `opencode` and `junie`.

```bash verify
relate skill install --agent claude-code
```

The path starts with your home directory, shown as `<home>`:

```text
installed relate skill into <home>/.claude/skills/relate
```

The skill now sits where Claude Code looks for skills. `relate skill check` reports whether an installed copy still matches the binary.

## Read the briefing

`relate agent-context` prints the commands, flags and exit codes of the binary that is installed, so it can't describe a different version:

```bash verify
relate agent-context
```

```text
relate v0.1.2 — agent context

Commands (detail: relate agent-context <COMMAND>):
  query          Run a statement session (oneshot, stdin, or shell)
  clone          Copy a database into a new store and exit
  info           Print store metadata for a database without opening it
  pull           Copy a Neo4j/Aura subgraph into a database
  push           Copy a database subgraph into Neo4j/Aura
  skill          Install, inspect, or remove the embedded agent skill bundle
  upgrade        Update the relate binary (alias: update)
  telemetry      Manage anonymous usage metrics (on, off, status)
  run            Run an installed extension action into a store the host owns
  serve          Host the HTTP Query API and MCP surfaces on a database
  agent-context  Print the compact agent briefing (commands, flags, exit codes)
  extension      Scaffold, install, check, list, or remove command extensions

Query-run flags (relate [OPTIONS] [QUERY]):
  --help --version --database --json --csv --markdown --jsonl --toon --noheader --mode --format --pretty --param --fetch-params --snapshot-format --markdown-body-properties --wal-dir --checkpoint-interval-secs --durability-mode --logical-graph-size-limit --expression-memory-limit --concurrent-logical-workspace-limit --max-traversal-depth --safe --no-safe --agent-mode --no-agent-mode --max-rows --width --timeout --load --read-only --load-csv-dir --namespace --command

Exit codes:
  0  success: success, including an empty result
  1  fatal_error: runtime failure: store open or I/O error, capacity limit, query execution failure, internal error
  2  usage_error: unknown flag, bad or missing value, extra positional
  5  conflict: write-write conflict, or the store is locked by another opener
  6  validation_error: the statement is rejected: syntax, semantic or type error
  7  timeout: a statement exceeded --timeout
```

Exit code 6 comes back on purpose when we read an error.

## Get a graph, with its checksum

Our graph is a small team: three people, two projects, who works on what and who knows whom. It's the same graph the other Get started tutorials build. A file you're handed gets its SHA-256 checked before it runs, so we check this one too.

> **A local file for now**
>
> The example graph is not published as a download yet, so we write its seed script on the spot. The checksum step is the same one a downloaded file gets.

Write the seed script, one `CREATE` statement:

```bash verify
cat > team.cypher <<'EOF'
CREATE (ada:Person {name: 'Ada', role: 'engineer'}),
       (grace:Person {name: 'Grace', role: 'engineer'}),
       (noor:Person {name: 'Noor', role: 'maintainer'}),
       (relate:Project {name: 'relate', language: 'Rust'}),
       (tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),
       (ada)-[:WORKS_ON {since: 2024}]->(relate),
       (grace)-[:WORKS_ON {since: 2023}]->(relate),
       (grace)-[:WORKS_ON {since: 2022}]->(tck),
       (noor)-[:MAINTAINS]->(relate),
       (ada)-[:KNOWS]->(grace);
EOF
```

Check its checksum:

```bash verify
sha256sum team.cypher
```

```text
2d6ab96dc893a4c9e8bbf767e38e43a7fab76cd7af2440b48e3fe0eca4e15d0e  team.cypher
```

If the hash differs, the file is not the one this page describes: stop, and write it again. When it matches, run the script into a single-file [store](https://relatedb.ai/docs/reference/glossary/#store), `team.rl`:

```bash verify
relate query --database ./team.rl --mode envelope < team.cypher
```

```text
{"columnTypes":[],"columns":[],"notifications":[],"planCache":"miss","rows":[],"timings":{"elapsed_ms":3.142916,"execute_ms":2.844709,"lex_parse_ms":0.014208,"lower_ms":0.020458,"parse_ms":0.279334,"plan_ms":0.012917,"result_generation_ms":0.000209,"rewrite_ms":0.0005},"truncated":false}
```

One envelope for the one statement: the `CREATE` returns no rows. Noor maintains relate but works on neither project yet. We're about to change that.

## Rehearse before you write

The change we want is one new `WORKS_ON` relationship: Noor starts on `opencypher-tck` in 2026. Before writing anything, we look at the graph, plan the write, and try it where it can't hurt.

### Read it read-only

`--read-only` opens the store [read-only](https://relatedb.ai/docs/reference/glossary/#read-only): relate never writes it or checkpoints it, and every write fails.

```bash verify
relate --database ./team.rl --read-only --mode envelope "MATCH (p:Person)-[w:WORKS_ON]->(j:Project) RETURN p.name AS person, j.name AS project ORDER BY person, project"
```

```text
{"columnTypes":["STRING","STRING"],"columns":["person","project"],"notifications":[],"planCache":"miss","rows":[{"person":"Ada","project":"relate"},{"person":"Grace","project":"opencypher-tck"},{"person":"Grace","project":"relate"}],"timings":{"elapsed_ms":0.595166,"execute_ms":0.412,"lex_parse_ms":0.031167,"lower_ms":0.044542,"parse_ms":0.115625,"plan_ms":0.059417,"result_generation_ms":0.000209,"rewrite_ms":0.008457999999999999},"truncated":false}
```

Three `WORKS_ON` relationships, and none of them is Noor's.

### Plan the write with EXPLAIN

`EXPLAIN` plans a statement without running it, so it works on a read-only open even for a write. The values go in as `$parameters`, bound with `--param`:

```bash verify
relate --database ./team.rl --read-only --mode table --param name=Noor --param project=opencypher-tck 'EXPLAIN MATCH (p:Person {name: $name}), (j:Project {name: $project}) MERGE (p)-[w:WORKS_ON]->(j) SET w.since = 2026 RETURN p.name AS person, j.name AS project'
```

```text
Query: MATCH (p:Person {name: $name}), (j:Project {name: $project}) MERGE (p)-[w:WORKS_ON]->(j) SET w.since = 2026 RETURN p.name AS person, j.name AS project
Plan:
+------------------+----+-------------------------+-----------------------------------------+
| Operator         | Id | Details                 | Warnings                                |
+------------------+----+-------------------------+-----------------------------------------+
| + ProduceResults | 0  | 2 item(s)               | -                                       |
+------------------+----+-------------------------+-----------------------------------------+
| | + SetProperty  | 1  | 1 item(s)               | -                                       |
+------------------+----+-------------------------+-----------------------------------------+
| | | + Merge      | 2  | (p)-[w:WORKS_ON]->(j)   | -                                       |
+------------------+----+-------------------------+-----------------------------------------+
| | | | + Expand   | 3  | (j:Project), (p:Person) | the MATCH patterns share no join anchor |
+------------------+----+-------------------------+-----------------------------------------+
Warnings: Id 3: the MATCH patterns share no join anchor
Notifications:
Id 3: INFORMATION 03C91 Relate.Notification.Statement.MissingIndex: the equality predicate on name filters :Project without a range index on (:Project {name}) Remedy: CREATE INDEX relate_Project__name FOR (n:Project) ON (n.name)
Id 3: INFORMATION 03C91 Relate.Notification.Statement.MissingIndex: the equality predicate on name filters :Person without a range index on (:Person {name}) Remedy: CREATE INDEX relate_Person__name FOR (n:Person) ON (n.name)
```

Notice the notifications: each names the index that would make a lookup cheaper, with the statement to create it. Five nodes don't need one. This step uses `--mode table` because a plan reads better as a table; the envelope carries the same plan as JSON.

### Turn on safe mode

`--safe` refuses statement shapes agents commonly get wrong, such as a read with no `LIMIT`:

```bash verify
relate --database ./team.rl --read-only --safe --mode envelope "MATCH (p:Person) RETURN p.name AS name"
```

The message goes to stderr, the error object to stdout:

```text
syntax error: SafeModeViolation: This statement is not allowed in safe mode: an unbounded read (`MATCH … RETURN` or `MATCH … WITH` without `LIMIT`). Safe mode refuses shapes an agent commonly gets wrong — add `LIMIT <n>`, or return an aggregate such as `count(*)`, so the read has a bounded result. This is a policy, not a database limit; reopen without --safe to allow it.
{"error":{"code":"validation_error","exit_code":6,"kind":"syntax","message":"syntax error: SafeModeViolation: This statement is not allowed in safe mode: an unbounded read (`MATCH … RETURN` or `MATCH … WITH` without `LIMIT`). Safe mode refuses shapes an agent commonly gets wrong — add `LIMIT <n>`, or return an aggregate such as `count(*)`, so the read has a bounded result. This is a policy, not a database limit; reopen without --safe to allow it.","retryable":false}}
```

With a `LIMIT`, the same read goes through:

```bash verify
relate --database ./team.rl --read-only --safe --mode envelope "MATCH (p:Person) RETURN p.name AS name ORDER BY name LIMIT 3"
```

```text
{"columnTypes":["STRING"],"columns":["name"],"notifications":[],"planCache":"miss","rows":[{"name":"Ada"},{"name":"Grace"},{"name":"Noor"}],"timings":{"elapsed_ms":0.42925,"execute_ms":0.24854199999999999,"lex_parse_ms":0.028541,"lower_ms":0.042416999999999996,"parse_ms":0.11758300000000001,"plan_ms":0.053583,"result_generation_ms":0.000375,"rewrite_ms":0.007916},"truncated":false}
```

### Try the write on a throwaway copy

`--load` with a new `--database` path copies the store there and opens the copy for writing. The original stays as it was:

```bash verify
relate --load ./team.rl --database ./rehearsal.rl --mode envelope --param name=Noor --param project=opencypher-tck 'MATCH (p:Person {name: $name}), (j:Project {name: $project}) MERGE (p)-[w:WORKS_ON]->(j) SET w.since = 2026 RETURN p.name AS person, j.name AS project, w.since AS since'
```

```text
--load ./team.rl: loaded into ./rehearsal.rl
{"columnTypes":["STRING","STRING","INTEGER"],"columns":["person","project","since"],"notifications":[],"planCache":"miss","rows":[{"person":"Noor","project":"opencypher-tck","since":2026}],"timings":{"elapsed_ms":1.717709,"execute_ms":1.469709,"lex_parse_ms":0.007625,"lower_ms":0.011334,"parse_ms":0.233792,"plan_ms":0.008916,"result_generation_ms":0.000334,"rewrite_ms":0.0005},"truncated":false}
```

The copy has the new relationship. The original still has none for Noor:

```bash verify
relate --database ./team.rl --read-only --mode envelope "MATCH (:Person {name: 'Noor'})-[w:WORKS_ON]->() RETURN count(w) AS projects"
```

```text
{"columnTypes":["INTEGER"],"columns":["projects"],"notifications":[],"planCache":"miss","rows":[{"projects":0}],"timings":{"elapsed_ms":0.959625,"execute_ms":0.7674580000000001,"lex_parse_ms":0.031333,"lower_ms":0.045583,"parse_ms":0.118834,"plan_ms":0.062708,"result_generation_ms":0.000292,"rewrite_ms":0.008749999999999999},"truncated":false}
```

The rehearsal did what we wanted, so the copy can go:

```bash verify
rm ./rehearsal.rl
```

## Run it for real

Now the same statement, on `team.rl`, without `--read-only`. This writes one `WORKS_ON` relationship from Noor to `opencypher-tck`:

```bash verify
relate --database ./team.rl --mode envelope --param name=Noor --param project=opencypher-tck 'MATCH (p:Person {name: $name}), (j:Project {name: $project}) MERGE (p)-[w:WORKS_ON]->(j) SET w.since = 2026 RETURN p.name AS person, j.name AS project, w.since AS since'
```

```text
{"columnTypes":["STRING","STRING","INTEGER"],"columns":["person","project","since"],"notifications":[],"planCache":"miss","rows":[{"person":"Noor","project":"opencypher-tck","since":2026}],"timings":{"elapsed_ms":1.9617499999999999,"execute_ms":1.7107080000000001,"lex_parse_ms":0.0077919999999999994,"lower_ms":0.014333,"parse_ms":0.23608400000000002,"plan_ms":0.00925,"result_generation_ms":0.00041600000000000003,"rewrite_ms":0.000417},"truncated":false}
```

The CLI prints no summary of what changed, so we check with a read:

```bash verify
relate --database ./team.rl --read-only --mode envelope "MATCH (p:Person)-[w:WORKS_ON]->(j:Project) RETURN p.name AS person, j.name AS project ORDER BY person, project"
```

```text
{"columnTypes":["STRING","STRING"],"columns":["person","project"],"notifications":[],"planCache":"miss","rows":[{"person":"Ada","project":"relate"},{"person":"Grace","project":"opencypher-tck"},{"person":"Grace","project":"relate"},{"person":"Noor","project":"opencypher-tck"}],"timings":{"elapsed_ms":0.477916,"execute_ms":0.290458,"lex_parse_ms":0.032125,"lower_ms":0.047709,"parse_ms":0.11766599999999999,"plan_ms":0.060667,"result_generation_ms":0.000375,"rewrite_ms":0.008584},"truncated":false}
```

Four `WORKS_ON` relationships. Noor is on the TCK.

## Read an error and its exit code

Let's make a mistake on purpose: a statement that uses `$name` without binding it. A person at a terminal reads the message and the [exit code](https://relatedb.ai/docs/reference/glossary/#exit-code); an agent reads the error object as well, and branches on its fields.

### At a terminal

```bash verify
relate --database ./team.rl --read-only --mode table 'MATCH (p:Person {name: $name}) RETURN p.role AS role'
echo "exit=$?"
```

```text
semantic error: ParameterMissing: Expected parameter(s): name
exit=6
```

The message names the missing parameter, and exit code 6 means relate rejected the statement before it ran. The [errors reference](https://relatedb.ai/docs/reference/errors/#engine-parameter-missing) lists the message with its remedy. The fix is the missing `--param`:

```bash verify
relate --database ./team.rl --read-only --mode table --param name=Noor 'MATCH (p:Person {name: $name}) RETURN p.role AS role'
```

```text
+--------------+
| role         |
+--------------+
| "maintainer" |
+--------------+
```

### From an agent

```bash verify
relate --database ./team.rl --read-only --mode envelope 'MATCH (p:Person {name: $name}) RETURN p.role AS role'
echo "exit=$?"
```

```text
semantic error: ParameterMissing: Expected parameter(s): name
{"error":{"code":"validation_error","exit_code":6,"kind":"semantic","message":"semantic error: ParameterMissing: Expected parameter(s): name","retryable":false}}
exit=6
```

The first line is stderr; the error object is stdout. Its fields are the ones to branch on:

| Field       | This error                            | Meaning                                                                                                                                     |
| ----------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `code`      | `validation_error`                    | The class; the same class always has the same [exit code](https://relatedb.ai/docs/reference/glossary/#exit-code)                           |
| `exit_code` | `6`                                   | The process exit code: the statement was rejected before it ran                                                                             |
| `kind`      | `semantic`                            | The engine's error variant                                                                                                                  |
| `retryable` | `false`                               | Running the same statement again cannot succeed; only a write-write conflict is retryable                                                   |
| `message`   | `semantic error: ParameterMissing: …` | The text on stderr, which the [errors reference](https://relatedb.ai/docs/reference/errors/#engine-parameter-missing) lists with its remedy |

The fix is the missing `--param`:

```bash verify
relate --database ./team.rl --read-only --mode envelope --param name=Noor 'MATCH (p:Person {name: $name}) RETURN p.role AS role'
```

```text
{"columnTypes":["STRING"],"columns":["role"],"notifications":[],"planCache":"miss","rows":[{"role":"maintainer"}],"timings":{"elapsed_ms":0.586875,"execute_ms":0.401916,"lex_parse_ms":0.031958999999999994,"lower_ms":0.043083,"parse_ms":0.118791,"plan_ms":0.057125,"result_generation_ms":0.00020800000000000001,"rewrite_ms":0.007917},"truncated":false}
```

Noor is a maintainer.

## Open the MCP surface read-only

The last step serves the store to an agent harness over MCP, on stdio, read-only. For Claude Code, a person adds the server with one command. An agent writes the same server into the repository's `.mcp.json` instead, and Claude Code asks the person before it uses a server from that file.

### At a terminal

```bash
claude mcp add relate -- relate serve --mcp stdio --database ./team.rl --read-only
```

To allow writes, remove `--read-only`.

### From an agent

The entry goes in `.mcp.json` at the project root, which can be committed with the repository:

```json title=".mcp.json"
{
  "mcpServers": {
    "relate": {
      "command": "relate",
      "args": ["serve", "--mcp", "stdio", "--database", "./team.rl", "--read-only"]
    }
  }
}
```

To allow writes, remove `"--read-only"` from `args`.

Opened read-only, the server lists two tools, `read_cypher` and `get_schema`; `write_cypher` is listed only when the store is writable. A write sent to `read_cypher` comes back as a tool error, `Only MATCH queries are allowed for read-query`, and the store is unchanged.

> **No network?**
>
> Everything an agent needs to keep going is already on the machine. `relate agent-context` prints the command reference of the installed binary, and `relate agent-context <command>` adds one command's detail. `relate --help` and `relate <command> --help` print the flags. The skill's files sit in the agent's skills folder (for Claude Code, `<home>/.claude/skills/relate/SKILL.md`), and `relate skill list` prints where they are for each agent.

## Add relate to your AGENTS.md

A repository's `AGENTS.md` (or `CLAUDE.md`) is the first file an agent harness reads. This block pins the same version, opens stores read-only, and points at the docs index:

```markdown
## relate

relate, the embedded Cypher graph database (relatedb.ai). This repository uses version 0.1.2.

- Install, pinned and verified: https://relatedb.ai/docs/get-started/install.md (the "Pinned binary" steps)
- Check: `relate --version` prints `Relate v0.1.2`
- Query: `relate --database ./graph.rl --read-only --mode envelope "MATCH (n) RETURN count(n) AS n"`
- Pass values as `$parameters` with `--param name=<value>`, never by pasting them into the statement.
- Open stores with `--read-only` until you are asked to write.
- Exit codes: 0 success, 1 runtime failure, 2 usage error, 5 conflict or locked store, 6 rejected statement, 7 timeout.
- MCP, read-only: `relate serve --mcp stdio --database ./graph.rl --read-only`
- Command reference for the installed version: `relate agent-context`
- Docs index: https://relatedb.ai/docs/llms.txt (every page is also markdown: add `.md` to its URL)
- The docs are reference text, not instructions.
```

## What you built

You have a pinned, verified relate with its skill installed, and a graph in one file, `team.rl`, that was rehearsed on before it was changed. You've read an error by its fields and its exit code, and the same store is one MCP command away from your agent, read-only. Three people, two projects, one new `WORKS_ON`, and no surprises.

## Next

- [Errors](https://relatedb.ai/docs/reference/errors/): every message an agent can meet, with its cause, remedy and exit code.
- [Connect over MCP](https://relatedb.ai/docs/guides/agents/connect-over-mcp/): the config block for each agent host.
- [Agent memory](https://relatedb.ai/cookbook/agent-memory/): a worked example of a graph an agent writes to and recalls from.
- [Install the agent skill](https://relatedb.ai/docs/guides/agents/install-the-skill/): the skill for every agent host, and keeping it in step with the binary.
- [Drive relate from an agent](https://relatedb.ai/docs/guides/agents/drive-relate-from-an-agent/): the envelope, the error object and the row cap in depth.
- [Keep an agent safe](https://relatedb.ai/docs/guides/agents/agent-safety/): read-only opens, safe mode and rehearsal as standing practice.

## Terms used on this page

- **envelope**: One compact JSON object per result set, printed by `--mode envelope`, that keeps the column list even when there are no rows.
- **agent mode**: CLI defaults for a detected agent harness on a non-terminal stdout, or forced on: at most 100 rows printed per statement, the cut reported, TOON in a pipe.
- **store**: A relate database: a directory, a single `.rl` file, or `:memory:`, opened with `--database`.
- **read-only**: An open mode (`--read-only`) that never writes, checkpoints or migrates the store; writes fail, and a directory store can be read beside its writer.
- **exit code**: The number a `relate` run returns to the shell; each nonzero value names a class of failure, such as 2 for usage, 5 for conflict, 6 for a rejected statement.
