Skip to content

fix(engram): correct the docs against the live API, the server spec, and the SDK - #525

Open
g-despot wants to merge 15 commits into
mainfrom
docs/engram-review-fixes
Open

fix(engram): correct the docs against the live API, the server spec, and the SDK#525
g-despot wants to merge 15 commits into
mainfrom
docs/engram-review-fixes

Conversation

@g-despot

Copy link
Copy Markdown
Contributor

A deep review of the Engram docs — read against the server repo, the Python SDK and the production API — found the published spec stale and a set of claims that don't match what the service does. This fixes them.

The spec. static/specs/engram-openapi.json is replaced wholesale from the server repo; the committed copy was from May and its paths lacked the /v1 prefix, so every URL the Scalar page rendered 404'd. It's now byte-identical to what production serves (sha256 matches both the dev-deploy commit and the v0.0.40 prod tag), and static/specs/README.md documents the refresh, including that info.version is pinned at 1.0.0 and does not track the server release.

Claims corrected against production. fetch is documented as the fourth retrieval type (three pages said three); defaults and limits are stated (hybrid, 10, range 1–100); concepts/scopes.md no longer says scope parameters are optional when searching — a write must satisfy the union of every topic's scope in the group, which is why snippets fail against a project with a scoped bounded topic. Input timestamps steer extraction but are not stored, so the page no longer implies you can order by them. Terminology follows the wire format (pre_extracted, topic_name), and topic names are case-sensitive where user_id is not.

Snippets. Every rendered FilteredTextBlock span now carries its own imports, so blocks are copy-pasteable standalone. pyproject.toml required weaviate-engram>=0.3.0 while the lock pinned 0.6.0 — a version where StringInput has no timestamp fields and none of the four retrieval models exist, so the includes could not run; now >=1.0.1 with the lock refreshed.

Verification. Nine API claims were checked live and two write paths exercised (22 memories created and deleted, none left). The build passes with no new warnings.

Known, not fixed here: the snippet harness cannot pass against a project whose group contains a scoped topic — it needs a project created without the ConversationSummary option. Some claims (403, 429, the list default of 20) remain unverified.

g-despot and others added 15 commits August 20, 2026 20:02
…he copy

Replace static/specs/engram-openapi.json wholesale with weaviate/engram's
openapi.json at 67a0248 (server v0.0.40). The committed copy dated from
2026-05-28 and every path was missing its /v1 prefix, so the Scalar page at
/engram/api/rest -- and its copy-as-curl -- pointed at URLs that 404. The
refresh also adds GET /v1/auth/verify and GET /v1/groups, the Group,
GroupList, Topic and TopicScoping schemas, created_at/updated_at on
StringInput, and the limit bounds on RetrievalConfigDTO and
ListMemoriesRequest.

Give the file a real section in static/specs/README.md: source repo, path and
commit, refresh-by-copy steps, the "every path starts with /v1" check, and the
two known upstream inaccuracies to fix in the server rather than here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
Add an API overview page and wire it into the sidebar, the introduction, the
quickstart and install-integrate. It covers what was previously scattered or
missing: the base URL including the required /v1 prefix and the absence of a
project ID in the path, the bearer header and the five ways to get a 401,
GET /v1/auth/verify, the RFC 9457 problem+json error body with a status-code
table (including the 422 and 429 the spec prose omits), the SDK's exception
types, GET /v1/groups with an example response, the unauthenticated /health
endpoint, and the free plan's 1,000 runs per month and 1 project.

Also: document POST /v1/memories/list as a "List memories" section in the
manage-memories guide, marked REST-only because the Python SDK has no list()
method, and point the multi-tenant RAG tutorial's deletion step at it instead
of leaving search() as an enumeration; state plainly in groups.md and
console.md that projects, groups and topics are console-only with no create
API; source the plan claims in pipelines.md and concepts/index.md against the
pricing page; and note that no official npm package exists.

The new curl snippets live in _includes/api_overview.sh and are registered
with tests/test_engram.py, so the verify, groups, health and missing-prefix
claims are checked live rather than asserted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
…rules

concepts/search.md said Engram has three search strategies while two pages
already used a fourth. Add fetch to the table, explain that it applies scope
and topic filters without ranking (and still requires a non-empty query it
ignores), and state the defaults nothing documented: hybrid with a limit of
10 when retrieval_config is omitted, limit 1-100, no pagination. Mirror the
defaults in the search guide's "Retrieval types" intro and give fetch a
subsection with Python, async and cURL examples.

