Skip to content

Latest commit

History

69 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

EcoDB: Collective AI memory infrastructure

ReleaseLicensePythonMCP ToolsLangChainDashboardDocker

EcoDB in motion — GAMR search, knowledge graph, ingestion, and the desktop dashboard

Personal AI memory tools serve one agent, one session. EcoDB extends this to teams: a shared memory system where multiple agents store, search, connect, and govern knowledge across projects, with workspace isolation, role-based permissions, and a knowledge graph that links entities across memories and documents.

The vision: move from personal developer memory to enterprise competitive intelligence. One system, multiple users, governed knowledge.

In production since May 2026.

Why not just vector search?

Standard RAG retrieves by cosine similarity. That works for simple recall, but falls apart when you need:

ProblemVector searchEcoDB GAMR
"What's connected to X?"Doesn't knowGraph traversal (Apache AGE)
Latest decision vs. stale oneTreats them equallyTemporal freshness scoring
Two memories that contradictReturns both silentlyDetects and flags contradictions
Text query finding an imageNot possibleCross-modal search (text ↔ image)
Agent A's notes vs. Agent B'sNo distinctionGoverned visibility by workspace/project

Multimodal Memory

EcoDB multimodal memory — what goes in

EcoDB stores and searches across text, images, and documents in the same system.

Jina v4 embeds text and images into the same 512-dimensional vector space. A text query retrieves relevant images. An image query retrieves relevant text. Search results mix memories, document chunks, and graph discoveries in a single ranked response, with images returned inline.

  • Store: save_memory(content="...", file_path="image.png") embeds both text and image, copies to media store
  • Search: search(query_text="...") returns text and image memories ranked together
  • View: view_image(memory_id) returns the actual image inline, visible to the consuming LLM

Documents (PDF, DOCX, PPTX, audio) are parsed, chunked, embedded, and searchable alongside memories. The GAMR pipeline scores everything uniformly; it doesn't distinguish between a memory saved by an agent and a chunk extracted from a PDF.

Benchmarks

LoCoMo (ACL 2024)

EcoDB benchmarks on LoCoMo (ACL 2024)

Evaluated on LoCoMo (Maharana et al., ACL 2024), a long-context conversational memory benchmark. 10 conversations, 1,982 queries, session-level retrieval:

MetricK=5K=10K=20
Recall@50.9140.9060.922
Recall@10*0.9310.959

* K=5 returns only 5 results, so R@10 cannot improve beyond R@5.

By query type (Recall@5, K=20): adversarial 0.95 · open-domain 0.94 · temporal 0.92 · single-hop 0.91 · multi-hop 0.73

10 conversations, no exclusions. Full methodology and scripts in eval/.

Why Recall@K?

EcoDB is a retrieval system, not a question-answering system. We report Recall@K because it isolates retrieval quality independent of the downstream LLM.

LLM-as-Judge accuracy conflates two capabilities: the memory system's ability to find relevant information, and the LLM's ability to reason over whatever it receives. A powerful LLM can infer correct answers from tangentially related context, scoring well even when retrieval fails. This means the metric rewards LLM reasoning ability rather than retrieval quality — the opposite of what you want when evaluating a memory system.

Recall@K has no such confound. The correct document is in the top K or it isn't. The metric is LLM-agnostic, reproducible, and directly measures what a memory system is responsible for: finding the right information.

Search latency

Configp50p95
Standard (limit=5)44ms44ms
Full pipeline (limit=20, graph discovery)44ms48ms

Measured on a single NVIDIA RTX 2080 Ti (11 GB). The full 10-stage GAMR pipeline completes in under 50ms at p95.

Internal golden set

We also maintain a harder internal benchmark against EcoDB's production corpus: 1,400+ memories across multiple languages and dozens of topics, paragraph-level retrieval instead of session-level. This is where we explore our margin of improvement. It's the benchmark that still challenges the system. Detailed methodology and results in eval/BENCHMARKS.md.

Dashboard

EcoDB v1.1 ships a desktop dashboard (Electron) — visual governance over the entire system. The engine was reachable only through the REST API and MCP tools; now there's a GUI to search, explore, ingest, and govern the knowledge base.

