Supermemory Documentation Audit
One-line state: feature-rich docs for a serious memory platform, undermined by self-contradiction — the SDK method names, the container-tag rules, the install command, and the self-host story each say something different depending on which page you land on, and an AI agent stitching these pages together will generate code that 403s or throws.
1. The containerTag character rules contradict each other across four pages — and the docs teach a tag format the ingest endpoint rejects (critical)
Location: /docs/concepts/container-tags.md, /docs/authentication.md, /docs/api-reference/ingest/add-document.md, /docs/api-reference/recall-search/search-memory-entries.md
Problem: Four pages define four different allowed-character sets for the same field:
- container-tags concept page:
^[a-zA-Z0-9_:-]+$— colons allowed, dots not. - authentication page: "Alphanumeric, hyphens, underscores, colons, dots" — colons and dots.
- ingest OpenAPI (
POST /v3/documents): "alphanumeric with hyphens, underscores, and dots only" — dots, no colons. - v4 search OpenAPI (
POST /v4/search):pattern: ^[a-zA-Z0-9_:-]+$— colons, no dots.
The concept page explicitly promotes hierarchical colon tags ("The colon is intentionally allowed so you can build hierarchical tags ... org:acme:user:john"), but the ingest endpoint's own regex allows dots only and would reject that exact tag.
Consequence: A developer who builds org:acme:user:john (as the concept page instructs) can search it via /v4/search but gets a validation error when adding documents via /v3/documents. The data written under one tag scheme becomes unreachable under another. Agents parsing the OpenAPI spec will generate tags that fail at the opposite endpoint, silently splitting a user's memory across incompatible keys.
The fix: Pick one canonical character set, enforce it identically on every endpoint, and update all four pages plus both OpenAPI specs to quote the same regex. If colons are truly supported for hierarchy, fix the ingest endpoint's containerTag description and validation to allow them.
2. The container-tags page deprecates containerTags, then uses it in its own example (critical)
Location: /docs/concepts/container-tags.md, /docs/integrations/supermemory-sdk, /docs/concepts/memory-vs-rag.md
Problem: The concept page states plainly: "The plural containerTags array field is deprecated ... The /v4 API only accepts containerTag," with a table marking containerTags ⚠️ Deprecated. Then, lower on the same page, the "list everything" example uses the deprecated form: await client.documents.list({ containerTags: ["project_q1"] }). The SDK integration page uses the deprecated plural in every example (add, search.documents, documents.list), and memory-vs-rag.md uses container_tags=["user_123"] throughout. The ingest OpenAPI additionally marks containerTags deprecated: true, hidden: true.
Consequence: Developers can't tell whether the plural array is dead or load-bearing. They copy deprecated patterns from the integration page (the most likely starting point), build on a field the platform says it's removing, and face a future break with no migration note. Agents have no way to resolve which form is current.
The fix: Replace every containerTags: [...] / container_tags=[...] usage in the SDK integration, memory-vs-rag, and the concept page's own documents.list example with the singular containerTag. If documents.list genuinely still requires an array, document that exception explicitly instead of contradicting the deprecation banner.
3. Four different SDK method names for "search" (and three for "add") across the docs (critical)
Location: /docs/quickstart.md, /docs/search.md, /docs/integrations/supermemory-sdk, /docs/concepts/memory-vs-rag.md, /docs/memory-api/sdks/python, /docs/self-hosting/quickstart.md, GitHub README
Problem: The same SDK is called differently on nearly every page:
- Search:
client.search.memories({...})(search.md, README),client.search.documents({...})(SDK integration),client.documents.search(query="...")(memory-vs-rag — notequery=, notq=),client.search.execute(q=...)(Python SDK page). - Add:
client.add(...)(quickstart, README),client.documents.add(...)(Python SDK retries example),client.memories.add(...)(self-hosting quickstart).
The search parameter name also flips: every page uses q= except memory-vs-rag.md, which uses query=.
Consequence: Only one of these can be the real method on the published SDK. A developer (or an AI agent) who copies client.search.execute(...) or client.memories.add(...) or client.documents.search(query=...) from the page they happened to read will hit AttributeError/TypeError at runtime. This is the single highest-friction issue in the docs because it makes copy-paste — the primary way people use SDK docs — a coin flip.
The fix: Establish one canonical method surface (e.g. client.add, client.search.memories, client.profile) and rewrite every page and the self-hosting quickstart to use it verbatim. Run the snippets in CI against the published package so drift is caught.
4. Self-hosting says "No Docker"; the changelog says "with Docker" (significant)
Location: /docs/self-hosting/overview.md, /docs/changelog/overview.md
Problem: The self-hosting overview leads with "One binary, zero config" and states flatly "No Docker. No database to provision. No config files." The changelog entry "Self-Hostable Supermemory" says the opposite: "Run the full Supermemory stack on your own infrastructure with Docker."
Consequence: A developer evaluating deployment can't tell whether Supermemory ships as a single static binary or a Docker stack — a decision that affects their whole infra plan. The two descriptions imply materially different operational footprints.
The fix: Reconcile the two. If the binary is the current path and Docker was an earlier/alternate option, update or remove the changelog entry; if both exist, document them as two supported install methods on the self-hosting overview rather than denying Docker outright.
5. "Zero config, fully offline" contradicts the first-boot LLM-key requirement (significant)
Location: /docs/self-hosting/overview.md, /docs/self-hosting/quickstart.md
Problem: The overview is titled "One binary, zero config" and claims it "Runs fully offline," yet the same page admits "The only thing you bring is a model" (an external provider key), and the quickstart confirms first boot "prompts you for an LLM API key" and "launches an interactive setup wizard — pick a provider ... paste your key." Pasting an API key into a setup wizard is configuration, and using OpenAI/Anthropic/Gemini/Groq is not offline.
Consequence: Readers expecting a true zero-config, air-gapped install (a reasonable read of "fully offline") discover at first boot that they must supply and configure a model provider. Only the Ollama/local-model path is actually offline, and that nuance is buried.
The fix: Reframe as "zero config for the memory engine; bring or configure one model." State up front that fully-offline operation requires a local model (Ollama/LM Studio/vLLM/llama.cpp) and that cloud providers are online by definition.
6. pip install --pre supermemory on one page, plain pip install supermemory everywhere else (significant)
Location: /docs/memory-api/sdks/python (vs /docs/quickstart.md, /docs/integrations/supermemory-sdk, GitHub README)
Problem: The dedicated Python SDK page installs a pre-release: pip install --pre supermemory. Every other surface — quickstart, SDK integration, and the GitHub README — uses plain pip install supermemory.
Consequence: The two commands can resolve to different package versions with different APIs. A developer following the Python SDK page gets pre-release behavior (possibly the only place client.search.execute and the documented error classes exist), while a quickstart reader gets the stable release. This compounds the method-name inconsistency in finding #3 — the snippets may each be "correct" for a different installed version, with no version pinning to tell them apart.
The fix: Standardize on pip install supermemory for general use. If the error-handling/retry/timeout features documented on that page require the pre-release, say so explicitly and state which version stabilizes them.
7. Endpoint-level error documentation is incomplete — 403/404/422/429 appear only in one SDK page (significant)
Location: /docs/api-reference/ingest/add-document.md, /docs/memory-api/sdks/python, /docs/concepts/container-tags.md
Problem: The ingest OpenAPI documents only 200, 401, and 500 responses. But the access-control rules on the container-tags page rely on 403 Forbidden ("Requesting a tag outside the allowed set returns 403"; "A write to a read-only tag returns 403"), and the Python SDK page documents a full table — 400, 401, 403, 404, 422, 429, >=500 plus APIConnectionError — along with retry behavior (auto-retried 2×) and a 1-minute default timeout. None of 400/403/404/422/429, retries, or timeouts appear in the endpoint-level API reference.
Consequence: A developer reading the OpenAPI spec (or an agent generating a client from it) will not handle 403 scoping errors, 422 validation errors, or 429 rate limits, even though the platform clearly returns them. Error handling gets written against an incomplete contract and fails in production.
The fix: Add the full response set (400/403/404/422/429/500) with schemas to each endpoint in the OpenAPI spec, and cross-link the SDK error table, retry policy, and timeout defaults from the API reference rather than isolating them on the Python page.
8. Scoped keys are "restricted to a single containerTag" — but the changelog adds multi-tag scoped keys (significant)
Location: /docs/authentication.md, /docs/changelog/overview.md
Problem: The authentication page states "Scoped keys are restricted to a single containerTag," and its create-key parameter table accepts a single containerTag string. The changelog entry "Multi-containerTag Scoped API Keys" says "Scoped API keys can now be assigned to multiple container tags — one key, multiple spaces."
Consequence: A developer who needs one key across several tenants reads the auth page, concludes it's impossible, and architects around the limitation (issuing many keys) — unaware the feature shipped. The auth page's request/response schema gives them no way to use the multi-tag capability.
The fix: Update the authentication page to document the multi-tag form (parameter shape, request example, response), or if multi-tag was reverted, remove the changelog entry. Either way, the canonical auth reference must reflect current capability.
9. threshold default is 0.5 in the docs and 0.6 in the OpenAPI — and the OpenAPI contradicts itself (significant)
Location: /docs/search.md, /docs/api-reference/recall-search/search-memory-entries.md
Problem: search.md's parameter table lists threshold default 0.5. The /v4/search OpenAPI declares default: 0.6 for the same field — while also carrying example: 0.5 in the same schema block.
Consequence: A developer who omits threshold gets behavior governed by the real default, which they cannot determine from the docs. Since threshold is a similarity cutoff ("higher = fewer, better results"), a 0.5-vs-0.6 mismatch silently changes how many results come back — a difference that's hard to debug precisely because the developer never set the value.
The fix: Confirm the actual server default, set it identically in search.md and the OpenAPI default, and align the OpenAPI example so the spec doesn't contradict itself.
10. The changelog has no dates and no version numbers (significant)
Location: /docs/changelog/overview.md
Problem: Every changelog entry is headline-only — "Instant dreaming," "No More 120 Memory Limit," "API Terminology Update," "Self-Hostable Supermemory," "Deprecate include: chunks in /v4/search" — with no date and no version attached to any of them.
Consequence: With multiple active deprecations (containerTags, include: chunks) and renames (/v3/memories → /v3/documents), developers cannot tell when a change shipped, which SDK version contains it, or how long a deprecated field will keep working. There's no way to correlate a behavior change with an upgrade. This is especially damaging given the install-command and method-name drift in findings #3 and #6.
The fix: Add an ISO date and the SDK/API version to every changelog entry, and note removal timelines for each deprecation.
11. The documents search mode is referenced in the spec but undocumented in the search params (significant)
Location: /docs/search.md, /docs/api-reference/recall-search/search-memory-entries.md
Problem: search.md documents exactly two searchMode values: "hybrid (recommended) or memories." The /v4/search OpenAPI's tag description says recall "supports memories, hybrid, and documents modes." The documents mode is never described in the search docs — no behavior, no when-to-use.
Consequence: A developer who needs document-chunk-only retrieval (the natural complement to "memories only") has no idea the mode exists or what it returns, and the params table actively implies only two valid values. Agents constrained to the documented enum will never emit the documents mode even when it's the right tool.
The fix: Either document the documents searchMode (behavior, response shape, when to prefer it) in search.md and the param table, or remove it from the OpenAPI tag description if it's not a supported public value.
12. Scoped-key allowed-endpoints list mixes v3/v4 and references endpoints documented nowhere (significant)
Location: /docs/authentication.md (vs /docs/search.md, /docs/changelog/overview.md)
Problem: The scoped-key allowed-endpoints list is /v3/documents, /v3/memories, /v4/memories, /v3/search, /v4/search, /v4/profile. But the changelog says /v3/memories/* was renamed to /v3/documents/* (with redirects), search.md tells developers to call /v4/search while the auth page's own example curls /v3/search, and /v4/memories and /v3/search are not documented as endpoints anywhere else in the docs.
Consequence: A developer can't tell which search endpoint is canonical (/v3/search per the auth example vs /v4/search per search.md), and the allowed-endpoints list grants access to routes (/v4/memories, /v3/memories) that have no reference pages. Building against a renamed/undocumented endpoint risks relying on redirect behavior that may be removed.
The fix: Normalize the docs to the current endpoint set, mark redirected/legacy routes as such in the allowed-endpoints list, update the auth page's example to the canonical search endpoint, and add (or remove) /v4/memories and /v3/search so every referenced endpoint has a reference page.
13. Quickstart reads profile.searchResults.results without the optional-chaining guard the schema requires (minor)
Location: /docs/quickstart.md, /docs/user-profiles.md
Problem: The user-profiles page defines searchResults as optional — searchResults?: {...}; // Only if q parameter provided — and its own example guards the access: result.searchResults?.results || []. The quickstart accesses it unconditionally: profile.searchResults.results (TS) / profile.search_results.results (Python). The quickstart happens to always pass q, so it works there, but it teaches the unguarded pattern.
Consequence: A developer who lifts the quickstart's profile-handling code into a path that omits q gets a runtime TypeError/AttributeError on undefined/None, because searchResults won't exist in the response.
The fix: Use the optional-chaining/.get() form in the quickstart too, matching the user-profiles example, and add an inline note that searchResults is present only when q is supplied.
14. OpenAPI info.version is 3.0.0 while the spec serves /v4/* paths (minor)
Location: /docs/api-reference/ingest/add-document.md, /docs/api-reference/recall-search/search-memory-entries.md
Problem: Both embedded OpenAPI specs declare info.version: 3.0.0, yet the recall spec defines /v4/search and the platform documents /v4/profile and /v4/memories. The version field doesn't track the API surface it describes.
Consequence: Tooling and agents that key off info.version for client generation or compatibility checks will mislabel a v4-capable spec as 3.0.0, and developers can't use the version field to reason about which API generation they're targeting.
The fix: Bump info.version to reflect the v4 surface (or adopt a versioning scheme that distinguishes v3 vs v4 paths), and keep it updated as endpoints move generations.
15. Benchmark claims differ between the docs and the README (minor)
Location: /docs/intro, GitHub README
Problem: The docs intro says Supermemory is "state of the art across multiple different benchmarks, like LongMemEval and LoCoMo" — two benchmarks, no figures. The README claims "#1 on LongMemEval, LoCoMo, and ConvoMem — the three major benchmarks," and adds a specific "LongMemEval | 81.6% — #1" number that the docs never state.
Consequence: A developer comparing sources sees a different number of benchmarks and a headline accuracy figure on GitHub that the docs omit, creating doubt about which claim is current. Inconsistent marketing claims undercut the credibility of the benchmark story.
The fix: State the same benchmark set and figures (with links to the published results) in both the docs intro and the README, and update them together.
What they do well
- Real machine-readable specs exist — endpoints expose OpenAPI at
https://api.supermemory.ai/v3/openapi, with nested filter semantics ("up to 5 levels of nesting") and enums documented, giving agents a programmatic starting point. - The Python SDK page is genuinely thorough — a complete error-class table, retry policy, and timeout defaults that most platforms never document at all (the problem is it's isolated, not absent).
- Self-hosting is a first-class, well-narrated path — a single-binary install, an offline local-model option, and an explicit self-hosted-vs-platform capability table are more than most memory platforms offer.
Top 3 recommendations
- Make copy-paste safe. Pick one canonical SDK method surface and one
containerTagcharacter rule, then enforce both in CI against the published package and the live OpenAPI so quickstart, search, integration, memory-vs-rag, self-hosting, and the README can never drift again (findings #1, #2, #3). - Fix the contract at the endpoint level. Document the full error set (400/403/404/422/429/500), reconcile the
thresholddefault (0.5 vs 0.6), expose thedocumentssearch mode, and bumpinfo.versionto match the v4 surface (findings #7, #9, #11, #14). - Tell a single deployment and history story. Resolve "No Docker" vs "with Docker," reframe "zero config / fully offline" around the required model key, standardize the install command, and add dates + versions to every changelog entry so deprecations and renames are traceable (findings #4, #5, #6, #10).