Also fix a cross-page contradiction in concepts/scopes.md, which told readers
that scope parameters are optional when searching. user_id follows the same
union rule as storing -- required if any targeted topic is user-scoped --
and only properties are optional filters, which is what scopes.md itself
says higher up and what the search guide says.

The new snippets are exercised by the existing harness files, and
search_memories.sh gains a fetch assertion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
FilteredTextBlock renders only the lines between START and END, so an import
above the marker is invisible on the page and the block it belongs to does
not run when a reader copies it. The quickstart's Connect block was the worst
case -- one bare EngramClient(...) call on the site's busiest Engram guide --
and every retrieval class, the pre-extracted input models, and all three
tutorial setup blocks had the same problem.

Each rendered block now imports what it uses, following the pattern
store_memories.py already had. Test-only imports (time, APIError, the uuid
that only feeds test user IDs) stay outside. Duplicate imports across blocks
are intentional: a snippet has to stand on its own. Also add the missing
import to the inline retrieval-tuning block in the context-window tutorial.

All eleven touched files still compile and still run top to bottom.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
The Hermes plugin install was wrong: `pip install hermes-weaviate-engram`
404s, the package is not on PyPI. Install it from the repository instead, and
warn that it requires weaviate-engram>=0.6,<1, so it downgrades an
environment holding the current 1.x SDK.

The Claude Code plugin section named a "Coding Assistant" template that the
plugin's README never mentions, and left out everything the plugin actually
needs. Replace it with what the README and the plugin's scope resolver
document: ENGRAM_USER_ID and its git-email default, the two config files and
what each may contain, how a property value resolves, the search narrowing
keys, and the "Engram · …" in-reply notice. Most importantly, `repo_name` and
`session_id` are the only properties the plugin can resolve on its own, so a
project with a topic scoped by anything else fails to store on every turn
until a .engram.json maps it -- that now has its own admonition with an
example.

Also stop implying the template choice is free: presets beyond the
personalization pipeline start at the Starter plan.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
Match the wire/SDK names: pre_extracted, and topic_name for a topic's
identifier. Document what the SDK actually exposes — user_id is
case-insensitive and auto-created, root is REST-only, runs.get versus
runs.wait (and that wait never returns on in_buffer), the typed
exceptions, and the created_at/updated_at/metadata fields that no page
mentioned. Also correct "content is an array": a bare Python list is
serialized as a conversation, so multiple strings need StringInput.
Standardise on "managed memory service", drop the self-hosted claim, and
name the optional Buffer step on the landing page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
Sentence-case the three tutorial titles and make every index entry and
cross-link use the title verbatim. Point the dual-memory paragraph at
Step 3, where that pattern actually is, and render the token-comparison
snippet that computes the table instead of leaving it orphaned. Give the
RAG tutorial the environment-variable block it was missing, the current
Auth.api_key idiom, and an up-front note that its Weaviate half is
illustrative and untested. Show a plain user_id in the chat app's setup
block rather than a test-generated one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
…rs consistent

Give the Guideflow iframe a title and a numbered text fallback, so the
click path survives a blocked third-party embed or a screen reader, and
drop the three non-standard React props plus the script tag React never
executed. Merge the duplicated "use the Personalization template"
instruction, and remove a stray blank line.

