Skip to main content
EverOS runs as a service — start the server, then call the HTTP API. There is no in-process library mode; an everos server is always in front of your agent.

Prerequisites

  • Python 3.12+
  • An OpenRouter API key — covers the chat LLM (memory extraction) and the multimodal LLM (parsing image / pdf / audio content items) with a single key.
  • A DeepInfra API key — for the embedding and rerank models that OpenRouter doesn’t ship.
Two keys total. Any OpenAI-compatible endpoint plugs in via the matching *__BASE_URL env var if you’d rather use OpenAI directly, self-host vLLM, route to Ollama, etc.

Steps

1

Install

pip install everos
# or:  uv pip install everos
2

Configure

Generate the starter config files and drop in your two keys:
everos init                       # writes ~/.everos/everos.toml + ome.toml (use --root to relocate)
chmod 600 ~/.everos/everos.toml    # the file holds your API keys
everos init generates two files in the memory root (~/.everos by default): everos.toml (provider and application settings) and ome.toml (offline strategy config, hot-reloaded). Open everos.toml and fill the api_key field in each provider section; only two distinct keys are needed:
Sectionapi_key provider
[llm]OpenRouter (chat LLM)
[multimodal]OpenRouter (same key works)
[embedding]DeepInfra
[rerank]DeepInfra (same key works)
The template ships model defaults for [llm] (gpt-4.1-mini) and [multimodal] (google/gemini-3-flash-preview). [embedding] and [rerank] ship no model default, so set their model and base_url yourself (for example DeepInfra’s Qwen/Qwen3-Embedding-4B and Qwen/Qwen3-Reranker-4B). To use a different OpenAI-compatible endpoint for any provider, set that section’s base_url.
everos init and everos server start must use the same root: relocate with everos init --root <path> and start with the matching --root <path> (or set EVEROS_ROOT). The server reads <root>/everos.toml and exits with an error if it is missing. Any setting can also be overridden by an EVEROS_* environment variable (e.g. EVEROS_LLM__API_KEY), handy for containers and CI. Edits to everos.toml need a server restart; ome.toml hot-reloads within ~2s.
3

Start the server

everos server start
You should see:
starting everos on 127.0.0.1:8000
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
The default bind is 127.0.0.1 (loopback only). To expose the API elsewhere, put your own auth/gateway in front first. The cascade index daemon runs in the same process as a FastAPI lifespan coroutine — you don’t need a separate worker.
The server runs in the foreground. Open a second terminal for the steps below, and use Ctrl+C to stop the server when you’re done.In the second terminal, verify the server is up:
curl http://127.0.0.1:8000/health
# {"status":"ok"}
4

Add a conversation

EverOS ingests memory at the conversation level: you POST a batch of messages tied to a session_id, and the server accumulates them until the boundary detector trips.
TS=$(($(date +%s)*1000))    # Unix epoch in milliseconds (v1 contract)
curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
  -H 'Content-Type: application/json' \
  -d "{
    \"session_id\": \"demo-001\",
    \"app_id\": \"default\",
    \"project_id\": \"default\",
    \"messages\": [
      {\"sender_id\": \"alice\", \"role\": \"user\", \"timestamp\": $TS, \"content\": \"I love climbing in Yosemite every spring.\"},
      {\"sender_id\": \"alice\", \"role\": \"user\", \"timestamp\": $((TS+10000)), \"content\": \"My favorite coffee shop is Blue Bottle in SOMA.\"},
      {\"sender_id\": \"alice\", \"role\": \"user\", \"timestamp\": $((TS+20000)), \"content\": \"I bike to work most days.\"}
    ]
  }"
Response:
{
  "request_id": "bf86e4e857834eba804841f8bff29106",
  "data": {
    "message_count": 3,
    "status": "accumulated"
  }
}
status: "accumulated" means the messages are in the session buffer, but the boundary detector hasn’t decided to extract a memory cell yet.
5

Force boundary extraction

For a quick demo, force extraction manually:
curl -X POST http://127.0.0.1:8000/api/v1/memory/flush \
  -H 'Content-Type: application/json' \
  -d '{"session_id":"demo-001","app_id":"default","project_id":"default"}'
Response (this takes a few seconds — one LLM call for extraction):
{
  "request_id": "ec0e7a00c3bd4b00bb21212a411b7763",
  "data": {
    "status": "extracted"
  }
}
status: "extracted" means at least one memory cell was carved out and written to disk and indexed.
/flush is OSS-only. The cloud edition decides boundary timing server-side and does not expose this endpoint.
6

Search your memory

curl -X POST http://127.0.0.1:8000/api/v1/memory/search \
  -H 'Content-Type: application/json' \
  -d '{
    "user_id": "alice",
    "app_id": "default",
    "project_id": "default",
    "query": "Where do I like to climb?",
    "top_k": 5
  }'
Response (trimmed):
{
  "request_id": "b53a3a94a080472d97692c503c88afdf",
  "data": {
    "episodes": [
      {
        "id": "alice_ep_20260528_00000002",
        "user_id": "alice",
        "session_id": "demo-001",
        "summary": "On May 28, 2026 ... Alice shared that she loves climbing in Yosemite every spring ...",
        "score": 0.628,
        "atomic_facts": [
          {
            "id": "alice_af_20260528_00000016",
            "content": "Alice said she loves climbing in Yosemite every spring.",
            "score": 0.628
          }
        ]
      }
    ],
    "profiles": [],
    "agent_cases": [],
    "agent_skills": []
  }
}
The hybrid retrieval (BM25 + vector + scalar) returns the episode that contains the climbing fact, with the matching atomic fact nested under it. The other arrays (profiles / agent_cases / agent_skills) are always present for client-side symmetry and are populated only when the relevant memory type matches.

Your memory is just Markdown

This is what makes EverOS different — your memory persists as plain Markdown files on disk:
~/.everos
├── everos.toml                        ← provider + application config (API keys)
├── ome.toml                           ← offline strategy config (hot-reloaded)
├── default_app/                       ← app_id  ("default" → "default_app")
│   └── default_project/               ← project_id ("default" → "default_project")
│       └── users/
│           └── alice/                  ← user_id
│               ├── episodes/
│               │   └── episode-2026-05-28.md
│               ├── .atomic_facts/
│               │   └── atomic_fact-2026-05-28.md
│               ├── .foresights/
│               │   └── foresight-2026-05-28.md
│               └── user.md             ← profile
└── .index/                             ← derived indexes (rebuildable from md)
    ├── sqlite/system.db
    └── lancedb/*.lance/
The default scope ID materialises as default_app / default_project on disk so the default space is visually distinct from any user-named space. Any other ID maps to itself (e.g. app_id: "my-app"my-app/). Top-level .index/ holds SQLite + LanceDB derived indexes — wipe it and the cascade daemon rebuilds everything from the Markdown alone. Every memory entry is a plain file you can cat / grep / vim directly, version with Git, or open in Obsidian (the dotfile directories stay hidden by default).

Stopping the server

Ctrl+C in the server terminal. Uvicorn shuts each lifespan provider down in reverse order before exiting.

Next steps

Integrate into your agent

Add /add, /flush, and /search to your agent loop. Any HTTP client works.

Scope your memory

Use app_id and project_id to isolate memory for different apps or projects.

Multi-modal messages

Pass images, audio, PDFs, and documents alongside text. Install the multimodal extra to enable parsing.

Search modes

Choose from keyword, vector, hybrid, or agentic retrieval. Filter by user, session, or custom fields.