> ## Documentation Index
> Fetch the complete documentation index at: https://www.plungeai.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat, memory & skills

> Three tools keep something for you across calls: a conversation, a memory, a skill. The examples use https://mcp.plungeai.com/v1. https://api.plungeai.com/v1/mcp is the same server.


Source: `orchestration/mcp-gateway/tools.ts` (`ChatSchema`, `plungeaiChat`, `MemorySchema`, `plungeaiMemory`, `LearnSchema`, `plungeaiLearn`), `orchestration/mcp-gateway/chat.ts`, `orchestration/mcp-gateway/tools-bots.ts` (the bot actions of 10.4), `orchestration/mcp-gateway/extras.ts` (`registrySigned`), `orchestration/mcp-gateway/index.ts` (argument pre-screen), `orchestration/mcp-gateway/server.ts` (`TOOL_DEFS`), `core/core-memory/core-memory.ts` and `core/core-memory/CLAUDE.md`, `agents/agents/harness-agent/runtime.ts` (run journal write).

Three tools keep something for you across calls: a conversation, a memory, a skill. The examples use `https://mcp.plungeai.com/v1`. `https://api.plungeai.com/v1/mcp` is the same server.

| Tool | Keeps | Also seen in | Read-only |
|---|---|---|---|
| `plungeai_chat` | conversations with the PlungeAI assistant | Studio's Think tab, `ocean-cli chat sessions` | no |
| `plungeai_memory` | your long-term memory (notes and a user profile); also reads the run journal | every mission recalls it at start; Studio's harness uses the same store | no (`remember` writes) |
| `plungeai_learn` | your private skill library | registry skill cards only you can see | no (`learn` and `forget` change state) |

Full parameter tables are in the [Tool reference](/mcp/tool-reference).

## 10.1 Chat: plungeai_chat

A persistent conversation with the platform assistant. One tool, four actions:

| `action` | Needs | Does | Answer |
|---|---|---|---|
| `send` | `message`; optional `conversation_id` | sends one turn and waits for the whole reply | the reply, then ``_(conversation: `<id>`)_`` |
| `new` | optional `message` | creates an empty conversation; `message` only sets its title | ``Created conversation `<id>`. Send messages with action "send" and this conversation_id.`` |
| `list_sessions` | nothing | your 20 most recently updated conversations | `# Your conversations (N)` and a table: Title, ID, Messages. Or `No conversations yet.` |
| `history` | `conversation_id` | the whole conversation | `# <title>` and every turn as `**User:**` / `**Assistant:**` |

**The assistant** is `harness-agent` on Anthropic `claude-sonnet-4-5`, with up to 15 turns and 8,192 output tokens per reply. Its tools are `web_search`, `registry_search`, `registry_lookup` and `task_complete`. It is told to verify current facts with web search, cite source URLs, and use the registry to find platform agents when relevant. It cannot run workflows or save anything: it has no execute or save tool. When a design is settled, ask your client to build it, and it calls `plungeai_build_workflow` ([Workflows](/mcp/workflows)).

**One account, three surfaces.** A conversation is stored the way Studio stores its plan conversations. The same conversation shows up in Studio's Think tab and in the CLI's `ocean-cli chat sessions`, and a thread started there can be continued here by its id.

**Titles.** `send` without a `conversation_id` starts a new conversation titled with the first 50 characters of your message. `new` titles it with the first 50 characters of `message`, or `New conversation` when there is none. That title stays: a later first `send` does not rename it.

**Live status.** A `send` reports `Thinking…`, then `Streaming… <n> chars` as the reply arrives ([Protocol & transport](/mcp/protocol)).

**Errors** (all `isError: true`):

| Answer | Cause |
|---|---|
| `message is required for send.` | `send` without `message` |
| `conversation_id is required for history.` | `history` without an id |
| `Conversation not found.` | `history` for an unknown id, or one that is not yours |
| `Chat error: Conversation not found or not yours` | `send` to an unknown or foreign `conversation_id` |
| `Chat error: Harness agent error (HTTP <n>): …` | the assistant could not be reached |

**One writer per conversation.** Two `send` calls on the same conversation at the same time can lose a turn: the conversation store has no compare-and-swap. Send turns one after another.

**Chat or something else?**

| You want | Use |
|---|---|
| an open-ended thread with the platform assistant | `plungeai_chat` |
| a conversation with one specific agent | `plungeai_execute_agent` with `session_id` ([Agents & missions](/mcp/agents-missions)) |
| more on one finished run, with its context | `plungeai_followup` ([Runs, results & follow-ups](/mcp/runs-results)) |

Try asking: *"Let's design a due-diligence workflow together."* The thread persists, so you can come back to it from Studio or the CLI. When you are happy with the design, say *"build it"*.

Send a turn. This runs a model and costs credits (not verified here):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_chat","arguments":{"user_request":"let us design a due-diligence workflow together","action":"send","message":"Let us design a due-diligence workflow together. What steps would you include?"}}}'
```

List your conversations:

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_chat","arguments":{"user_request":"show my conversations","action":"list_sessions"}}}'
```

