---
name: agent-memory
title: give an agent a memory
kind: skill
version: 1.0.0
description: >
  wire a long-term memory into an ai agent someone is building (a support bot, an
  assistant, a slack or discord bot, a research script) with two web requests: one
  before it answers, to remember what matters, and one after, to keep what was said.
  no sdk to install, any language, ten minutes.
when_to_load: >
  when someone pastes this link with an agent key and asks you to add memory to their
  agent, bot or assistant, or asks how their agent can remember people and
  conversations between runs.
authored_by: innernet
author_url: https://innernet.live
license: CC BY 4.0
updated: 2026-10-19
tags: [agents, memory, setup, api]
category: workflow
---

# give an agent a memory

you are helping someone give the agent they are building a memory that lasts between conversations. it takes two requests to one endpoint. read this whole page, then do it for them in their code, then show them it works.

## what they gave you

- **an agent key**, starting `innernet_`. it is a server secret: it reaches this one agent's memory and nothing else of theirs.
  - put it in an environment variable named `INNERNET_AGENT_KEY` (their `.env`, their host's secrets, wherever the project keeps secrets). add `.env` to `.gitignore` if it is not there.
  - never write the key into source code, never send it to a browser or a mobile app, never print it in logs. if they pasted it in the chat, tell them where you put it.
  - no key yet? ask them to make one: on innernet.live, connections → the agents you keep → make an agent of your own. the key is shown once, when it is made.

the base url is `https://innernet.live/api/v1/agents/me` (`me` is whichever agent the key belongs to). every request is a POST with `Authorization: Bearer <key>` and a JSON body.

## first, find the turn

look through their code for the place where one turn happens: a message comes in, the model is called, a reply goes out. that is where both requests go. if there are several (a chat route, a webhook handler, a cli loop), use the one they actually run, and ask if it is unclear.

then ask yourself one question: **does this agent talk to many different people** (customers, users, members of a server)? if it does, every request carries a `user_id`: a stable id for the person it is talking to (their account id, a slack user id, an email): 1 to 128 characters of letters, numbers and `_ . : @ -`. memories are kept per person, and one person's memories never reach another's answer. if it is a personal agent that only ever talks to its owner, leave `user_id` out.

## before it answers: what it remembers

```
POST https://innernet.live/api/v1/agents/me/context
{ "query": "<the incoming message>", "user_id": "<the person, if any>" }
```

the answer has `text`: one block, ready to drop into the system prompt, holding what the agent knows and what it knows about this person. add it under a short heading such as `what you remember`. when `text` is empty there is nothing yet, which is normal on day one. if the request fails or takes longer than about two seconds, answer without it: memory must never stop the agent from replying.

## after it answers: what to keep

```
POST https://innernet.live/api/v1/agents/me/memories
{ "messages": [ { "role": "user", "content": "<their message>" }, { "role": "assistant", "content": "<the reply>" } ],
  "user_id": "<the person, if any>" }
```

innernet reads the exchange, keeps only what is worth keeping (a preference, a fact, a decision, how a task is done), sorts each piece by what kind of thing it is, and hides email addresses, phone numbers, keys and card numbers before anything is stored. send it after the reply has gone out, without waiting on it: keeping should never slow the answer down. the answer lists what was kept.

## a helper to start from

adapt it to their stack and their style; keep both calls this small.

typescript (any runtime with `fetch`):

```ts
const MEMORY = "https://innernet.live/api/v1/agents/me";
const headers = { Authorization: `Bearer ${process.env.INNERNET_AGENT_KEY}`, "Content-Type": "application/json" };

export async function remembered(query: string, userId?: string): Promise<string> {
  try {
    const res = await fetch(`${MEMORY}/context`, { method: "POST", headers, body: JSON.stringify({ query, user_id: userId }), signal: AbortSignal.timeout(2000) });
    return res.ok ? ((await res.json()).text ?? "") : "";
  } catch {
    return ""; // answer without memory rather than not at all
  }
}

export function keep(userMessage: string, reply: string, userId?: string): void {
  void fetch(`${MEMORY}/memories`, {
    method: "POST",
    headers,
    body: JSON.stringify({ messages: [{ role: "user", content: userMessage }, { role: "assistant", content: reply }], user_id: userId }),
  }).catch(() => {});
}
```

python (`requests`):

```python
import os, threading, requests

MEMORY = "https://innernet.live/api/v1/agents/me"
HEADERS = {"Authorization": f"Bearer {os.environ['INNERNET_AGENT_KEY']}"}

def remembered(query, user_id=None):
    try:
        body = {"query": query, **({"user_id": user_id} if user_id else {})}
        r = requests.post(f"{MEMORY}/context", headers=HEADERS, json=body, timeout=2)
        return r.json().get("text", "") if r.ok else ""
    except requests.RequestException:
        return ""  # answer without memory rather than not at all

def keep(user_message, reply, user_id=None):
    body = {"messages": [{"role": "user", "content": user_message}, {"role": "assistant", "content": reply}], **({"user_id": user_id} if user_id else {})}
    threading.Thread(target=lambda: requests.post(f"{MEMORY}/memories", headers=HEADERS, json=body, timeout=10), daemon=True).start()
```

leave `user_id` out of the body entirely when there is no person (as both helpers do): a `null` is not the same as no field.

## show them it works

1. run one turn of their agent with a message that says something worth keeping, such as "i prefer short answers, and i'm in lisbon".
2. run a second turn that needs it, such as "what time is it where i am?". the reply should use what was kept.
3. tell them to open innernet.live → connections → the agents you keep → their agent: **memory** shows what it kept, sorted by kind, and **activity** shows each call.

if a request answers `401`, the key is wrong or was not loaded into the environment. `404` means the key is not an agent key. `429` means a limit was reached for the minute; it clears on its own.

## what they can change later, without code

on their agent's page in innernet: **access** decides what the agent may read of them and whether what it learns about them reaches their own memory (sealed · asks first · trusted). **settings** decides what it keeps, what it never keeps, when it forgets, and how much it brings back. nothing in their code has to change for any of it.

## going further

- forget everything about one person: `DELETE https://innernet.live/api/v1/agents/me/users/<user_id>`.
- recall a list instead of a block: `POST …/me/recall` with `{ "query": "...", "user_id": "...", "limit": 5 }`.
- the whole api, with every field: https://innernet.live/docs/agents-api