EcoDB desktop dashboard — quick tour

  • Command Center — workspace overview: attention inbox, live activity (SSE), knowledge health, ingestion pipeline.
  • Knowledge Explorer — GAMR search across memories and documents, with author / tag / workspace / project filters, UltraSearch, and document preview.
  • Graph Studio — the knowledge graph on a canvas: pan, zoom, re-center, expand neighbors, merge entities.
  • Decisions Inbox — review what the system flagged: stale memories, alias candidates, unconfirmed relations, low-trust documents.
  • Ingestion — upload documents and watch them flow through the pipeline (pending → indexed) in real time.
  • Ontology Console — curate the graph's vocabulary: entity dictionary, canonical predicates, alias management (manual scan + merge direction), merges.
  • Memory Agent — the metacognition surface: schedule the reflection cells, review consolidated clusters, and track foresights, distilled skills, and run telemetry (see Metacognition).
  • Settings — configurable backend URL (connect to a local Docker stack or a remote EcoDB instance on your network), API keys, trust tiers.

Built with React + TypeScript + Tailwind on Electron, talking to the same REST API. The API key never leaves the main process. Windows installer (unsigned — SmartScreen will warn on first run).

GAMR Engine

EcoDB's GAMR engine (Graph-Augmented Multimodal Retrieval) is a 10-stage scoring pipeline:

GAMR: 10-stage scoring pipeline

Query classification → embedding → vector retrieval (with UltraSearch multiplier) → BM25 lexical → graph expansion → source resolution → freshness → contradiction detection → multiplicative composite scoring → optional cross-encoder reranking. Each stage adds a signal that pure vector search doesn't have. The query type (factual, analytical, historical, contextual) adjusts signal weights automatically.

Knowledge Graph

Knowledge graph as a make-sense layer

Most AI memory systems use knowledge graphs as a retrieval signal, a score bonus in the ranking formula. EcoDB uses the graph differently. The graph is a make-sense layer: it provides curated context so the consuming LLM understands the ecosystem and the user's request before searching.

Vector search finds what's similar. The graph finds what's related. A decision made last month about database schema has zero semantic similarity to today's question about API design, but they're connected through shared entities. The graph surfaces that connection.

  • Apache AGE: Cypher queries inside PostgreSQL, no separate database
  • ~100 canonical predicates with ontological metadata (symmetry, inverses, transitivity, domain/range)
  • Traversal tools: neighbors (depth N), path_between (shortest path), search_nodes (fuzzy), co-occurrence analysis
  • Graph bonus = 5% of GAMR composite score, deliberately low. The graph's value is in exploration, not ranking

Automatic entity extraction

GLiNER extracts entities from every memory and document chunk at ingestion time and links them to the graph automatically. But automatic extraction alone generates noise. EcoDB combines GLiNER with an entity dictionary, a curated list of allowed entities with canonical names and aliases. Dictionary matches take priority over raw NER predictions. Entities that don't match the dictionary are flagged as candidates for human review.

Automatic linking feeds the graph. It never substitutes a healthy, curated graph. The system detects and suggests; the human decides.

Metacognition

Most memory systems are passive: they store what you give them and retrieve it on demand. EcoDB also reflects on its own memory — on a schedule, without prompting. Background workers ("cells") read the accumulated memories of each agent and write back higher-order knowledge: consolidated narratives, predicted events, distilled skills, and identity tensions.

EcoDB metacognition — cell workers turn raw memories into consolidated knowledge

Each cell is a cron-scheduled job over one agent's memory:

CellWhat it doesProduces
ConsolidationClusters related memories across time horizons (weekly → monthly → quarterly → yearly) and narrates each cluster. Each closed week's thematic clusters are woven into one unified weekly narrative (week rollup), with the themes preserved beneath it for drill-downTelescopic memory: a zoomable summary of what happened
Foresight extractionScans recent memories for temporal signals (deadlines, scheduled events) above a confidence thresholdForesights: events the system expects, urgency-scored
Skill distillationFinds cases that share a task type with a high success rate and abstracts the procedureSkills: reusable steps, tools, and failure modes
Identity tensionCompares how an agent behaves against how it describes itselfTensions: gaps between observed and declared traits

The result is a memory that gets more organized over time, not just bigger. A year of raw memories collapses into a telescopic narrative; recurring work becomes a named skill; an upcoming deadline surfaces before you ask.

It's all governed and surfaced in the dashboard's Memory Agent page:

  • Briefing — what the system is watching right now: urgency-sorted foresights, open identity tensions, and a telescopic preview.
  • Configs — schedule and tune the cells per agent (cron builder, model, prompt template), manage LLM providers (keys stored encrypted, never returned in clear).
  • Clusters — browse, search, and approve the consolidated narratives; drill into members and sources.
  • Foresights / Skills — the full per-agent view of predicted events and distilled procedures.
  • Telemetry — cell-run history and health: runs, durations, cost, errors.

