A knowledge pack is a document you upload to Truememory — PDF, Markdown, or plain text — so an agent can quote from it when it answers. Truememory parses the file, splits it into chunks, embeds them, and stores them. At request time it pulls the passages most relevant to what the user asked and adds them to the agent’s system prompt as a Relevant Document Context section.
The point is grounding: instead of hoping the model already knows your handbook, pricing sheet, or SOP, you attach the source and let the agent answer from it. Your app decides which packs apply to a given request; Truememory handles storage, retrieval, and access.
To attach a whole set of packs at once instead of listing IDs on every request, group them under a brain.
Think of it like a shared reference shelf. You put a document on the shelf (upload), tag which agents or skills may pull it down (see Retrieval), and the agent quotes the relevant page when it answers.
Where that metaphor breaks down: the agent never receives the whole document. Retrieval returns only the highest-scoring chunks for the current question, not the full file.
flowchart TD
subgraph Ingest["1 · Upload once"]
direction LR
U["Upload a file<br/>PDF · Markdown · text"] --> P["Parse → chunk → embed"]
P --> S["Stored & searchable<br/>status: ready"]
end
subgraph Ask["2 · Every chat request"]
direction LR
R["POST /v1/chat/completions<br/>skill_id and/or knowledge_pack_ids"] --> E["Embed the user's message"]
E --> H["Hybrid search<br/>vector + keyword (RRF)"]
H --> C["Inject top chunks as<br/>Relevant Document Context"]
C --> A["Grounded answer"]
end
S -.->|"only visible, ready packs"| H
style U fill:#f0f9ff,stroke:#3b82f6,color:#181818
style P fill:#e6f4ff,stroke:#0a99ff,color:#181818
style S fill:#ecfdf5,stroke:#10b981,color:#181818
style R fill:#f0f9ff,stroke:#3b82f6,color:#181818
style E fill:#e6f4ff,stroke:#0a99ff,color:#181818
style H fill:#e6f4ff,stroke:#0a99ff,color:#181818
style C fill:#e6f4ff,stroke:#0a99ff,color:#181818
style A fill:#ecfdf5,stroke:#10b981,color:#181818
All knowledge pack endpoints require authentication. User-scoped endpoints (/knowledge-packs) accept either:
- a user Bearer token from Truememory Auth
- the calling app’s service token plus
X-On-Behalf-Of: <user_id>when your backend is proxying for a user
Admin endpoints (/admin/knowledge-packs/*) require the service token or an admin user token — see Admin endpoints.
Retrieval
This is how a pack actually reaches the model. On a /v1/chat/completions request, opt in with any of these fields:
| Field | Type | What it does |
|---|---|---|
skill_id |
string | null | Pull packs tagged with this skill — the id of a skill registry entry (see Assigning packs to a skill) |
knowledge_pack_ids |
string[] | null | Pull these specific packs by id |
brain_id |
string | null | Pull every pack in a brain. Ignored when knowledge_pack_ids is also set |
brain_ids |
string[] | null | Pull every pack in several brains, merged and deduplicated. brain_id is the singular alias — both are honoured together |
All are optional. skill_id and knowledge_pack_ids can be combined; brain_id/brain_ids resolve to a set of pack IDs and are a shorthand for the second. When all are absent, no document context is injected — retrieval only runs when you ask for it.
POST https://your-tie-host/v1/chat/completions
Authorization: Bearer $TOKEN
Content-Type: application/json
{
"model": "anthropic/claude-sonnet-4-5",
"messages": [
{ "role": "user", "content": "What's our refund window for annual plans?" }
],
"knowledge_pack_ids": ["7f3c..."]
}Under the hood: Truememory embeds the user’s latest message, runs a hybrid search (vector similarity + keyword match, fused with reciprocal rank fusion) over the chunks you’re allowed to see, and injects the top results into the system prompt under a Relevant Document Context heading. Only packs with status ready are searched.
A pack is retrievable on a request only if the caller can see it — see Visibility. skill_id and knowledge_pack_ids narrow within what’s visible; they never widen it.
Uploading a pack
POST https://your-tie-host/knowledge-packs?skill_id=<uuid>&app_id=vibrantly
Authorization: Bearer $TOKEN
Content-Type: multipart/form-data
file=@handbook.pdfAccepted file types are PDF (application/pdf), Markdown (text/markdown), and plain text (text/plain). The skill_id and app_id query params are optional — they tag and scope the pack (see Visibility and Assigning packs to a skill).
Ingestion runs in the background, so the response comes back immediately with status: "pending". The status then moves through:
pending → processing → ready (searchable) — or error if parsing or embedding fails.
Poll GET /knowledge-packs (or the admin detail endpoint) to watch the status. A pack is only returned by Retrieval once it reaches ready. If ingestion fails, re-upload — there is no automatic retry.
GET https://your-tie-host/knowledge-packs
Authorization: Bearer $TOKENReturns the packs the calling user owns — both the ones they uploaded and the ones they’ve been granted access to. Delete a pack you own with DELETE /knowledge-packs/{pack_id}.
Visibility
Every pack has three tiers of visibility, derived from user_id and app_id:
user_id |
app_id |
Who can retrieve it |
|---|---|---|
| set | — | Only that user |
null |
vibrantly |
Every user of that app |
null |
null |
Everyone, every app (global) |
Retrieval always applies this filter first, then narrows by skill_id / knowledge_pack_ids. A user cannot pull a pack scoped to another user or another app, even if they pass its id.
Ownership and entitlements
Visibility answers “who is allowed to see this.” Entitlements answer a different question: “which specific users own this pack.” A pack can be a product that’s granted (or sold) to many users, and ownership is cross-app — a grant made through any app makes the pack show up for that user everywhere they go.
Think of it like a per-seat license. The pack is the product; an entitlement is one user’s seat, valid across every app on the platform. The pack’s own user_id still records who uploaded it; entitlements are a separate grant layer on top.
The app_id on an entitlement records the app the user acquired it through — attribution for billing, nothing more. It does not restrict where the pack appears; a user with a grant sees it from every app.
# Grant a user access to a pack (idempotent)
POST https://your-tie-host/admin/knowledge-packs/{pack_id}/entitlements
Authorization: Bearer $AUTH_SECRET
Content-Type: application/json
{ "user_id": "1111...", "app_id": "blinklife" }| Endpoint | Behavior |
|---|---|
POST /admin/knowledge-packs/{id}/entitlements |
Grant ownership to a user. Re-granting updates the acquiring app_id |
DELETE /admin/knowledge-packs/{id}/entitlements/{user_id} |
Revoke a user’s access |
GET /admin/knowledge-packs/{id}/entitlements |
List everyone with access, enriched with each user’s name and email |
Truememory stores the grant only — it takes no part in pricing or purchase flow. Your backend confirms a sale (or any access decision) and records it here.
Managing the document
These admin endpoints let an operator review and revise a pack after upload.
| Endpoint | Behavior |
|---|---|
GET /admin/knowledge-packs/{id} |
Fetch a single pack’s metadata |
GET /admin/knowledge-packs/{id}/content |
The extracted text (reconstructed from the stored chunks), plus has_original |
PUT /admin/knowledge-packs/{id}/content |
Replace the extracted text and re-embed it in place |
PUT /admin/knowledge-packs/{id}/file |
Re-upload a file; re-ingests in place, keeping the same id and its entitlements |
GET /admin/knowledge-packs/{id}/file |
Download the original uploaded file |
GET /admin/knowledge-packs/{id}/events |
Change log: uploaded, text_edited, file_reuploaded with timestamps |
Editing the text or re-uploading a file wipes the old chunks and re-embeds, so retrieval reflects the change once the pack returns to ready. Both keep the same pack id — so entitlements and any skill_id tag survive the change.
Original file availability. Truememory only retains the raw uploaded file when object storage is configured (GCS_BUCKET set). Without it, ingestion keeps the extracted text and embeddings but discards the original — has_original is false and the download endpoint returns 404. The extracted-text endpoints work either way.
Assigning packs to a skill
A pack carries an optional skill_id tag. Tagging a pack to a skill is what lets a chat request pull it in by passing that skill_id (see Retrieval). Set or clear the tag without re-uploading:
PUT https://your-tie-host/admin/knowledge-packs/{pack_id}/skill
Authorization: Bearer $AUTH_SECRET
Content-Type: application/json
{ "skill_id": "9a2b1f6e-1111-2222-3333-444455556666" }The tag is a soft association, not ownership: deleting the skill clears the tag but keeps the document. A pack holds one skill_id at a time, so re-assigning moves it.
Admin endpoints
The /admin/knowledge-packs/* block manages packs across all users without the per-user visibility filter. It’s gated by the Truememory service token (AUTH_SECRET) or an admin user token; end-user tokens cannot reach it. Use it to create global or app-scoped packs, list across users, and run the management and entitlement operations above.
# Create a global pack (user_id = null) scoped to one app
POST https://your-tie-host/admin/knowledge-packs?app_id=vibrantly
Authorization: Bearer $AUTH_SECRET
Content-Type: multipart/form-data
file=@pricing.mdGET /admin/knowledge-packs lists across everyone with user_id, app_id, skill_id, and status filters plus limit/offset.
Common pitfalls
- Expecting a pack to be used automatically. It isn’t. A request injects document context only when it passes
skill_id,knowledge_pack_ids,brain_id, orbrain_ids. Remember the precedence: explicitknowledge_pack_idsoverride (and disable) the brain fields. Uploading a pack does nothing on its own. - Searching a pack that isn’t
readyyet. Ingestion is asynchronous. A freshly uploaded pack ispending/processingand is skipped by retrieval until it reachesready. - Passing an id you can’t see.
knowledge_pack_idsnarrows within your visibility; it never bypasses it. An id scoped to another user or app returns nothing. - Confusing the acquiring
app_idwith a scope. On an entitlement,app_idis attribution only. Ownership is cross-app — the pack shows up for that user from every app regardless. - Expecting the original file back without object storage. When
GCS_BUCKETis unset, only the extracted text is retained; the original download is unavailable. - Deleting a skill to remove its documents. Deleting a skill only clears the
skill_idtag on its packs; the packs remain. Delete the packs themselves if that’s the intent.