Read one back (replace `<conversation_id>`):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_chat","arguments":{"user_request":"show me that conversation","action":"history","conversation_id":"<conversation_id>"}}}'
```

## 10.2 Memory: plungeai_memory

Long-term memory is scoped to you. It has two curated stores:

| `target` | Holds | Default size budget |
|---|---|---|
| `memory` (the default) | notes: facts, preferences and decisions worth keeping | 2,200 characters |
| `user` | a profile of you | 1,375 characters |

The budgets are per-user settings; the numbers above are the defaults.

**Who reads it.** Every mission (`plungeai_run_mission`, [Agents & missions](/mcp/agents-missions)) recalls both stores at the start of its run and can write to them. This is the same mechanism Studio's harness uses, so a note saved here is known to every later run. The recall is a snapshot taken once per run: a write during a run is saved, but it does not change that run's prompt.

**What it is not.** Memory is not your run history. There are three separate things:

| Store | What is in it | Read with |
|---|---|---|
| memory | the curated notes and profile above | `recall`, `remember` with `operation: "read"` |
| run journal | the goal and full result of each run the harness agent finished | `search_runs`, `get_run` |
| execution history | every execution on your account | `plungeai_executions` ([9.4](/mcp/runs-results#94-run-history-plungeai_executions)) |

`recall` deliberately leaves the run journal out.

**Actions.**

| `action` | Needs | Does | Answer |
|---|---|---|---|
| `recall` | nothing | returns both stores, memory first, then the user profile | the entries, or `No memory recorded yet.` |
| `remember` | depends on `operation` (below) | writes the store that `recall` reads | ``Saved to memory (<usage>). recall will see it immediately.`` or `Saved to your user profile (<usage>)…` |
| `search_runs` | `query`; optional `limit` (default 10) | keyword search over the run journal | `# Matching runs` and one line per run: `` `<run id>` — <goal> `` |
| `get_run` | `run_id` | one journal entry in full | the stored goal and result, or `Run not found.` |
| `forget` | exactly one of `entry_id` or `content` | `entry_id` (`mem_…`, the id `GET /v1/memory` lists) removes that one entry from its store; `content` removes every entry containing it from both stores. The same body as One API `POST /v1/memory/forget` | ``Forgot <n> memory entries.`` (`entry` for one). An id your stores do not hold is `Memory entry not found.`; both or neither is `forget takes exactly one of entry_id or content.` (both `isError: true`) |

`recall` has no query: it returns all of both stores and your client picks what is relevant.

**`remember` operations** (`operation` defaults to `add`, `target` to `memory`):

| `operation` | Needs | Effect |
|---|---|---|
| `add` | `content` | appends an entry. An identical entry is not added twice |
| `replace` | `old_text` and `content` | replaces the one entry that contains `old_text` |
| `remove` | `old_text` | removes the one entry that contains `old_text` |
| `read` | nothing | lists the entries as `# Memory (<target>)` with the store's usage |

**When a write is refused** (all `isError: true`):

| Answer | Cause | What to do |
|---|---|---|
| `content is required for remember (what to store; old_text identifies the entry for replace/remove).` | a write with neither `content` nor `old_text` | pass them |
| `replace requires old_text and content` / `remove requires old_text` | a half-specified change | pass both |
| `no entry matched '<text>'` | `old_text` is in no entry | read the store first |
| `'<text>' matches N entries — use a more specific substring. …` | `old_text` is in several entries | use a longer substring |
| `Memory at <n>/<limit> chars. … Consolidate now: …` followed by **Current entries** | the write would exceed the budget | `replace` overlapping entries with shorter ones or `remove` stale ones, then retry |
| `blocked: content matched threat pattern '<name>'` | the content looks like an instruction-injection attempt | rephrase it as a plain fact |
| `<target> store failed the round-trip integrity check (externally modified or oversized entry). Current bytes backed up to <path>. …` (or `entry-size`) | the stored file was changed outside the memory tool; its bytes were backed up | repair the file with the raw memory editor, then retry |

**`search_runs`** matches the words of your query that are longer than two characters against the goals in the journal, and ranks runs by how many words match. If no word matches, it returns your most recent runs instead of nothing. `No matching runs.` means the journal is empty. `query is required for search_runs.` and `run_id is required for get_run.` are `isError: true`.

Try asking:

- *"What do you remember about Circle's acquisitions?"* → `recall`
- *"Remember that our fiscal year ends in June."* → `remember`
- *"Find my past runs about Tesla."* → `search_runs`, then *"Show me that run."* → `get_run`
- *"Forget my old office address."* → `forget` with `content`

Recall (read-only):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_memory","arguments":{"user_request":"what do you remember about Circle acquisitions?","action":"recall"}}}'
```

Read the raw memory store (read-only):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_memory","arguments":{"user_request":"show my memory entries","action":"remember","operation":"read","target":"memory"}}}'
```