Nothing runs without a schedule you set, and every consolidation is reviewable before it's trusted. The system distills and suggests; the human approves.

MCP Tools

Connect any MCP-compatible client (Claude Code, Claude Desktop, Cursor, Windsurf, etc.):

SSE transport — for clients that support SSE natively (e.g. Claude Code settings.json):

{
"mcpServers": {
"ecodb": {
"type": "sse",
"url": "http://localhost:8091/sse"
}
}
}

stdio transport — for clients that launch MCP servers as subprocesses (e.g. Claude Desktop claude_desktop_config.json):

{
"mcpServers": {
"ecodb": {
"command": "docker",
"args": ["exec", "-i", "ecodb-mcp", "python", "server.py", "--transport", "stdio"]
}
}
}

Note: The --transport stdio flag is required when using docker exec because the MCP container runs in SSE mode by default. Without it, the subprocess tries to bind port 8091 which is already in use by the running container.

ToolWhat it does
Memory
searchGAMR search (10-stage). Text and image queries, cross-modal
search_recentRecent memories with filters (agent, tags, date range)
get_relevant_contextContext injection — returns formatted context block for LLM consumption
save_memoryStore memory with optional image (auto-embeds, auto-extracts entities, auto-links graph)
read_memoryRead a memory by UUID
delete_memorySoft-delete to recycle bin
unarchive_memoryRestore from recycle bin
view_imageView image attached to a memory, inline to the LLM
Knowledge Graph
save_tripleAdd relationship to knowledge graph
save_triples_batchBatch add triples (max 100)
delete_tripleRemove a graph relationship
neighborsGraph neighbors at depth N
path_betweenShortest path between two nodes
search_nodesFuzzy search nodes by name
graph_statusGraph statistics (nodes, triples, predicates)
Identity
load_identityLoad agent identity fragments (ordered narrative)
save_identitySave agent identity (versioned snapshot)
Documents
register_documentRegister document for ingestion (PDF, DOCX, audio)
document_statusCheck document processing status
search_in_documentSearch within a specific document's chunks
read_documentRead document metadata and chunks
list_documentsList documents with filters
reindex_documentRe-queue document for processing
unlink_documentSoft-delete a document
classify_documentSet document trust tier (0–3)
confirm_document_relationConfirm related document pair
Governance
review_alias_candidateApprove or reject entity alias candidate
merge_entitiesSoft-merge source entity into target
undo_mergeRevert a merge operation
seed_dictionaryBulk-add entries to entity dictionary
validate_linkValidate entity↔memory link
get_graph_vocabularyRead entity dictionary and approved predicates
Metacognition
search_clustersSemantic search over fractal memory clusters (cosine + label BM25)
list_clustersList an agent's clusters by level / status
read_clusterRead a cluster's narrative (+ optional members / sources)
get_telescopic_viewLoad an agent's full fractal memory chain (yearly → weekly + last 3 days)
get_progressive_viewProgressive-zoom boot: each layer compresses the previous, closed periods are never re-read. One call loads an agent's whole memory (size-annotated for MCP hosts)
fractal_searchDrill-down navigation: enter at the highest abstraction, zoom by id (quarter → month → week → themes → raw memories), optional semantic ranking per scope
get_briefingAgent briefing: foresights + tensions + telescopic summary
narrate_clusterWrite / update a cluster narrative (owner-only)

UltraSearch

Standard search returns K results from a pool of K candidates. UltraSearch multiplies the internal candidate pool without changing the output size.

search(limit=5, deep_factor=4) fetches 20 candidates internally, runs the full GAMR pipeline on all 20, and returns only the best 5. You get K=20 retrieval quality at K=5 token cost: the LLM consuming the results processes 5 memories instead of 20.

deep_factor ranges from 1 (standard) to 10. Hard cap at 200 internal candidates. The only trade-off is compute time, not output cost.

LangChain Integration

EcoDB ships a first-class LangChain integration. Use it as a Retriever, a durable cross-session Memory, or a full agentic toolset (13 native tools, or 40 via MCP parity) — all backed by the GAMR retrieval engine.

The package lives in the repo at ecodb-langchain/ and installs from source (not yet on PyPI):

