Everos
Persistent agent memory
git clone https://github.com/bijectionhq/everos.git
cd everos
git checkout a04f24a5cd2c27aef9f8cce2ee0b2b3aec327494Bijection repository access is required. Request access.
Description
Persistent agent memory
Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.
Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.
Getting started
- Get the source at the revision above and read its package documentation.
- Check the required Bijection SDK version, dependencies, and external service credentials.
- Follow the package setup instructions and the guide to using components.
- Exercise the component in your deployment according to your project’s verification rules.
Open source
Maintained source: bijectionhq/everos. Based on EverMind-AI/EverOS-Convex. License: Apache-2.0. Consult the repository for license terms, notices, and contributor attribution.
From the upstream publisher
Long-term memory for Convex apps, backed by EverOS Cloud. Drop-in remember/recall plus one-line memory for @convex-dev/agent.
Explore the demo ↗Upstream overview
From the upstream package documentation.
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
From the upstream package documentation.
- 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
From the upstream package documentation.
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 package FAQ
How long does it take for a remembered fact to become searchable in EverOS Memory?
EverOS Memory runs extraction asynchronously in the background. After calling everos.remember(), extracted memories are typically searchable within 15 to 30 seconds. During that window, everos.recall() still returns the raw content from the component's local queue marked with pending: true, so recently ingested content is never invisible to your application.
Does EverOS Memory work with @convex-dev/agent?
Yes. EverOS Memory is designed to integrate directly with @convex-dev/agent. You can expose memory search as a tool the model calls using everos.asTool({ userId }), or prepend recalled memories as a message array using everos.contextMessages(). Both @convex-dev/agent 0.6 and 0.7 are supported.
How do I keep memory separate between staging and production environments?
EverOS Memory supports namespacing via the appId and projectId options passed to new EverOS(components.everos, { appId: 'staging', projectId: 'staging' }). All reads, writes, and deletes are scoped to that namespace. Using separate API keys on the same account does not isolate namespaces; you must use appId and projectId for that.
How should I handle the userId parameter securely in EverOS Memory?
The EverOS Memory component does not perform authentication itself. The userId parameter controls which user's memory is read or written, so it must always be derived server-side from your app's auth system, for example from ctx.auth.getUserIdentity(). Passing a client-supplied userId as an argument would allow any caller to read or delete another user's memories via everos.recall() or everos.forgetUser().
Can I page through or audit everything EverOS has stored for a user?
Yes. EverOS Memory provides everos.listMemories({ userId, page, pageSize }) to paginate through all memories stored for a user in EverOS Cloud, returned newest first. Each recalled memory also includes atomicFacts with individual scores and timestamps, and a sessionId for tracing which conversation produced the memory.
Use with agents and CLI
Give your coding agent the component’s source identity and setup guidance.
Help me integrate Everos with Bijection.
Read: https://bijection.com/components/everos/SKILL.md
Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.Upstream README.md
View repository ↗Documentation from EverMind-AI/EverOS-Convex, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.
@everos-ai/convex
Long-term memory for Convex apps, backed by EverOS Cloud, the hosted service of 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:
persistent, cross-thread, cross-session memory that goes beyond vector search
over chat logs.
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
npm install @everos-ai/convex @convex-dev/agent zod
@convex-dev/agentandzodare peer dependencies. The main entry imports them forasTool, and Convex resolves imports when it pushes your code, so they are required even if you only callremember/recall. Splitting the agent helpers into their own entry point is tracked for a later release. Both@convex-dev/agent0.6 (AI SDK v6) and 0.7 (AI SDK v7) are supported; npm installs the matchingaipackages as its peers.
1. Register the component
// 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 (free tier; API reference at docs.evermind.ai), then:
npx convex env set EVEROS_API_KEY <your-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:
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,recallstill returns the freshly saved content from the component's local queue, markedpending: 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".
// 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:
// 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,
getPendingStatussays whether it is still in flight or actually failed. A rejected API key shows up there aslastError; 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, andrecall/listMemoriesalways read EverOS itself. Internals are in 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:
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.
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/agenttool that searches long-term memory.everos.contextMessages(ctx, { userId, prompt, topK? })→ an array of{ role, content }messages to pass asmessagesbefore yourprompt.
Demo app
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.
cd example
npm install
npx convex env set EVEROS_API_KEY <your-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 instance:
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. Changes go through pull requests; CI (build, tests, secret scan) must pass before merging.
License
Apache-2.0 © EverMind