Personal knowledge vault plugin for Claude Code — session recording, memory distillation, and hybrid semantic + BM25 retrieval.
> /plugin marketplace add XBlueSky/cortexes> /plugin install cortex@cortex
FAQ
cortex is a Claude Code plugin with 6 hand-picked skills for productivity work, indexed on Flowy. Install it with the command on its page. It includes cortex-broadcast, cortex-distill, cortex-evolve. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Repo: XBlueSky/cortexes
Cortex turns your working memory into a searchable knowledge base. Every Claude Code session gets automatically recorded when it ends, then can be distilled and retrieved later.
Design philosophy: the vault is the source of truth (plain markdown + git); the vector store is just a rebuildable derived index.
# From GitHub
/plugin marketplace add https://github.com/XBlueSky/cortexes.git#plugin
# cortex-vec ships inside the installed plugin; install from the latest cached version
pip install -e "$(ls -d ~/.claude/plugins/cache/cortex/cortex/*/cortex-vec | sort -V | tail -1)"
Requires the OPENAI_API_KEY environment variable (used for embeddings).
/cortex:genesis /path/to/your/vault
This sets the vault path and author info, and builds the semantic index.
"save to cortex" → manually save knowledge
"check cortex" → semantic search over the vault
"distill" → extract knowledge from Raw/
"broadcast" → fuse new Raw content into existing pages
Live docs and changelog: https://cortexes.pages.dev (Cloudflare Pages,
generated from .cc-marketspec/dist/manifest.json).
See site/README.md for local builds.
| Command | Description |
|---|---|
/cortex:genesis | Initialize the vault — set path, author, rebuild the index |
/cortex:evolve | Manually save knowledge to Notes or Projects (also writes log.md) |
/cortex:distill | Distill Raw/ session records into Notes/Projects (map-first navigation + two-stage evaluation + pending-merge exit) |
/cortex:broadcast | Fuse newly distilled content into related existing pages (llm-wiki-style ingest) |
/cortex:takeoff | Hand-off baton — curate a temporary, non-git hand-off for the next session to resume (resume/done subcommands) |
| Skill | Trigger |
|---|---|
| cortex-evolve | "save to cortex", "note this down", "remember this" |
| cortex-distill | "distill", "clean up raw", "distill raw records" |
| cortex-broadcast | "broadcast", "merge pending-merge", "fuse this into the vault" |
| cortex-takeoff | "hand off", "takeoff", "hand off to next session", "context is running low" |
| cortex-query | "check cortex", "have I noted this before", "is this in cortex" |
| Hook | Event | Behavior |
|---|---|---|
| Session Report | SessionEnd | On session end, filters the transcript through a TOML pipeline before writing to Raw/ |
| Memory Injection | SessionStart | Interactive menu — checks vault backlog status and asks what to do next |
Before writing to Raw/, the SessionEnd hook runs a TOML-driven filter pipeline that
strips tool output with no knowledge value (e.g. ls, volume listings,
repetitive build logs) — you can write custom filters per slash command so
what lands in Raw/ actually carries signal.
cortex repo
├── plugin branch (orphan) ← the Claude Code plugin (this file lives here)
└── main branch ← Obsidian vault data
~/.cortex/
├── config.json ← settings produced by genesis
└── vectorstore/ ← ChromaDB semantic index (local only, not in git)
Raw/YYYY/MM/DD/ ← session dumps (complete, distilled on demand)
Notes/<category>/ ← distilled technical knowledge
Projects/<repo-name>/ ← project notes organized by repo
_index.md ← vault-wide summary index
log.md ← chronological history of evolve/distill
Nothing machine-checks _index.md for consistency (reorganizing pages is the
one path that changes the index with no skill involved). See
docs/index-audit.md for the audit, and for the regex
traps that let a naive check pass while reporting the wrong set.
Every session:
SessionStart → surfaces available memory → user decides whether to load it
...work happens...
session ends → SessionEnd hook → confirmation → Raw/
Anytime:
/cortex:evolve → Notes/Projects + _index.md + log.md + vector store
/cortex:query → vector search → precise file reads
Periodically:
/cortex:distill → Raw → Notes/Projects (+ pending-merge → broadcast)
/cortex:broadcast → pending-merge → fused into existing Notes/Projects
Hybrid retrieval (0.4.0+) — BM25 + vector dual streams, fused with Reciprocal Rank Fusion (RRF, k=60), default weights w_bm25=0.4 / w_vec=0.6:
~/.cortex/bm25/, kept in sync with ChromaDB by
rebuild/upsert/delete.text-embedding-3-small semantic search,
dual-vector (document body + bilingual summary), covering cases that are
semantically close but lexically different.OPENAI_API_KEY, or offline, this
automatically falls back to BM25-only, with no dependency on the
skill-layer grep fallback.Other layers:
The vault's semantic indexing tool, built on ChromaDB + OpenAI
text-embedding-3-small, paired with gpt-5.4-mini to generate a bilingual
summary as a second embedding (dual-vector) to improve recall for mixed
Chinese/English queries.
cortex-vec status # view index status
cortex-vec rebuild # full index rebuild
cortex-vec search "nginx certificate" # semantic search
cortex-vec search "oauth" --repo acme-core # filter by repo
cortex-vec search "sharing" --type project # filter by type
cortex-vec upsert Notes/Nginx/new.md # add/update a single document
cortex-vec delete Notes/Nginx/old.md # delete a document
cortex-vec search now defaults to BM25 + vector RRF hybrid, balancing exact
lexical matches with semantic similarity:
cortex-vec search "nginx certificate" # hybrid (default)
cortex-vec search "nginx certificate" --no-bm25 # vector only (debug/eval)
cortex-vec search "nginx certificate" --no-vector # BM25 only (debug/eval)
cortex-vec status # shows both vector and BM25 entry counts
/cortex:distill drives these read-only commands to walk a Raw without
ever loading the whole file into context. A Raw is parsed once into a
gap-free, overlap-free source partition; raw-span is the only reader that
returns original text, and every page is hard-capped so an oversized session
distills across bounded continuations instead of overflowing context:
cortex-vec distill-queue --root <vault>/Raw --stat # per-Raw projected sizes before a batch
cortex-vec raw-view <raw.md> # budget-bounded L0–L3 projection
cortex-vec distill-plan start <raw.md> # open a coverage/budget plan → plan_id
cortex-vec raw-map <raw.md> --plan-id <id> # navigation cards (kind/size/range/anchors)
cortex-vec raw-span <raw.md> --plan-id <id> --span-id <n> # exact original text, one bounded page
cortex-vec distill-plan status --plan-id <id> # coverage + no-insight gate state
The per-Raw plan lives under $XDG_CACHE_HOME/cortex/distill-plans/ with an
active.json pointer enforcing one active Raw at a time (atomic writes,
user-only permissions, fail-closed on corruption or identity drift).
SessionEnd fires more than once per conversation (/clear, exit + --resume)
and re-filters the same growing transcript each time, so the earlier Raws are
strict prefixes of the latest one. The hook now removes those automatically;
this command is the manual form, and the only way to clean up a backlog
recorded before 1.1.0:
cortex-vec reclaim-superseded --root <vault>/Raw # list the whole queue's duplicates
cortex-vec reclaim-superseded --root <vault>/Raw --apply \
--vault <vault> # remove them (staged with git rm)
Only files in the undistilled queue are candidates — a Raw already carrying a
<!-- distilled: --> marker is never touched — and a candidate must be a
prefix of its survivor, so the failure mode is "duplicate stays", never
"content lost".
# Step 1: have an LLM draft candidate queries; a human reviews and confirms
# gold paths before they can be used
cortex-vec eval propose --queries eval-data/cortex-vault-v1.jsonl
# Step 2: run all adapters, print NDJSON results, and write a markdown scorecard
cortex-vec eval run \
--queries eval-data/cortex-vault-v1.jsonl \
--adapters grep,vector,bm25,hybrid \
--k 5 \
--out docs/benchmarks/$(date +%Y-%m-%d)-cortex-vault-v1.md
Supported adapters: grep / vector / bm25 / hybrid.
Metrics: P@5 / R@5 / MRR / hit.
The four enhancements below are all disabled by default and require explicit
configuration to enable. Always measure the P@5 / R@5 / MRR lift with
cortex-vec eval run before and after enabling any of them, before
deciding what's worth defaulting to on and what should be reverted.
Controlled by config retrieval.synonym_weight (0 = off; try 0.7). The
BM25 stream boosts documents that match a synonym by that weight, so "OAuth"
can match synonyms like "SSO / auth / authorization."
The synonym table lives at cortex-vec/src/cortex_vec/synonyms.py
(common Chinese/English technical terms included) and can be extended.
Enabled via cortex-vec search --graph (or config retrieval.graph: true).
Treats "wikilink neighbors of matched results" as a third RRF stream
fused into the ranking — surfacing notes that are clearly linked from a hit
but don't directly match the query themselves (recovering neighbors that
vector/BM25 alone would miss).
Tunable parameters: retrieval.graph_hops (propagation hops),
retrieval.w_graph (the graph stream's weight in RRF, default 0.3),
retrieval.graph_top_k (how many top hits seed the BFS).
Uses rank-based RRF fusion (not additive boosting), so it's neutral for typical queries and doesn't hurt ranking — it only adds recall for "linked" queries. Measured: no difference on a 20-query general corpus with it on/off; R@5 0.50→0.667 on a wikilink-stress corpus.
Enabled via cortex-vec search --rerank (or config retrieval.rerank: true). Calls OpenAI (model set by retrieval.rerank_model, default
gpt-5.4-mini) to re-rank the top retrieval.rerank_window (default 15)
hybrid results, replacing pure score ranking with LLM relevance judgment. Any
failure (API error / timeout) automatically falls back to the original RRF
order without affecting search availability.
Controlled by config retrieval.max_per_repo (0 = unlimited), caps how
many results from the same repo can appear in the top-k, preventing one
large repo from drowning out results from other sources.
retrieval config exampleThe advanced keys under retrieval in ~/.cortex/config.json and their
defaults:
{
"retrieval": {
"synonym_weight": 0,
"graph": false,
"graph_hops": 1,
"w_graph": 0.3,
"graph_top_k": 5,
"rerank": false,
"rerank_model": "gpt-5.4-mini",
"rerank_window": 15,
"max_per_repo": 0
}
}
Using it with CLI flags:
# Enable graph-boost + rerank (one-off test)
cortex-vec search "OAuth token" --graph --rerank
# Set synonym_weight, then run eval to confirm the lift
cortex-vec eval run \
--queries eval-data/cortex-vault-v1.jsonl \
--adapters hybrid \
--k 5 \
--out docs/benchmarks/$(date +%Y-%m-%d)-synonym-0.7.md
~/.cortex/config.json (generated by genesis):
{
"vault_path": "/path/to/vault",
"author": "tonyhu",
"author_email": "tonyhu@synology.com",
"git": {
"auto_commit": true,
"auto_push": false
}
}
| Variable | Required | Description |
|---|---|---|
OPENAI_API_KEY | No* | OpenAI API key for text-embedding-3-small. Required for rebuild/upsert/vector search; search automatically falls back to BM25-only without it |
CORTEX_VAULT_PATH | No | Overrides vault_path from config.json |
CORTEX_SKIP_RECORD | No | When set (e.g. =1), the SessionEnd hook skips recording this session into Raw/ — for launcher/probe sessions that carry no distill-worthy content |
| Package | Purpose |
|---|---|
| ChromaDB | Semantic vector index |
| OpenAI | text-embedding-3-small embedding model |
| python-frontmatter | YAML frontmatter parsing |
| pysqlite3-binary | SQLite 3.35+ compatibility (needed when the system SQLite is too old) |
Install:
pip install -e ./cortex-vec
commands/ Slash commands (/cortex:*)
skills/ Self-triggering skills
hooks/ SessionStart/SessionEnd lifecycle hooks
cortex-vec/ Python semantic indexing CLI
site/ Static site generator for cortexes.pages.dev
docs/ Design specs, plans, and benchmark reports
scripts/ Dev tooling (e.g. run-checks.sh)
tests/ Plugin-level tests
Contributions are welcome — see CONTRIBUTING.md for dev setup, tests, and the PR process. Please also read the Code of Conduct. Security issues should be reported privately — see SECURITY.md.
See CHANGELOG.md for version history.
Licensed under the Apache License 2.0 — see LICENSE for the
full text.
Copyright 2026 tonyhu (see NOTICE).
.cc-marketspec/
.gitignore
catalog.yaml
entries/
plugin-cortex.yaml
.claude-plugin/
marketplace.json
plugin.json
.github/
ISSUE_TEMPLATE/
bug_report.yml
config.yml
feature_request.yml
PULL_REQUEST_TEMPLATE.md
workflows/
python.yml
site.yml
.gitignore
.pre-commit-config.yaml
CHANGELOG.md
CODE_OF_CONDUCT.md
CODE_OF_CONDUCT.zh-TW.md
commands/
broadcast.md
distill.md
evolve.md
genesis.md
takeoff.md
CONTRIBUTING.md
CONTRIBUTING.zh-TW.md
cortex-vec/
pyproject.toml
src/
cortex_vec/
__init__.py
bm25.py
cli.py
config.py
distill_plan.py
distill_queue.py
eval/
__init__.py
adapters.py
corpus.py
report.py
run.py
score.py
fusion.py
graph.py
parser.py
raw_map.py
raw_page.py
raw_source.py
raw_span.py
raw_view.py
reclaim.py
rerank.py
store.py
synonyms.py
tokenize.py
tests/
conftest.py
test_adapters.py
test_bm25_synonym.py
test_bm25.py
test_cmd_search_flags.py
test_cmd_search.py
test_config_plan2.py
test_config.py
test_corpus.py
test_distill_plan.py
test_distill_queue.py
test_fusion_diversify.py
test_fusion_graph.py
test_fusion_rerank.py
test_fusion_rrf.py
test_fusion_search.py
test_fusion_synonym.py
test_graph_build.py
test_graph_stream.py
test_lockstep.py
test_raw_map.py
test_raw_page.py
test_raw_source.py
test_raw_span.py
test_raw_view.py
test_rebuild_bm25_only.py
test_reclaim.py
test_report.py
test_rerank.py
test_run.py
test_score.py
test_smoke.py
test_synonyms.py
test_tokenize.py
test_vector_stream.py
test_wikilinks.py
docs/
images/
logo.png
index-audit.md
hooks/
hooks.json
scripts/
analyze_bash_volume.py
filter-transcript.py
filters/
ansible-playbook.toml
basedpyright.toml
biome.toml
brew-install.toml
bundle-install.toml
composer-install.toml
df.toml
dotnet-build.toml
du.toml
fail2ban-client.toml
gcc.toml
gcloud.toml
gradle.toml
hadolint.toml
helm.toml
iptables.toml
jira.toml
jj.toml
jq.toml
just.toml
liquibase.toml
make.toml
markdownlint.toml
mise.toml
mix-compile.toml
mix-format.toml
mvn-build.toml
nx.toml
ollama.toml
oxlint.toml
ping.toml
pio-run.toml
poetry-install.toml
pre-commit.toml
ps.toml
quarto-render.toml
rsync.toml
shellcheck.toml
shopify-theme.toml
skopeo.toml
sops.toml
spring-boot.toml
ssh.toml
stat.toml
swift-build.toml
systemctl-status.toml
task.toml
terraform-plan.toml
tofu-fmt.toml
tofu-init.toml
tofu-plan.toml
tofu-validate.toml
trunk-build.toml
turbo.toml
ty.toml
uv-sync.toml
xcodebuild.toml
yadm.toml
yamllint.toml
find_large_bash.py
lib/
repo-slug.sh
log_dedup.py
meta_session.py
rtk_cmd/
__init__.py
cargo.py
dispatch.py
git.py
js_tools.py
lint.py
listing.py
mcp_playwright.py
mcp_tools.py
pytest.py
python_tools.py
rtk_filter.py
session-end-record.sh
session-start-inject.sh
takeoff.sh
LICENSE
NOTICE
package-lock.json
package.json
README.md
README.zh-TW.md
ruff.toml
scripts/
raw-map-corpus-check.py
run-checks.sh
SECURITY.md
SECURITY.zh-TW.md
site/
assets/
fonts/
IBMPlexSans-Medium.woff2
IBMPlexSans-Regular.woff2
JetBrainsMono-Bold.woff2
JetBrainsMono-Regular.woff2
graph.js
hero-spiral.webp
logo.png
style.css
build.mjs
lib/
changelog.mjs
html.mjs
manifest.mjs
README.md
templates/
changelog.mjs
docs.mjs
landing.mjs
tests/
build.test.mjs
changelog-page.test.mjs
changelog.test.mjs
docs.test.mjs
html.test.mjs
landing.test.mjs
manifest.test.mjs
skills/
cortex-broadcast/
SKILL.md
cortex-distill/
SKILL.md
cortex-evolve/
SKILL.md
cortex-query/
SKILL.md
cortex-takeoff/
SKILL.md
using-cortex/
SKILL.md
tests/
test_log_dedup.py
test_meta_session.py
test_rtk_cmd_cargo.py
test_rtk_cmd_dispatch.py
test_rtk_cmd_git.py
test_rtk_cmd_js_tools.py
test_rtk_cmd_lint.py
test_rtk_cmd_listing.py
test_rtk_cmd_mcp_playwright.py
test_rtk_cmd_mcp_tools.py
test_rtk_cmd_pytest.py
test_rtk_cmd_python_tools.py
test_rtk_filter.py
test_session_end_record.py
test_takeoff.py© 2026 Flowy · Free and open source
Built for Claude Code · Not affiliated with Anthropic