pip install -e ./ecodb-langchain
# optional extras
pip install -e "./ecodb-langchain[mcp]"# full 40-tool MCP parity (langchain-mcp-adapters)
pip install -e "./ecodb-langchain[openai]"# langchain-openai for the agent LLM
fromecodb_langchainimportEcoDBClient, EcoDBRetriever, make_ecodb_tools# base_url + api_key also default to env (ECODB_API_URL, ECODB_API_KEY)client=EcoDBClient(base_url="http://localhost:8080", api_key="ecodb_...")
# 1. As a LangChain Retriever over GAMR searchretriever=EcoDBRetriever(client=client)
docs=retriever.invoke("what did we decide about auth")
# 2. As an agentic toolset (13 native LangChain tools)tools=make_ecodb_tools(client)
InterfaceWhat it is
EcoDBClientSync httpx client with JWT auth, 1:1 with the MCP surface
EcoDBRetrieverBaseRetriever over GAMR search → list[Document] (semantic + graph + temporal)
EcoDBMemoryDurable cross-session LangChain memory
make_ecodb_tools(client)13 native tools: search, recent, save, graph nav, clusters, telescopic, briefing
build_ecodb_agent()Prebuilt LangGraph ReAct agent, model-agnostic
load_ecodb_mcp_tools() / build_ecodb_agent_from_mcp()Full 40-tool parity via langchain-mcp-adapters

Requirements: Python ≥ 3.10, langchain-core ≥ 0.3, httpx ≥ 0.27. Extras: [mcp] needs langchain-mcp-adapters ≥ 0.1, [openai] needs langchain-openai ≥ 0.3.

Architecture

EcoDB architecture

Two interfaces, same data:

  • REST API: 30+ endpoints with JWT auth, full CRUD, interactive docs at /docs
  • MCP Server: 40 tools via Model Context Protocol. Works with any MCP host (Claude Code, Cursor, Windsurf, custom clients). SSE or stdio transport.

Six Docker services:

ServiceRoleSize
postgresStorage + vector index + knowledge graph640 MB
apiFastAPI, GAMR engine, auth, CRUD10 GB
embeddingsJina v4 embedding model (GPU)10 GB
nerGLiNER named entity recognition8.3 GB
mcpMCP protocol server280 MB
llmllama.cpp + Qwen 2.5 3B (optional)2.2 GB

Ingestion

Two pipelines for two content types. Both produce memories with embeddings that feed into the same GAMR search.

Documents (Docling)

Docling parses PDFs, Word documents, HTML, and PowerPoint into structured chunks. Audio files go through Whisper for transcription. Each chunk inherits document metadata (tags, project, workspace) and is tracked through a lifecycle: pending → processing → indexed → error.

Pipeline: parse → chunk (960 tokens) → NER (GLiNER) → embed (Jina v4) → graph link → index

Conversational sessions (Session Parser)

Raw Claude Code sessions (JSON with speaker/text turns) are split into 5-turn sliding windows with 1-turn overlap before embedding. Each window becomes one memory tagged with session ID and chunk index. On retrieval, chunks are deduplicated back to session level.

In an isolated experiment on the same LoCoMo benchmark, this single ingestion change took Recall@5 from 0.769 to 0.922 (+19.9%) without any changes to the GAMR pipeline. The benchmarks above reflect this ingestion strategy applied across the full pipeline. For conversational data, ingestion granularity matters more than ranking sophistication.

Governance

The system controls who sees what, who can write where, and how knowledge flows between teams.

Governance model and roadmap

Role hierarchy

RoleScopeCan do
SuperuserGlobalEverything. Manage organizations, users, agents, ontology.
CEOOrganizationManage workspaces and projects within their org. Admin operations (entity dictionary, trust tiers, merges) scoped to org data.
Workspace LeadDepartmentManage projects and members within their workspace.
Project MemberProjectRead/write within assigned projects.

Memory visibility

Every memory has a visibility scope:

  • Public: visible to all members of the workspace
  • Private: visible only to the author (agent or user)
  • Workspace-scoped: cascading permissions from workspace → project

Agents operate within their assigned workspace and project. A sales agent can't read engineering memories unless explicitly granted access.

Multi-tenancy

EcoDB v0.9 adds organization-level isolation. Multiple teams share one EcoDB instance without seeing each other's data.

