# Everos Persistent agent memory - Package: @bijectionhq/everos - Category: AI & Agents - Status: Preview - License: Apache-2.0 - Bijection source (repository access required): https://github.com/bijectionhq/everos/tree/a04f24a5cd2c27aef9f8cce2ee0b2b3aec327494 - Upstream: https://github.com/EverMind-AI/EverOS-Convex/tree/d7093b3ef4e37c024a2001bc9ffd2d9cde515194 - Documentation: https://docs.bijection.com/components/using - Directory: https://bijection.com/components/everos ## Get the source Bijection repository access is required. Request access at https://bijection.com/contact. ```sh git clone https://github.com/bijectionhq/everos.git cd everos git checkout a04f24a5cd2c27aef9f8cce2ee0b2b3aec327494 ``` ## Before using this component Read the package README at the recorded revision for setup, dependencies, and API examples. Upstream documentation describes the original package and may differ from the Bijection adaptation. This is a source candidate for evaluation. Catalog inclusion does not establish npm availability or runtime qualification. Check compatibility with your SDK and deployment before adoption. External providers run their own compute. ## Upstream package documentation Recorded 2026-10-23. This describes @everos-ai/convex; check the Bijection adaptation separately. EverOS Memory provides persistent, cross-thread, cross-session long-term memory for Convex apps and agents via the EverOS Cloud API. It exposes `remember` and `recall` methods that handle async memory extraction, local pending queues, and ranked retrieval with atomic fact provenance. The component integrates directly with `@convex-dev/agent` as either a tool or context injection, making user memory portable across agents, models, and sessions without requiring manual vector search infrastructure. ### Use cases - Building a multi-agent system where different agents or models need shared user context without access to each other's chat history - Adding user preference and behavioral memory to a support or assistant app so returning users are recognized across sessions - Constructing RAG context for agent prompts from structured user memories rather than raw chat log embeddings - Storing and auditing user-generated facts with timestamped, session-scoped provenance for consequential decisions like refunds or account changes - Implementing per-user memory namespacing across staging and production deployments on a single EverOS account ### How it works After installing the package and registering the component in `convex/convex.config.ts`, you instantiate `new EverOS(components.everos)` in your Convex module. Credentials are set via `EVEROS_API_KEY` in your Convex deployment environment and threaded into component calls as arguments, following Convex component authoring conventions where secrets are resolved in the app rather than inside the component itself. The `remember` method is a Convex mutation that enqueues content locally and flushes it to EverOS Cloud asynchronously. Extraction typically completes in 15 to 30 seconds. During that window, `recall` returns pending items marked `pending: true` from the local queue alongside already-extracted memories, so no content is invisible immediately after ingestion. Once extraction completes, queue rows are deleted and all reads go directly to EverOS. The `recall` action returns ranked episodic memories, a semantic user profile, and any pending items. Each episodic result includes `atomicFacts` with individual scores, timestamps, and session IDs for provenance tracing. For agent integration, `everos.asTool({ userId })` produces a `@convex-dev/agent`-compatible tool, and `everos.contextMessages` returns a message array for prepending recalled context before a prompt. Namespace isolation between environments is handled by passing `appId` and `projectId` options to the constructor. ### Upstream README # @everos-ai/convex Long-term memory for [Convex](https://convex.dev) apps, backed by [EverOS Cloud](https://evermind.ai/everos), the hosted service of [EverOS](https://github.com/EverMind-AI/EverOS) — the open-source agent memory OS (state of the art on LoCoMo). Drop-in `remember` / `recall` / user memory profiles for any Convex app, plus **one-line long-term memory for [`@convex-dev/agent`](https://docs.convex.dev/agents)**: persistent, cross-thread, cross-session memory that goes beyond vector search over chat logs. ```ts const everos = new EverOS(components.everos); await everos.remember(ctx, { userId, content: "I'm vegetarian" }); const memories = await everos.recall(ctx, { userId, query: "what do I eat?" }); ``` --- ## Install ```bash npm install @everos-ai/convex @convex-dev/agent zod ``` > `@convex-dev/agent` and `zod` are peer dependencies. The main entry imports > them for `asTool`, and Convex resolves imports when it pushes your code, so > they are required even if you only call `remember` / `recall`. Splitting the > agent helpers into their own entry point is tracked for a later release. > Both `@convex-dev/agent` 0.6 (AI SDK v6) and 0.7 (AI SDK v7) are supported; > npm installs the matching `ai` packages as its peers. ### 1. Register the component ```ts // convex/convex.config.ts import { defineApp } from "convex/server"; import everos from "@everos-ai/convex/convex.config"; const app = defineApp(); app.use(everos); export default app; ``` ### 2. Set your EverOS API key Get a free key at **[everos.evermind.ai](https://everos.evermind.ai/)** (free tier; API reference at [docs.evermind.ai](https://docs.evermind.ai/api-reference/introduction)), then: ```bash npx convex env set EVEROS_API_KEY # optional — defaults to https://api.evermind.ai npx convex env set EVEROS_BASE_URL https://api.evermind.ai ``` To keep separate memory spaces on one account (staging, a public demo, production), give each a namespace: ```ts new EverOS(components.everos, { appId: "staging", projectId: "staging" }); ``` Reads, writes and deletes are all scoped to it, so nothing under one namespace is searchable or deletable from another. Issuing a second API key does **not** do this: keys on the same account share a namespace. `EVEROS_APP_ID` / `EVEROS_PROJECT_ID` work too. The app-side client reads credentials from `process.env` (you can also pass `{ apiKey, baseUrl }` to `new EverOS(...)`). Per Convex component authoring best practice, secrets are resolved in your app and threaded into the component — they are never read inside the component itself. --- ## Usage > **Memory extraction is asynchronous.** EverOS runs layered extraction on > ingested content in the background — after `remember`, extracted memories > typically become searchable within **~15–30 seconds** (the component drives > extraction automatically). Until then, `recall` still returns the freshly > saved content from the component's local queue, marked `pending: true`, so > nothing is ever invisible. Long-term memory complements (doesn't replace) > your thread's conversation context: use the thread for "what was just > said", EverOS for "what's worth remembering across sessions". ```ts // convex/memory.ts import { action, mutation } from "./_generated/server"; import { components } from "./_generated/api"; import { v } from "convex/values"; import { EverOS } from "@everos-ai/convex"; const everos = new EverOS(components.everos); export const remember = mutation({ args: { content: v.string() }, handler: async (ctx, { content }) => { const userId = (await ctx.auth.getUserIdentity())!.subject; // auth in the app await everos.remember(ctx, { userId, content }); }, }); export const recall = action({ args: { query: v.string() }, handler: async (ctx, { query }) => { const userId = (await ctx.auth.getUserIdentity())!.subject; return await everos.recall(ctx, { userId, query, topK: 5 }); }, }); ``` `recall` returns ranked memories with provenance, plus anything remembered in the last few seconds that EverOS has not finished extracting yet: ```ts // abridged: every item also carries everosMemoryId and userId [ { kind: "episodic", text: "Alex Chen said he is on the Pro plan, billed annually, and asked to be contacted by email.", score: 0.41, timestamp: 1789509522956, sessionId: "support-2026-09", atomicFacts: [{ text: "Alex Chen is on the Pro plan.", score: 0.41, timestamp: 1789509522956 }], }, { kind: "profile", text: "Prefers email over phone.; Uses a Node.js stack on Vercel." }, { kind: "episodic", text: "Our webhooks started failing again this morning.", pending: true }, ] ``` ### API | Method | Kind | Description | | --- | --- | --- | | `everos.remember(ctx, { userId, content, role?, senderName?, sessionId?, timestamp? })` | mutation | Enqueue content; flushed to EverOS asynchronously | | | | Pass `senderName` whenever `userId` is opaque (a UUID, an auth subject). It is the attribution key, and without a display name extraction writes it into the fact text itself — `"1036ffce-… said their webhooks fail"`. | | `everos.rememberMessages(ctx, { userId, messages, sessionId? })` | mutation | Remember a whole turn (prompt **and** reply) in one call; each message takes its own `senderName` | | `everos.recall(ctx, { userId, query, topK?, kind?, includeRecent? })` | action | Retrieve relevant memories, ranked (plus not-yet-extracted content marked `pending`) | | | | `topK` bounds the ranked episodes only. Profiles ride along, and up to 5 `pending` items may be appended, so size prompts from the returned array rather than from `topK`. | | `everos.getProfile(ctx, { userId })` | action | Fetch the user's profile / semantic memory | | `everos.forgetSession(ctx, { userId, sessionId })` | action | Delete one session's memories remotely + locally | | `everos.forgetUser(ctx, { userId })` | action | Delete ALL of a user's memories remotely + locally | | `everos.getPendingStatus(ctx, { userId })` | query | Whether anything is still on its way to EverOS, and why if it is stuck | | `everos.listMemories(ctx, { userId, page?, pageSize? })` | action | Page through everything EverOS holds for a user, newest first | > **If something looks missing**, `getPendingStatus` says whether it is still > in flight or actually failed. A rejected API key shows up there as > `lastError`; without checking it, a bad key is indistinguishable from > extraction being slow. The component keeps no copy of your memories: queue > rows are deleted once EverOS has extracted them, and `recall` / > `listMemories` always read EverOS itself. Internals are in > [CONTRIBUTING.md](./CONTRIBUTING.md). --- ## Security model **`userId` is trusted input — derive it server-side.** The component performs no authentication of its own (it can't; only your app knows who is signed in). Every method reads and writes exactly the memory space of the `userId` you pass, so a `userId` taken from a client-supplied argument lets any caller read — or, via `forgetUser`, delete — anyone's memories. Always derive it from your app's auth, as every example in this README does: ```ts const userId = (await ctx.auth.getUserIdentity())!.subject; // never an arg ``` **Memories are user-generated content, not verified facts.** Whatever a user says is extracted and later replayed into prompts as context. That is the point of a memory system, but if your agent makes decisions on it (refunds, account changes, access), remember that users can seed their own memory with convenient "facts" ("support agreed to a full refund last month"). For anything with consequences, audit the claim: each recalled memory decomposes into `atomicFacts` with timestamps and session provenance. **Where the API key travels.** The key lives in your deployment's environment variables and is threaded into component calls as an argument, so it also appears in scheduled-function arguments (the `_scheduled_functions` system table) — visible to people with dashboard access to your deployment, who can already read your environment variables. It is never exposed to clients, and component functions are not callable from clients. Requests refuse non-HTTPS base URLs (loopback excepted, for self-hosted local dev), and `baseUrl` should only ever come from an environment variable or a constant — never from user input. --- ## Agent integration (`@convex-dev/agent`) Add persistent memory to any Convex agent in one line — either as a **tool** the model calls, or as **context** you prepend. ```ts import { Agent } from "@convex-dev/agent"; import { openai } from "@ai-sdk/openai"; import { EverOS } from "@everos-ai/convex"; import { components } from "./_generated/api"; const everos = new EverOS(components.everos); const agent = new Agent(components.agent, { languageModel: openai.chat("gpt-4o-mini"), instructions: "You have long-term memory of the user. Use searchMemory.", }); export const chat = action({ args: { threadId: v.string(), prompt: v.string() }, handler: async (ctx, { threadId, prompt }) => { const userId = (await ctx.auth.getUserIdentity())!.subject; // Option A — give the agent a memory-search tool: const result = await agent.generateText( ctx, { threadId, userId }, { prompt, tools: { searchMemory: everos.asTool({ userId }) } }, ); // Option B — prepend recalled memories as context: const messages = await everos.contextMessages(ctx, { userId, prompt }); // await agent.generateText(ctx, { threadId, userId }, { messages, prompt }); // Remember the turn for future threads/sessions: await everos.remember(ctx, { userId, content: prompt }); return result.text; }, }); ``` - `everos.asTool({ userId, topK? })` → a `@convex-dev/agent` tool that searches long-term memory. - `everos.contextMessages(ctx, { userId, prompt, topK? })` → an array of `{ role, content }` messages to pass as `messages` before your `prompt`. --- ## Demo app [`example/`](./example) is **Mindy**, an AI support desk built on `@convex-dev/agent` + this component. A returning customer chats with the frontline agent (GPT-4o-mini); clicking **Escalate to specialist** hands the conversation to a different agent on a different model (Llama-3.3-70B) in a **brand-new thread with zero shared chat history** — the specialist greets the customer already knowing their plan, stack, and issue, purely from EverOS memory. A live agent console shows the customer's memory profile, per-message recalled context with traceable atomic facts (scored + timestamped), and the memory pipeline activity feed. It demonstrates the differentiator vs a model's built-in memory: **memory belongs to the user — portable across agents, models, and sessions — and auditable**. ```bash cd example npm install npx convex env set EVEROS_API_KEY # LLM: either OpenRouter (any model) or plain OpenAI npx convex env set OPENROUTER_API_KEY sk-or-... # uses openai/gpt-4o-mini # or: npx convex env set OPENAI_API_KEY sk-... npm run dev ``` To reset between recordings: `npx convex run demo:clearAll` wipes all demo conversations, the agent console state, and the customers' EverOS memories. --- ## Testing To test the component inside your own app, register it with a [`convex-test`](https://docs.convex.dev/testing/convex-test) instance: ```ts import { convexTest } from "convex-test"; import schema from "./schema.js"; import everos from "@everos-ai/convex/test"; const t = convexTest(schema, import.meta.glob("./**/*.ts")); everos.register(t); ``` --- ## Contributing Design notes, how the ingestion pipeline works, and local development setup are in [CONTRIBUTING.md](./CONTRIBUTING.md). Changes go through pull requests; CI (build, tests, secret scan) must pass before merging. --- ## License Apache-2.0 © [EverMind](https://evermind.ai)