Use the same placeholders everywhere: alice for user_id, and <run-id> /
<memory-id> for path segments, matching the site's convention and the
Python tab. Those strings live inside the DOCSNIPPETS heredoc of each
shell include, which the harness never executes. Show fractional hybrid
scores instead of a flat 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
Order the Concepts sidebar the way the pages introduce each other —
groups before topics — matching the Concepts index. Render the three
snippet blocks that no page pointed at (the quickstart's run check, and
the context-window tutorial's setup and token count) and move the
cleanup helper, which was neither documented nor tested, out of the
docs tree into tests/. Settle on one name, "Engram console", fix the
escaped underscore in one feedback import, and answer the question the
page never did: a scope is a Weaviate tenant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
…eval-type count

The Claude Code plugin does not search broadly by default: cross-topic
properties default to repo_name, so recall is confined to the repository
you are working in until search.properties overrides it or an empty array
clears it. Say so, and note that the default is inert unless the group is
actually scoped by repo_name.

Wave 1 raised three retrieval types to four on the search pages but left
five enumerations behind, so the section contradicted itself; all of them
now name fetch. The quickstart's text fallback is now an equal
alternative to the embed rather than a failure path: it covers the group
and topic screen the embed shows, including the Conversation Summary
option that makes conversation_id required on every write.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
Settle the console reference so the term always links to the page and the
sign-in URL always attaches to Weaviate Cloud. Give illustrative topic
names the PascalCase the API actually matches case-sensitively, on the
same pages that now warn a wrong case is a 422. Put List memories ahead
of Get and Delete, the order the page intro and every other page already
use. Deep-link bounded-topic and get/wait references, and give two
internal links the .md the link checker needs to see them.

Say what a reader of the rendered page can act on: the REST reference's
overview text rather than the spec's info.description, the REST shape of
retrieval_config alongside the Python models, a retrieval-type heading
that matches its block, and a Manage-memories description that is not a
survivor of the pre-List page. Plan limits now live in one place. Align
"managed memory service" across the FAQ, the navbar, the announcement
bar and the spec README, and correct that README's claim that 67a0248 is
the v0.0.40 release commit — it is the dev-deploy commit, byte-identical
to the production build f2e6cbb.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
The retrieval-type sweep left "returns ranked results" covering fetch,
which concepts/search.md says does not rank. Attribute ranking to the
query-based types. Also note that an explicitly configured repo_name is
resolved whatever the group's schema says, so the plugin's default
recall filter can apply even to a group that is not scoped by it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
api_overview.sh assigned the group listing to GROUPS, which bash reserves
for the caller's group IDs: the assignment is discarded, $GROUPS expands
to the numeric primary GID, and jq fails with "Cannot index number with
string". The check could never pass on any machine. Rename it, and leave
a comment so it does not come back.

The lockfile pinned weaviate-engram 0.6.0, which has neither the
timestamp fields on StringInput nor the four retrieval models these
snippets import, so the documented 1.x surface could not run under it.
Require 1.0.1 and relock.

In the context-window tutorial, only the search was guarded, but the add
that carries conversation_id is rejected first on a project where no
topic declares that key. Guard the whole sequence, which is what the
block's own comment already claimed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
Six claims did not survive a run against a real project.

Input timestamps do not order memories: the stored created_at/updated_at
are ingest wall-clock and nothing on the memory carries the time you
sent. What they demonstrably do is anchor relative-time resolution during
extraction, which is the better reason to send them anyway.

scope_properties is omitted, not empty, for a topic that has none, so
reading it as an array raises. properties appears only on memories whose
topic declares scope properties — a UserKnowledge memory has no such key
even when the write carried a conversation_id. created_at is refreshed
when a memory is rewritten, so it is a last-write time. /health returns
$schema like every other body, and a validation error omits value when
the rejected value was null.

Also record that a mistyped topic name is silent until the scope has
data: searching a user with no memories returns 200 and an empty list for
a topic that does not exist, which is exactly when a reader is hunting a
typo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E74iUw2NdCfeUBf9eRqqJb
Ivan removed docs/engram/api-overview.md, its _includes/api_overview.sh
snippets, the SDK exception list, the TypeScript note and the Claude Code
plugin deep-dive, leaving the plugin section pointing at the upstream README.

That left four links resolving to nothing. console.md and concepts/groups.md
now point GET /v1/groups at the REST reference — deliberately with no anchor,
since Scalar generates those — and each sentence gained a clause saying what
the endpoint returns, so neither depends on the reader following the link.
index.md drops the API-overview bullet, whose neighbour already covers the
same ground, and console.md's Plans section points at pipeline runs.

The plan numbers came home. An earlier pass had emptied console.md of them on
the premise that api-overview.md owned them; that premise died with the page,
so the free plan's 1,000 runs per month, its 1-project cap and the 429 at the
cap are stated where the reader meets them.

One sentence survives from the deleted plugin deep-dive: recall defaults to
the current repository via the repo_name property. The upstream README says
the opposite in one place and the truth in another, so a bare pointer would
route readers to the wrong claim.

Also fixes an unclosed </details tag in quickstart.md that broke the client
bundle: MDX consumed forward from it and choked on an apostrophe two lines
below.

@orca-security-eu orca-security-eu Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Infrastructure as Code high 0   medium 0   low 0   info 0 View in Orca
Passed Passed SAST high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Vulnerabilities high 0   medium 0   low 0   info 0 View in Orca

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant