Skip to main content
Glama

Cortex

Every mind needs a memory that is dynamic, not stationary.

Cortex is a dynamic, governed memory layer for AI agents, assistants, and chatbots, backed by a real Obsidian vault. Humans keep using ordinary Obsidian-compatible Markdown files; AI clients access that same memory only through a secure Model Context Protocol (MCP) server:

  • Obsidian-native — the source of truth is a normal Obsidian vault: Markdown notes, YAML frontmatter, folders, links, and your editor of choice.

  • Account-owned — every vault belongs to a named account. There is no global vault. Requests default to the authenticated account, including administrators; cross-account administration requires explicit selection.

  • Scoped — each token sees only its allowed vaults, note paths, and MCP tools. Out-of-scope resources are invisible, not just unreadable.

  • Audited — every change is a git commit tagged with actor and reason. Git is the single audit trail and rollback mechanism.

  • Deterministic by default — search, reads, and context packs spend zero model tokens. Only the one semantic_search tool calls an LLM.

  • Dedicated memory MCP — only Cortex memory tools, filtered by the token owner's always-on deny-wins policy. No upstream registry or proxy.

  • Self-improving (bounded) — an optional, report-first janitor tidies and watches the vault on a heartbeat, never able to edit its own limits.

Anyone can spin one up — locally, in Docker, or on a homelab — and keep their memory theirs: a fully working Obsidian vault for humans, a governed memory API for agents.

Breaking storage correction: legacy vault.path is no longer served or synced. Read account-vault migration before upgrading an existing installation. No automatic merging or deletion is performed.

See ARCHITECTURE.md for the broader design; the account-vault contract supersedes its historical shared-vault sections.


Quick start

git clone https://github.com/pixlflip/cortex.git && cd cortex
cp cortex.example.yaml cortex.yaml          # edit to taste
# import existing notes into the owning account under ./data/vaults/<username>
docker compose run --rm cortex check        # validate setup
docker compose run --rm cortex init         # DB + admin + git baselines
docker compose up -d                        # headless API + MCP on :8765

Run cortex sync any time (or on a schedule — see docs/bare-metal.md) to snapshot pending human edits into the git audit trail and refresh the search index, so the status tool's freshness numbers stay current.

Bare metal (Debian / Proxmox / laptop)

git clone https://github.com/pixlflip/cortex.git && cd cortex
python3 -m venv .venv && . .venv/bin/activate
pip install .
cp cortex.example.yaml cortex.yaml          # edit to taste
cortex check
cortex init
cortex serve                                # stdio or HTTP, per cortex.yaml

Full host/service setup (service user, systemd) is in docs/bare-metal.md.

Cortex is headless: there is no web app, vault viewer, or admin dashboard. Manage accounts and tokens with the CLI or authenticated JSON API. Readiness is available at /healthz; / and former UI paths return 404. OAuth consent is retained only for MCP client authorization.

Connect an AI once

Create a per-user token with cortex token mint <username> <client-name>, then configure the AI client with Cortex as its memory MCP endpoint:

{
  "mcpServers": {
    "cortex": {
      "url": "https://cortex.example.com/mcp",
      "headers": { "Authorization": "Bearer ctx_…" }
    }
  }
}

Tool discovery is identity-specific and memory-only. Authorization is checked again at call time, including when an old config sets gateway.enabled: false. Upstream tools, search_mcps/peek_mcp/load_mcp, and /api/v1/mcp/* broker routes have been removed. This is an intentional breaking change, not a switch. See memory policy and broker retirement before cutover.

For local stdio clients, register Cortex as a server that runs cortex serve with CORTEX_CONFIG pointing at your config. Built-in tools include:

Tool

What it does

discover_scopes

What can I (this principal) see?

status

Freshness signal: git HEAD/commit time, last index refresh, visible note count

list_notes

List visible note paths

list_files

List visible vault files, including binary attachments

search

Substring/regex search over visible notes

read_note

Read a full note (scope-checked)

get_file

Pull a scoped file in bounded, binary-safe base64 chunks

read_frontmatter

Read a note's YAML frontmatter

read_section

Read one section by heading

context_pack

Compact, budgeted bundle for a query

semantic_search

Fuzzy "comb & synthesize" — the only tool that uses an LLM

The proposed path to genuinely local concept retrieval (hybrid FTS5 plus on-machine embeddings, with optional local synthesis) is documented in docs/local-semantic-search.md. It is a design, not yet part of the shipped configuration surface.

With writes.enabled: true in cortex.yaml (default false — otherwise these tools are not registered at all), the mutating tools appear. Each one requires a reason, is write-scope-checked, and lands as exactly one git commit (always git revert-able):

Tool (gated by writes.enabled)

What it does

write_note

Create a note (or replace one, only with overwrite=True)

put_file

Atomically upload a scoped binary attachment from base64 (8 MiB maximum)

patch_note

Replace a single unique string in an existing note

append_note

Append text to an existing note

update_frontmatter

Merge a patch into a note's YAML frontmatter

set_memory_state

Change lifecycle YAML with a reason and expected file hash

supersede_note

Link an old record to a current replacement, preserving both bodies

delete_note

Delete one note file (committed, so still recoverable)

move_note

Move/rename a note when both paths are writable


Related MCP server: brain

Memory lifecycle

Notes use a fixed memory_state: unreviewed, draft, current, superseded, or disputed. Missing metadata means unreviewed, not verified. Normal recall prefers current records and excludes superseded ones; historical recall is an explicit option. State-only operations preserve note-body bytes. The deterministic janitor reports metadata issues without modifying notes; optional bounded LLM suggestions remain advisory.

See docs/memory-lifecycle.md for tool contracts, authorization, preservation guarantees, and first-iteration limitations.

Configuration

cortex.yaml is public-safe: structure only, no secrets. Tokens and API keys are referenced by env-var name and read at startup. The shipped example runs locally with no API key and the LLM disabled (deterministic tools only).

Key knobs (see cortex.example.yaml):

  • vaults.root — account-owned directories (<root>/<username>).

  • vaults — private-vault root, index directory, templates, archives, sync.

  • principals — static identities, their scopes (path globs), and token_env.

  • database.path — SQLite identity, sessions, memory permissions and telemetry; historical upstream records remain inert for rollback.

  • memory_policy — existing read/write permission defaults and memory audit retention. No authorization-off switch. See the migration compatibility rules.

  • sync.adapter — none (default, local-only) · git · nextcloud · s3.

  • llm.provider — none (default) · openrouter · openai · anthropic · ollama. OpenRouter (one key, many models; defaulting to the latest Claude Sonnet) is the recommended way to enable semantic_search.

  • janitor — off by default; report-only before any write mode.

Run one bounded report pass across account vaults with cortex janitor --force (or omit --force when janitor.enabled is true). Reports are stored in SQLite and available through the authenticated API; the current worker never modifies vault content.


What v2 includes

  • Local accounts, LDAP/Active Directory login and sync, groups, sessions, CSRF-protected same-origin API, and individually revocable user tokens.

  • One git-audited vault per account, explicit cross-account administration, lifecycle repair/archive operations, and token-level path narrowing. There is no general or shared default vault.

  • Headless JSON API and MCP access, with scope-checked notes and attachments. The React UI, static assets, and legacy browser admin have been removed.

  • Memory-only per-user/group tool permissions, deny-wins behavior (including admins), listing/call parity, and argument-shape-only call telemetry.

  • Reproducible Docker/Compose and Python-wheel packaging, a v1→v2 migration command, health checks, CI, and documented backup/upgrade procedures.

Start with docs/multi-user.md, docs/memory-policy.md, and account-vault migration. The original v2 upgrade and security review are historical.


Development

pip install -e ".[dev]"
pytest

License

Apache-2.0 — see LICENSE.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    A self-hosted MCP server that gives AI agents shared, long-term memory over a git-backed folder of markdown, enabling persistent knowledge search, read, and write without a database.
    16
    13 npm
    16
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A personal memory engine and MCP server that stores durable facts in markdown files managed via git, enabling hybrid search (lexical + semantic) through an MCP interface for persistent context across LLM sessions.
    3
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that provides agentic memory management for markdown vaults, enabling hybrid search, governed writing, and maintenance of episodic, semantic, procedural, and working memories for LLM agents.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for managing a local, domain-agnostic knowledge base using Markdown notes with frontmatter. Enables AI agents to capture, read, search, link, and maintain notes with atomic writes and privacy controls.
    13
    MIT