For the complete documentation index, see llms.txt. This page is also available as Markdown.

agentmemory backend

Optional `Memory` trait backend that delegates to a locally-running agentmemory REST server, for users who self-host agentmemory across Claude Code, Cursor, Codex, OpenCode, and OpenHuman.

OpenHuman's default Memory trait backend is sqlite β€” the unified store documented in Memory Trees. For users who already self-host agentmemory β€” typically because they want a single durable memory shared across Claude Code, Cursor, Codex, OpenCode, and OpenHuman β€” OpenHuman exposes an opt-in backend that proxies every trait call through agentmemory's REST surface.

Selecting backend = "agentmemory" skips OpenHuman's SQLite + embedder path entirely. agentmemory owns the storage, embedding, and retrieval layers. OpenHuman becomes a thin REST client.

When to use this

Use the agentmemory backend if:

  • You already run npx -y @agentmemory/agentmemory for one or more coding agents and want OpenHuman to share the same durable store.

  • You want hybrid BM25 + vector + graph retrieval without provisioning a separate embedder on the OpenHuman side.

  • You prefer agentmemory's lifecycle (consolidation, retention scoring, auto-forget, graph extraction) over OpenHuman's unified store.

Keep the default sqlite backend if:

  • You want self-contained, single-process operation with no external daemon dependency.

  • You rely on OpenHuman-specific Memory Tree features (chunking, sealing, summary trees) that operate on top of the SQLite store. The Memory Tree pipeline is unaffected by the trait backend β€” it operates on the host's document store, orthogonally β€” but the agentmemory backend is most valuable when you've already standardised on agentmemory across other agents.

Quick start

  1. Install + start agentmemory (one terminal):

    npx -y @agentmemory/agentmemory

    Defaults to http://localhost:3111 (REST) + ws://localhost:49134 (engine). First boot generates an HMAC secret at ~/.agentmemory/.hmac and prints it once.

  2. Point OpenHuman at it in your config.toml:

    [memory]
    backend = "agentmemory"
    # Defaults below β€” set only when overriding.
    # agentmemory_url        = "http://localhost:3111"
    # agentmemory_secret     = ""           # HMAC bearer token, optional
    # agentmemory_timeout_ms = 5000
  3. Restart OpenHuman. The factory short-circuits the SQLite path and logs [memory::factory] using agentmemory backend at <url>.

That's it. Existing OpenHuman call sites (store, recall, get, list, forget, namespace_summaries, count, health_check) work unchanged.

Config keys

Field
Default
Purpose

agentmemory_url

http://localhost:3111

Base URL for the agentmemory REST server

agentmemory_secret

none

Optional HMAC bearer token. Sent as Authorization: Bearer <secret>

agentmemory_timeout_ms

5000

Per-request reqwest timeout

When backend == "agentmemory", the following existing MemoryConfig fields are ignored β€” agentmemory owns its own embedding stack via ~/.agentmemory/.env:

  • embedding_provider

  • embedding_model

  • embedding_dimensions

  • sqlite_open_timeout_secs

Setting them on this path is a no-op. The local-AI Ollama health-gate also doesn't run on this path β€” agentmemory's daemon manages its own embedder lifecycle.

Field mapping

OpenHuman's MemoryEntry ↔ agentmemory wire row:

OpenHuman field
agentmemory field
Notes

namespace

project

Defaults to "default" when empty

key

title

content

content

id

id

agentmemory-generated (mem_<rand>)

category: Core

type: "fact"

category: Daily

type: "conversation"

category: Conversation

type: "conversation"

category: Custom(s)

type: "fact" + concepts: [s]

Custom tag rolled into the concepts array so it remains queryable

session_id

sessionIds: [...]

OpenHuman exposes a single id; agentmemory persists an array

timestamp

updatedAt (RFC3339)

Falls back to createdAt if updatedAt is absent

score (recall hits only)

smart-search score

Populated on recall responses, None on get / list

agentmemory carries additional fields β€” concepts (auto-extracted), files (path tags), strength (retention score), version, supersedes (the lifecycle chain) β€” that this backend leaves at defaults. They're internal to agentmemory's lifecycle layer and don't need to round-trip through OpenHuman's trait.

Trait method β†’ endpoint

Memory method

agentmemory REST

Notes

store

