Cortex – Agent-Native Knowledge OS on Markdown (Karpathy's LLM Wiki, via MCP)
PULSE8.ai Cortex is an agent-native knowledge OS built on Markdown, providing a shared vault for AI agents and humans with a typed knowledge graph, full-text search, and a MarkItDown-powered compiler, all accessible via a unified MCP interface. Inspired by Andrej Karpathy's LLM Wiki pattern, it requires no database.
Notifications You must be signed in to change notification settings
Fork 1
Star 5
BranchesTags
Open more actions menu
Folders and files
NameName
Last commit message
Last commit date
Latest commit
History
206 Commits
206 Commits
.cursor/skills
.cursor/skills
.github/workflows
.github/workflows
assets
assets
cortex
cortex
docker/qmd
docker/qmd
docs
docs
example_vault
example_vault
roadmap
roadmap
scripts
scripts
tests
tests
.env.example
.env.example
.gitignore
.gitignore
AGENTS.md
AGENTS.md
CHANGELOG.md
CHANGELOG.md
Dockerfile
Dockerfile
LICENSE.md
LICENSE.md
README.md
README.md
claude_desktop_config.example.json
claude_desktop_config.example.json
development_plan.md
development_plan.md
docker-compose.cortex-only.yml
docker-compose.cortex-only.yml
docker-compose.gpu.yml
docker-compose.gpu.yml
docker-compose.yml
docker-compose.yml
pyproject.toml
pyproject.toml
server.json
server.json
uv.lock
uv.lock
Repository files navigation
Agent-native knowledge OS built on Markdown
PULSE8.ai Cortex is an agent-native knowledge OS built on Markdown. It gives AI agents and humans a shared vault backed by a typed knowledge graph, full-text search, and a MarkItDown-powered compiler — all accessible through a unified MCP interface.
Drop files in (PDF, DOCX, PPTX, XLSX, HTML, images, and more), let agents read, write, search, link, and compile knowledge — no database required.
Inspired by Andrej Karpathy's LLM Wiki pattern — a persistent, compounding knowledge base maintained by LLMs instead of re-derived on every query. Search powered by Tobi Lütke's QMD.
Get started
Note
PULSE8.ai Cortex requires Docker. An OpenRouter API key is optional — needed only for LLM-powered cross-referencing between wiki articles. File conversion works out of the box without any API key.
Clone the repository:
git clone https://github.com/synpulse8-opensource/pulse8-ai-cortex-knowledge-vault.git cd cortex-knowledge-vault
Launch PULSE8.ai Cortex:
./scripts/start.sh
This builds and starts both PULSE8.ai Cortex (API + MCP on :8420) and QMD (search on :3100), waits for health checks, and you're ready to go.
Connect your MCP client (e.g. Claude Desktop) to http://localhost:8420/mcp/.
To stop: ./scripts/stop.sh
Cortex-only mode (macOS / native QMD)
If you want QMD to run natively (e.g. on macOS with Metal GPU acceleration), start only the Cortex container:
Terminal 1: Run QMD natively
npm install -g @tobilu/qmd VAULT_PATH=./example_vault node docker/qmd/server.mjs
Terminal 2: Start only Cortex in Docker
./scripts/start.sh --cortex-only
To stop: ./scripts/stop.sh --cortex-only
GPU-accelerated QMD (EC2 / Linux with NVIDIA GPU)
For production deployments with NVIDIA GPU acceleration:
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up --build -d
See docs/ec2-gpu-setup.md for a full guide on instance selection, NVIDIA toolkit installation, and cost estimates.
Features
Knowledge Graph Typed graph engine (NetworkX) — wikilinks, tags, and custom edges, auto-maintained on every file change
Full-Text Search QMD search with hybrid (BM25 + vector + re-ranking) by default; keyword and semantic modes selectable. Results cached with a configurable TTL.
File Compiler Converts raw sources (PDF, DOCX, PPTX, XLSX, HTML, images, etc.) to Markdown via MarkItDown. LLM used only for cross-referencing.
MCP Server Streamable HTTP + stdio transport — works with Claude Desktop, Cursor, and any MCP client
Feedback & Notifications vault_feedback captures quality feedback as notes; optional Microsoft Teams webhook posts an adaptive card per submission
Daily Activity Log Every write/ingest/compile is mirrored into daily/.md as a greppable, wikilinked timeline
Bulk Ingest Ingest dozens or hundreds of files at once from a local directory with SHA-256 dedup and bounded concurrency
REST API FastAPI endpoints mirroring all MCP tools at /api/v1/, including multipart file upload and bulk ingest
Vault Watcher Real-time filesystem monitoring — graph stays in sync automatically
Zero Database Everything persists as Markdown + JSON on your filesystem
MCP tools
Tool Description
vault_read Read a note by path
vault_write Create or update a note
vault_search Search the vault (keyword / semantic / hybrid)
vault_link Create, query, or delete graph edges
vault_context Build a context window: search → graph traversal → ranked subgraph
vault_ingest Ingest raw content or binary files (supports content_base64 for binary)
vault_compile Compile unprocessed raw sources into wiki Markdown via MarkItDown
vault_feedback Submit feedback on vault quality (status: OPEN; optional related_paths of .md notes)
vault_list_feedbacks List feedback note metadata (paths, tags, status; not full body)
Architecture
┌──────────────────────────────────────────────┐ │ MCP Client (Claude Desktop, Cursor, etc.) │ └──────────┬───────────────────────────────────┘ │ MCP (HTTP or stdio) ┌──────────▼───────────────────────────────────┐ │ PULSE8.ai Cortex :8420 │ │ ┌──────────────────────────────────────┐ │ │ │ Auth (API Key or Microsoft Entra ID) │ │ │ └──────────────┬───────────────────────┘ │ │ ┌─────────┐ ┌──┴───────┐ ┌──────────────┐ │ │ │ MCP │ │ REST API │ │ Vault Watcher│ │ │ │ /mcp/ │ │ /api/v1/ │ │ (watchfiles) │ │ │ └────┬────┘ └────┬─────┘ └──────┬───────┘ │ │ └───────────┼──────────────┘ │ │ ┌──────▼──────┐ │ │ │ Graph Engine│ │ │ │ + Compiler │ │ │ └─────────────┘ │ └──────────┬───────────────────────────────────┘ │ ┌──────────▼───────────────────────────────────┐ │ QMD :3100 │ │ BM25 + vector search, auto-indexes on start │ └──────────┬───────────────────────────────────┘ │ ┌──────────▼───────────────────────────────────┐ │ Vault (bind-mounted volume) │ │ wiki/ raw/ agents/ sessions/ daily/ feedback/ │ │ .cortex/ (graph.json, index.md, log.md) │ └──────────────────────────────────────────────┘
Vault layout
The vault is a plain directory of Markdown files organised by purpose. Cortex classifies each file into a typed node (NodeType) used by the graph engine and exposed in REST and MCP responses.
Folder NodeType Purpose
wiki/ note Compiled, interlinked knowledge articles
raw/ raw_source Unprocessed sources (PDF, DOCX, TXT, …) the compiler reads from
agents/ agent_def Agent definitions
sessions/ session Per-session notes / conversation transcripts
daily/ daily Daily notes (Obsidian Daily Notes convention)
feedback/ feedback Feedback on vault quality (status, related_paths)
.cortex/ (skipped) Cortex internals — graph.json, index.md, log.md, manifests
How classification works
Order of precedence (first match wins):
*Frontmatter type:* — explicit override always wins (e.g. type: note in agents/foo.md resolves to NodeType.NOTE)
Folder prefix — files under raw/ agents/ sessions/ daily/ feedback/ inherit the folder's type with no filename suffix needed (e.g. daily/2026-06-10.md → daily)
Filename suffix (backward-compatible) — .agent.md, .session.md, .memory.md are still honored anywhere (e.g. wiki/legacy.agent.md → agent_def)
Default — NodeType.NOTE
In practice this means you can drop YYYY-MM-DD.md straight into daily/, or an unsuffixed planner.md into agents/, and the graph and API will classify them correctly without any renaming.
Daily activity log
Every vault_write, vault_ingest, and successful compile event (MCP and REST paths) is automatically mirrored into today's UTC daily note at daily/YYYY-MM-DD.md. The file is created on first event of the day and each subsequent event appends a ## [HH:MM] event | summary block plus a [[wiki-stem]] wikilink (so the watcher draws a LINKS_TO edge to the affected note). The format follows the Karpathy log.md greppable-prefix pattern — grep "^## \[" daily/2026-06-10.md gives a clean timeline of the day.
Writes targeting daily/, feedback/, or .cortex/ are deliberately not mirrored (would be self-referential noise). The hidden .cortex/log.md audit log is unaffected and continues to receive every operation.
Bulk ingest
For ingesting many files at once (dozens or hundreds of PDFs, papers, docs), use the one-click shell script instead of feeding them one at a time through MCP. It reads directly from a local directory — no wire overhead, no running server required — deduplicates via SHA-256 hashing, compiles with bounded concurrency, and rebuilds the index once at the end.
One-click script (recommended)
Ingest all files from a directory
./scripts/bulk_ingest.sh ./my-papers/
Dry-run to preview what would be ingested
./scripts/bulk_ingest.sh ./my-papers/ --dry-run
Force re-ingest (bypass dedup manifest)
./scripts/bulk_ingest.sh ./my-papers/ --force
Control LLM concurrency (default: 4)
./scripts/bulk_ingest.sh ./my-papers/ --concurrency 8
The script automatically loads your .env for the LLM key and vault path, prints a summary, then runs the full pipeline (copy, compile, reindex). No running Cortex server needed.
Python CLI (direct)
CORTEX_VAULT_PATH=./example_vault uv run cortex-bulk-ingest --source ./my-papers/
Inside Docker
Set INGEST_DIR in .env or export it, then restart
export INGEST_DIR=/path/to/your/papers docker compose up -d
Run bulk ingest inside the container
docker exec pulse8-ai-cortex uv run cortex-bulk-ingest --source /ingest
Via REST API
For programmatic use without MCP (requires running Cortex server):
curl -X POST http://localhost:8420/api/v1/bulk-ingest \ -H "Content-Type: application/json" \ -H "x-api-key: your-secret-api-key" \ -d '{"source_dir": "/ingest", "concurrency": 4}'
Deduplication
The dedup manifest is stored at .cortex/ingest-manifest.json. Files are matched by content hash, not filename — renaming a file won't cause re-ingestion, and the same content under a different name will be skipped.
Configuration
Copy the example and fill in your values:
cp .env.example .env
Variable Required Default Description
LLM_API_KEY No — OpenRouter (or compatible) API key (for cross-referencing only)
COMPILER_MODEL No anthropic/claude-sonnet-4 Model for cross-reference detection
LLM_BASE_URL No https://openrouter.ai/api/v1 LLM API base URL
VAULT_DIR No ./example_vault Path to your vault directory
INGEST_DIR No ./ingest Path to bulk-ingest source directory (mounted as /ingest in Docker)
QMD_REFRESH_INTERVAL_SECONDS No 900 Periodic re-index interval (seconds; 0 to disable)
QMD_SEARCH_MODE No hybrid Default search mode when unspecified: hybrid (BM25 + vector + re-rank), semantic, or keyword
QMD_CACHE_TTL_SECONDS No 30 TTL for the search-result cache; raise it on read-heavy vaults to skip repeat QMD calls
QMD_SEARCH_TIMEOUT_SECONDS No 120 Per-request search timeout (increase for hybrid on CPU-only hosts)
QMD_EMBED_TIMEOUT_MS No 600000 Embed timeout in ms (increase for CPU-only deployments)
QMD_URL No — External QMD URL for cortex-only mode (e.g. http://host.docker.internal:3100)
AUTH_METHOD No none Authentication method: none, apikey, or oidc (see Authentication)
API_KEY No — Static API key for x-api-key header (used when AUTH_METHOD=apikey)
OIDC_TENANT_ID No — Microsoft Entra ID tenant ID (used when AUTH_METHOD=oidc)
OIDC_CLIENT_ID No — Microsoft Entra ID app (client) ID
OIDC_CLIENT_SECRET No — Microsoft Entra ID client secret
OIDC_BASE_URL No http://localhost:8420 Public base URL of the Cortex server (used for OAuth callbacks)
TEAMS_WEBHOOK_URL No — Incoming webhook / Power Automate URL; posts an adaptive card on each new feedback note
TEAMS_APP_BASE_URL No — Optional public Cortex base URL for a "View in Cortex" link on the Teams card
OPENROUTER_API_KEY and CORTEX_LLM_API_KEY are accepted as aliases for LLM_API_KEY. Variables above are set in .env (Docker reads them via Compose) and map to the CORTEX_* settings used by the app.
Authentication
Cortex support
[truncated for AI cost control]