The organization is the tenant boundary. Every memory, document, workspace, project, API key, and audit entry belongs to exactly one organization. Queries never return data from another org — scoping is enforced at the SQL level, not application-level filtering. Every JWT carries organization_id for all roles, so permission checks need no additional database lookups.

What's isolated: memories, documents, workspaces, projects, teams (cross-org membership blocked by database triggers), API keys, audit log.

What's shared: graph nodes and triples (structural knowledge like "PostgreSQL is a technology" benefits all orgs), entity dictionary, canonical predicates. The graph is a shared ontology, not tenant data.

Key capabilities:

  • API key rotationPOST /auth/api-keys/{key_id}/rotate issues a new key while the old one enters a configurable grace period (default 24h, max 720h). Both keys work simultaneously. Zero-downtime rotation.
  • Rate limiting — per-user sliding window. 120 req/min general, 60 req/min search. Retry-After and X-RateLimit-* headers on 429 responses.
  • Audit trail — every mutation endpoint writes to audit_log with organization_id. CEOs query their org's audit. Superusers see all.
  • IDOR prevention — auth before fetch, unified error responses. A 403 never reveals whether a resource exists in another org.

For the complete architecture — authentication flow, data isolation model, admin operations, and design decisions — see docs/architecture/multi-tenant.en.md.

Quick Start

git clone https://github.com/josortmel/EcoDB
cd EcoDB
./scripts/setup.sh # generates .env, verifies dependencies
docker compose up --build -d # first boot builds images + downloads models (~35 GB)

On Windows, run the setup step with PowerShell instead of setup.sh:

powershell -ExecutionPolicy Bypass -File scripts\setup.ps1

Monitor first boot (model downloads take time):

docker compose logs -f embeddings ner # wait for "model loaded" / "ready"
docker compose ps # all services should show "healthy"

Generate your API key:

docker exec ecodb-api python bootstrap_first_apikey.py
# Add to .env: ECODB_API_KEY=ecodb_...
docker compose restart mcp

Optional profiles:

docker compose --profile with-ingestion up --build -d # PDF, DOCX, audio ingestion
docker compose --profile with-llm up --build -d # local LLM for classification

Requirements

  • Docker with Compose v2
  • NVIDIA GPU with CUDA drivers
  • ~35 GB disk space

Environment Variables

The setup script (scripts/setup.sh / scripts/setup.ps1) generates .env with all required secrets. For production deployments, set these manually:

VariablePurposeDefault
ECODB_ENVRuntime environment (development/production)development
DATABASE_URLPostgreSQL DSNdev default (localhost:5435)
ECODB_JWT_SECRETJWT signing secretdev-only default — refused in production
ECODB_API_KEY_PEPPERAPI key hash pepperdev-only default — refused in production
ECODB_API_KEYAPI key for MCP server— generate with bootstrap_first_apikey.py
INTERNAL_BROADCAST_SECRETWorker → API broadcast authno default — generate with openssl rand -hex 32
ECODB_CORS_ORIGINSAllowed CORS originshttp://localhost:8080,http://localhost:8091
HF_CACHE_PATHHuggingFace model cache pathnamed volume hf_cache

Production: ECODB_ENV=production activates security validation. The API refuses to start if ECODB_JWT_SECRET or ECODB_API_KEY_PEPPER are missing, too short (< 16 chars), or at their dev defaults.

INTERNAL_BROADCAST_SECRET: required for document ingestion events (--profile with-ingestion). Without it, worker SSE events are silently dropped. If upgrading from v1.1.x or earlier, the old public default (fa8b0c02...) was shipped in docker-compose — rotate it: openssl rand -hex 32 → update .envdocker compose restart api worker.

Verify schema version after upgrade:

docker exec ecodb-postgres psql -U ecodb -d ecodb -c \
"SELECT version FROM schema_version ORDER BY applied_at DESC LIMIT 1;"

Expected: 5.3.0

Documentation

Development

# Tests (requires postgres on port 5435)cd api && python -m pytest tests/ -v
# Type checkcd api && python -m mypy .# Run API locally for debugging
docker compose up postgres embeddings -d
cd api && uvicorn main:app --reload --port 8080

License

PolyForm Noncommercial 1.0.0. Free for personal, educational, and noncommercial use. Commercial deployment requires a separate license from Eco Consulting.

Third-party dependencies: THIRD_PARTY_LICENSES

Maintainers

About

Collective AI memory for multi-agent teams. 10-stage GAMR search engine, knowledge graph (Apache AGE), document ingestion, 32+ MCP tools.

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages