> ## Documentation Index
> Fetch the complete documentation index at: https://cortex-e852fafe-t3code-rewrite-docs-declutter.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Memories

> How to use Memories to personalize responses with user-specific context.

export const Field = ({name, type, required, recommended}) => {
  const label = required ? 'required' : recommended ? 'recommended' : null;
  const typeLabel = typeof type === 'string' ? type : null;
  const ariaParts = [name, typeLabel && `${typeLabel}`, label].filter(Boolean);
  return <span aria-label={ariaParts.join(', ')} className={label ? 'field-wrap has-field-tip' : 'field-wrap'} style={{
    position: 'relative',
    cursor: label ? 'default' : undefined
  }} tabIndex={label ? 0 : undefined}>
      <span className="field-name-row">
        <code>{name}</code>
        {required && <span className="field-req"> *</span>}
        {recommended && <span className="field-rec"> ●</span>}
      </span>
      {type && <span className="field-type">{type}</span>}
      {label && <span className="field-tip" role="tooltip">
          {label}
        </span>}
    </span>;
};

## Why Memories exist

Most applications start every conversation from scratch. Memories let your agent carry useful user-specific context from one session to the next, so responses become more personal over time.

A memory is information your application saves for later: a preference, a past conversation, a decision, or a fact about a user. For example, saving "this customer already tried restarting" lets a support agent avoid suggesting it again. Your application must send the information to HydraDB; it is not captured automatically.

See [Knowledge vs Memories](/essentials/v2/knowledge#1-what-it-is) for a side-by-side comparison.

***

## The mental model: user context vs. shared context

Choose by the purpose of the content: **reference material** goes in [Knowledge](/essentials/v2/knowledge); **information to remember between conversations** goes in Memories. A private document can still be knowledge.

To keep a user's memories separate, send that user's `collection` on writes, status checks, and queries. Your backend selects it from the authenticated session. Content categories do not grant or enforce user access.

| If the content is… | Store it as… |
| - | - |
| About a specific user or session | Memory |
| Reference material, whether shared or restricted | [Knowledge](/essentials/v2/knowledge) |

Good candidates for [Knowledge ingestion](/essentials/v2/knowledge) include product docs, policy PDFs, internal wikis, Slack exports, and other shared material that should be reusable across users.

***

## What happens when you ingest a memory

When you call [`POST /context/ingest`](/api-reference/v2/endpoint/ingest-context) with `type=memory`, HydraDB turns your input into queryable user context.

The pipeline works like this:

1. **Parse the input**: raw text, markdown, or user-assistant pairs.
2. **Optionally infer meaning**: if `infer: true`, HydraDB extracts the underlying preference, trait, or fact.
3. **Index it**: once indexed, [`POST /query`](/api-reference/v2/endpoint/query) can retrieve it with `type: "memory"` or `type: "all"`.

The most important choice is [`infer`](#choose-whether-hydradb-should-infer-the-memory). It decides whether HydraDB should extract a useful fact from text or dialogue, or store exactly what you send.

Ingestion is asynchronous, so memories are not queryable immediately. Poll [`GET /context/status`](/api-reference/v2/endpoint/source-status) until the memory reaches at least `graph_creation`, or wait for `indexing_status` to become `completed` if you need full indexing. Alternatively, [register a webhook](/essentials/v2/webhooks) to be notified when indexing finishes instead of polling.

***

## Choose the right input shape

Each memory item takes either `text` or `user_assistant_pairs`, **not both** (sending both returns `400`). Choose the shape that matches the content you already have.

### Text

Use `text` for any prose input: plain observations, captured facts, preference statements, meeting notes, memos, or semi-structured records. Set `is_markdown: true` when the content uses markdown syntax (headings, lists, code blocks) and you want HydraDB to preserve that structure during chunking and embedding. Leave `is_markdown` unset (or `false`) for plain prose.

```json theme={"dark"}
{
  "text": "# Meeting Notes\n\n## Key Points\n- Budget approved",
  "is_markdown": true,
  "infer": false
}
```

```json theme={"dark"}
{
  "text": "Prefers detailed technical explanations and works in PST.",
  "infer": true
}
```

### User-assistant pairs

Use `user_assistant_pairs` when the useful signal comes from dialogue, especially when the preference is implied rather than explicitly stated.

```json theme={"dark"}
{
  "user_assistant_pairs": [
    { "user": "Remember I like dark mode", "assistant": "Noted." }
  ],
  "infer": true
}
```

***

## Memory fields

The full schema lives on [`POST /context/ingest`](/api-reference/v2/endpoint/ingest-context). For `type=memory`, send a JSON-stringified `memories` array; each item can use the fields below.

### Request-level fields

| Field | Default | Description |
| - | - | - |
| <Field name="type" type="memory" required /> | None | Selects the Memories store. Use singular `memory`. |
| <Field name="database" type="string" required /> | None | Target database. The `database` field was formerly `tenant_id`. |
| <Field name="collection" type="string" recommended /> | default collection | User, workspace, or session scope for the memory. The `collection` field was formerly `sub_tenant_id`. |
| <Field name="upsert" type="boolean" /> | `true` | Replace existing memories with the same `id`. |
| <Field name="memories" type="string (JSON array)" required /> | None | JSON-stringified array of memory items. |

### `memories` item fields

| Field | Description |
| - | - |
| <Field name="id" type="string" /> | Optional stable ID. Acts as the upsert key. |
| <Field name="title" type="string" /> | Short label for display in `/context/list` and query results. |
| <Field name="text" type="string" recommended /> | Raw text or Markdown content. Required unless `user_assistant_pairs` is provided. |
| <Field name="user_assistant_pairs" type="array" recommended /> | Conversation pairs in the shape `{ "user": "...", "assistant": "..." }`. Required unless `text` is provided. |
| <Field name="is_markdown" type="boolean" /> | Treat `text` as Markdown for chunking and indexing. |
| <Field name="infer" type="boolean" /> | When `true`, HydraDB extracts the underlying preference, trait, or fact. When `false` (the default), it stores the input as written. |
| <Field name="custom_instructions" type="string" /> | Guides extraction when `infer: true`. Ignored when `infer: false`. |
| <Field name="user_name" type="string" /> | User name used during inference. |
| <Field name="metadata" type="object" /> | Database-schema fields for filtering and query. Send this as an object inside each `memories[]` item, for example `"metadata": { "department": "support" }`. Up to 16 KiB as compact JSON. |
| <Field name="additional_metadata" type="object" /> | Canonical free-form per-memory fields for display or bookkeeping. Send this as an object. Up to 1 KiB as compact JSON. |

<Warning>
  **Memory metadata encoding:** `memories` is itself a JSON-stringified multipart field. Within each memory item, `metadata` and `additional_metadata` are plain objects. Do not stringify them again.
</Warning>

```json theme={"dark"}
{
  "id": "pref_dark_mode",
  "text": "User prefers dark mode and concise answers.",
  "infer": true,
  "metadata": { "department": "support", "workspace": "docs" },
  "additional_metadata": { "source": "onboarding" }
}
```

***

## Query memories

Memories live in their own store, separate from [Knowledge](/essentials/v2/knowledge). [`POST /query`](/api-reference/v2/endpoint/query) reaches each store through the `type` parameter:

* `type: "memory"` queries the Memories store (`vectorstore_status.memories`).
* `type: "knowledge"` queries the [Knowledge](/essentials/v2/knowledge) store (`vectorstore_status.knowledge`).
* `type: "all"` runs both in parallel and returns a single merged, re-ranked result set.

<Info>
  **One endpoint, two stores.** Both stores are read from the same collection. If shared documents live in their own collection, list it next to the user's in `collections`. See [Query](/essentials/v2/query).
</Info>

***

## Minimal working example

This example stores a user preference scoped to one user.

<CodeGroup>
  ```python Python SDK theme={"dark"}
  import json
  import os
  from hydra_db import HydraDB

  client = HydraDB(token=os.environ["HYDRA_DB_API_KEY"])

  result = client.context.ingest(
      type="memory",
      database="acme_corp",
      collection="user_john_123",
      upsert=True,
      memories=json.dumps([
          {
              "text": "Prefers short, direct answers with no preamble.",
              "infer": True,
              "user_name": "John",
          }
      ]),
  )
  ```

  ```typescript TypeScript SDK theme={"dark"}
  import { HydraDBClient } from "@hydradb/sdk";

  const client = new HydraDBClient({
    token: process.env.HYDRA_DB_API_KEY,
  });

  const result = await client.context.ingest({
    type: "memory",
    database: "acme_corp",
    collection: "user_john_123",
    upsert: "true",
    memories: JSON.stringify([
      {
        text: "Prefers short, direct answers with no preamble.",
        infer: true,
        user_name: "John",
      },
    ]),
  });
  ```

  ```bash cURL theme={"dark"}
  curl -X POST 'https://api.hydradb.com/context/ingest' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -F "type=memory" \
    -F "database=acme_corp" \
    -F "collection=user_john_123" \
    -F "upsert=true" \
    -F 'memories=[
      {
        "text": "Prefers short, direct answers with no preamble.",
        "infer": true,
        "user_name": "John"
      }
    ]'
  ```
</CodeGroup>

The response returns an `id` for each memory and an initial `status` of `queued`. The payload is wrapped in the standard envelope, so the fields live under `data` (`response.data.results`):

```json theme={"dark"}
{
  "success": true,
  "data": {
    "success": true,
    "message": "Memories queued for ingestion successfully",
    "results": [
      { "id": "mem_abc123", "status": "queued", "infer": true }
    ],
    "success_count": 1,
    "failed_count": 0
  },
  "error": null,
  "meta": {
    "request_id": "9d13aef4-02f4-4e73-8c62-4c2601d04f9d",
    "latency_ms": 12.3
  }
}
```

Poll [`GET /context/status`](/api-reference/v2/endpoint/source-status) with the returned `id`, or register a [webhook](/essentials/v2/webhooks), until the memory is indexed.

***

## Choose whether HydraDB should infer the memory

`infer` controls how much extraction work your application does before sending content to HydraDB.

### Use `infer: true` when the input is raw signal

With `infer: true`, you give HydraDB messy or indirect evidence (dialogue, logs, behavior, feedback, or observations), and HydraDB extracts the useful preference, trait, or fact.

For example, instead of writing your own logic to decide whether a user prefers dark mode, send the raw stream of UI events and let HydraDB infer it. The [example below](#example-infer-a-preference-from-behavior) shows exactly this.

Use `infer: true` for:

* Dialogue where the preference is implicit.
* Behavior logs and event streams.
* Feedback like “the last summary was too long.”
* Any input where the useful memory needs to be derived from raw context.

`custom_instructions` only takes effect when `infer: true`. Use it to guide extraction, for example: `"Focus on UI and notification preferences only"`.

### Use `infer: false` when the input is already the memory

With `infer: false` (the default), HydraDB stores and indexes exactly what you send. There is no extraction step.

Use `infer: false` for:

* Facts you already captured, such as `"User's plan tier is Pro"`.
* Pre-structured notes.
* Content you want to retrieve exactly as written.

**Rule of thumb:** `infer: false` is faster and deterministic. `infer: true` is better when your input is raw, noisy, or indirect.

***

## Example: infer a preference from behavior

Here is a more realistic example. A user has been toggling dark mode in your app. Instead of extracting the preference yourself, send the raw behavior log and let HydraDB infer the useful memory.

<CodeGroup>
  ```python Python SDK theme={"dark"}
  import json

  client.context.ingest(
      type="memory",
      database="acme_corp",
      collection="user_john_123",
      memories=json.dumps([
          {
              "text": (
                  "User opened the app 14 times in the last week. "
                  "Switched to dark mode on first session. "
                  "Toggled back to light once on 2026-04-12 at 3pm, "
                  "then switched back to dark within 4 minutes. "
                  "Has not changed theme since."
              ),
              "infer": True,
              "user_name": "John",
              "custom_instructions": "Focus on display and theme preferences.",
          }
      ]),
  )
  ```

  ```typescript TypeScript SDK theme={"dark"}
  const result = await client.context.ingest({
    type: "memory",
    database: "acme_corp",
    collection: "user_john_123",
    memories: JSON.stringify([
      {
        text:
          "User opened the app 14 times in the last week. " +
          "Switched to dark mode on first session. " +
          "Toggled back to light once on 2026-04-12 at 3pm, " +
          "then switched back to dark within 4 minutes. " +
          "Has not changed theme since.",
        infer: true,
        user_name: "John",
        custom_instructions: "Focus on display and theme preferences.",
      },
    ]),
  });
  ```

  ```bash cURL theme={"dark"}
  curl -X POST 'https://api.hydradb.com/context/ingest' \
    -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
    -H "API-Version: 2" \
    -F "type=memory" \
    -F "database=acme_corp" \
    -F "collection=user_john_123" \
    -F 'memories=[
      {
        "text": "User opened the app 14 times in the last week. Switched to dark mode on first session. Toggled back to light once on 2026-04-12 at 3pm, then switched back to dark within 4 minutes. Has not changed theme since.",
        "infer": true,
        "user_name": "John",
        "custom_instructions": "Focus on display and theme preferences."
      }
    ]'
  ```
</CodeGroup>

Later, when [`POST /query`](/api-reference/v2/endpoint/query) runs with `type: "memory"` and a query like `"what UI settings does the user prefer?"`, HydraDB can return the inferred preference (for example, `"prefers dark mode"`) rather than the raw event log.

If you sent the same input with `infer: false`, HydraDB would index the event log verbatim. That is useful only when you want to retrieve the log itself.

***

## Common mistakes

| Mistake | What goes wrong | Fix |
| - | - | - |
| Sending `"memory": "..."` instead of `"memories": [...]` | Validation fails | Use `"memories": [ { "text": "..." } ]`, always an array of objects |
| Omitting `database` | `400` (`database is required`) | Include `database` on every call |
| Omitting `collection` for per-user data | The memory lands in the default collection and may surface in the wrong scope | Use the user's ID as `collection` for B2C separation |
| Extracting preferences yourself before sending raw logs | You duplicate work HydraDB can do for you | Send the raw signal with `infer: true` |
| Sending pre-extracted facts with `infer: true` | HydraDB may re-derive the memory and change the original phrasing | Use `infer: false` for already-structured facts |
| Treating `user_name` as cosmetic | It can influence inference, so the wrong name can bias extraction | Pass the actual user's name |
| Storing shared docs as memories | They will not surface when querying `type: "knowledge"` | Use [knowledge ingestion](/essentials/v2/knowledge) with `type=knowledge` on [`POST /context/ingest`](/api-reference/v2/endpoint/ingest-context) |

***

## Related

* [Knowledge](/essentials/v2/knowledge): shared, database-wide document context
* [Query](/essentials/v2/query): how memories are retrieved at query time
* [Multi-tenant support](/essentials/v2/multi-tenant): scoping memories per user or workspace
* [Metadata](/essentials/v2/metadata): designing filterable fields


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.