POST /agentmemory/remember

{project, title, content, type, concepts, sessionIds}

recall

POST /agentmemory/smart-search

Hybrid BM25 + vector + graph

get

POST /agentmemory/smart-search

+ client-side exact-title filter

list

GET /agentmemory/memories?latest=true&project=<ns>

forget

get(ns, key) β†’ POST /agentmemory/forget

Two-step: resolve id then forget

namespace_summaries

GET /agentmemory/projects

Returns [{name, count, lastUpdated}]

count

GET /agentmemory/health

Reads memories field

health_check

GET /agentmemory/livez

RecallOpts.category, RecallOpts.session_id, and RecallOpts.min_score are applied as client-side filters on the smart-search response. agentmemory's REST surface doesn't expose them as server-side filters today. For very large recall windows (limit > 100) prefer issuing a tighter query string to reduce server-side work over relying on client-side post-filtering.

Security

When agentmemory_secret is set, the client honours agentmemory's v0.9.12 plaintext-bearer guard contract:

  • Loopback hosts (localhost, 127.0.0.1, ::1) over http:// β€” allowed. Local dev path.

  • https:// to any host β€” allowed.

  • Plaintext HTTP to a non-loopback host β€” emits a one-time stderr warning at construction time. The bearer is observable on the wire.

  • AGENTMEMORY_REQUIRE_HTTPS=1 (process env, ASCII-case-insensitive matches 1 or true) β€” escalates the warning into a hard refusal at client construction. The backend fails to start rather than leak the bearer once.

Production deploys should set AGENTMEMORY_REQUIRE_HTTPS=1 so a misconfigured TLS terminator fails loud rather than silently leaking.

The plaintext-bearer guard mirrors the integration plugin guards in agentmemory's PR #315 so an operator who's seen the warning on Hermes / OpenClaw / pi will recognise the same message on OpenHuman.

Failure modes

Failure
Backend behaviour

Daemon unreachable at startup

from_config succeeds (URL parses), but health_check() returns false on first call. Trait methods bubble up reqwest transport errors

Network timeout

anyhow::Error per trait contract; surfaces to caller

4xx / 5xx response

anyhow::Error with status + body snippet

Bearer over plaintext non-loopback (no env)

One-time stderr warning, request proceeds

Bearer over plaintext non-loopback + AGENTMEMORY_REQUIRE_HTTPS=1

Hard refusal at construction time

Empty agentmemory_url

Hard refusal at construction time with hint to leave it unset for the default

Invalid URL syntax

Hard refusal at construction time with the parser error

No automatic fallback to SQLite. If the daemon is down at boot, the backend surfaces the transport error loudly. Operators flip back to backend = "sqlite" in config.toml to recover. Rationale: a silent SQLite fallback would hide a misconfigured daemon β€” "private, simple, predictable" wins over "magically tolerant".

Performance notes

The backend is a thin REST proxy β€” it adds one HTTP round-trip per trait call. Practical implications:

  • store and forget are single-RTT.

  • recall, get, list are single-RTT.

  • forget against an unknown key is two-RTT (the implicit get lookup

    • a no-op confirmation). Caller can short-circuit this by checking the return value of a prior list.

  • agentmemory's REST is 127.0.0.1 by default β€” same-host latency is sub-millisecond. Over a managed deploy with HTTPS termination, expect ~10–30ms per RTT.

  • The default per-request timeout is 5 seconds. Bump agentmemory_timeout_ms if you're seeing intermittent timeouts on cold-start of the iii engine; agentmemory's first-request latency after a long idle can stretch toward 3–5s depending on persistence state.

Migration: from SQLite to agentmemory

There's no in-place migration today. The recommended path:

  1. Export your existing memories from the SQLite store via OpenHuman's existing export RPC (or by direct SQL).

  2. Walk the export and POST each row to /agentmemory/remember with the same project + title + content. agentmemory will assign new ids; the OpenHuman side picks them up on first list.

  3. Set backend = "agentmemory" and restart.

A dedicated bulk import path is filed as a follow-up.

Implementation reference

In-tree files:

Related upstream:

  • agentmemory REST contract β€” ~/.agentmemory/.env keys + endpoint list in the agentmemory README

  • v0.9.12 plaintext-bearer guard β€” agentmemory PR #315

Last updated