Save a note. This writes to your memory (not verified here):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_memory","arguments":{"user_request":"remember that our fiscal year ends in June","action":"remember","content":"Our fiscal year ends in June."}}}'
```

Change it later with `"operation":"replace","old_text":"fiscal year","content":"Our fiscal year ends in July."`.

Search the run journal (read-only):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_memory","arguments":{"user_request":"find my past runs about Tesla","action":"search_runs","query":"Tesla","limit":5}}}'
```

## 10.3 Skills: plungeai_learn

`plungeai_learn` manages your private skill library. A skill is a reusable piece of know-how, distilled from a source, that you inject into later missions.

| `action` | Needs | Does | Answer |
|---|---|---|---|
| `learn` (the default) | `source`; optional `name`, `mode` | distills the source into a skill with the `learn` pre-built agent | async (the default): `ok` with ``Started distilling `<id>` (async). Poll plungeai_get_workflow_status with this id, then fetch output with plungeai_get_result once completed.`` and the execution footer. Sync: the run's result |
| `list` | nothing | your learned skills, up to 50 | `ok`: `N learned skill(s).` and one line per skill: `` `<id>` — <description> ``. Or `No learned skills yet.` |
| `forget` | `name` | deletes one of your skills | `ok`: ``Forgot skill `<name>`.`` |

**`source`** is a URL, text or Markdown to distill (up to 65,536 characters), or a description of what you just did, such as a workflow you ran. **`name`** is the skill id in kebab-case: picked for you on `learn` when you leave it out, required on `forget` (take it from `list`).

**How `learn` runs.** It starts a one-task harness workflow named `learn` whose task points at the `learn` pre-built agent card. The card is resolved live when the run starts, so an edit to the card changes every later call without a redeploy. The run is a full agent loop (fetch, summarize, save), so it defaults to `mode:"async"`: poll `plungeai_get_workflow_status` with the execution id, then read the result with `plungeai_get_result` ([Runs, results & follow-ups](/mcp/runs-results)). It creates an execution in your history and runs a model.

**Where skills go.** A learned skill is a registry skill card tagged with your user id as its owner. Only you can list it or delete it.

**Using a skill.** Pass its id in `skills` on `plungeai_run_mission` to inject it into the mission ([Agents & missions](/mcp/agents-missions)).

**Answers.** Every answer is the structured outcome envelope ([Tools](/mcp/tools)), because the tool declares an `outputSchema`:

| `status` | Summary | Cause |
|---|---|---|
| `needs_input` | `` `plungeai_learn` was not called — its arguments do not match the tool's schema. `source`: `source` is required to learn a skill. `` | `learn` without `source`; the gateway checks this before the tool runs |
| `needs_input` | `` `forget` needs `name` (the skill id from `action: list`). `` | `forget` without `name` |
| `error` | ``No skill named `<name>`. Use `action: list` to see yours.`` | no such skill |
| `unavailable` | ``Not yours to delete: `<name>`.`` | the skill belongs to someone else |
| `error` | `Registry refused the delete (<status>).` | the registry failed the delete |

Try asking:

- *"Learn a skill from https://developers.cloudflare.com/durable-objects/."*
- *"Turn what we just did into a skill called weekly-brief."*
- *"What skills have I learned?"*
- *"Forget the weekly-brief skill."*

List your skills (read-only):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_learn","arguments":{"user_request":"what skills have I learned?","action":"list"}}}'
```

Learn one. This starts an agent run and costs credits (not verified here):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_learn","arguments":{"user_request":"learn a skill from the Durable Objects docs","action":"learn","source":"https://developers.cloudflare.com/durable-objects/","name":"durable-objects-basics"}}}'
```

## 10.4 Bot chats: bindings, inbox and groups

A saved bot is talked to outside these tools too. Three kinds of conversation around a bot are read and managed with `plungeai_workflow` (the full action table is [8.6](/mcp/workflows#86-manage-saved-workflows--plungeai_workflow)):

| Conversation | `action` | What it is |
|---|---|---|
| Paired chats | `bindings`, `bind`, `unbind` | the Telegram, WhatsApp, Discord or Teams chats bound to the bot, so that chat talks to it. Pair the chat first; `bindings` answers a plain "not enabled yet" until the message gateway supports it |
| Bot-to-bot messages | `inbox` | what other bots queued for this bot's next run |
| A bot group | `groups`, `group_set`, `group_delete`, `group_thread` | a named set of 2 to 6 of your bots and the thread they share |

Try asking:

- *"Which chats are bound to my Outreach bot?"* The client runs `bindings`.
- *"Show me what the Sales group has been saying."* The client runs `group_thread` with `group: "Sales"`.

Reading a group's shared thread is read-only (not run by the docs verifier; it needs a group you made):

```bash
curl -s https://mcp.plungeai.com/v1 \
  -H "Authorization: Bearer $PLUNGE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_workflow","arguments":{"user_request":"show me what the Sales group has been saying","action":"group_thread","group":"Sales"}}}'
```
