Persistent memory for Claude via the **CHORUS** Obsidian vault, using the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api).
Reads and writes notes across Claude/CoWork sessions through direct REST calls, routed through a bundled validated client (`scripts/chorus.py`) that status-checks every write. The toolchain is **pure Python**, so it runs identically on Windows, macOS, and Linux (only a Python 3 interpreter is needed — no bash). The plugin is **user-agnostic**: the vault owner, endpoint, and API key are not shipped in it — each machine supplies them through a local config file (see **Configuration**).
**The plugin is the single source of truth.** All control logic — bootstrap/repair, operating contract, taxonomy, frontmatter conventions, and the canonical note templates — ships inside this plugin under `skills/chorus-memory/`. The vault itself holds **data only**: there are no `CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md` control docs in it. This makes CHORUS self-bootstrapping (point it at an empty Obsidian vault and it stands up the full structure), easy to update (update the plugin, not the vault), and portable to any other vault.
- **One-call `capture`** routes a memory to its canonical home, stamps **complete** frontmatter (kind-default `status`, kind-seeded `tags`), indexes it, auto-links any entity it mentions, and logs it — driven by a machine-maintained **entity index** so routing is an alias-aware lookup, not a fuzzy search. Updates keep the **whole body**; a title that strongly resembles an existing entity **stops at a duplicate gate** (exit 76 — `--merge-into <slug>` / `--force`) instead of spawning a near-duplicate
- **`recall`** returns a topic's matching notes *and* their one-hop linked neighbourhood (Related links + `source_notes`) — the corpus spans the entity graph **plus session logs and journal notes** (down-weighted), ranked by BM25 × freshness × status so live notes outrank stale ones; **`resolve`** maps any mention to its canonical path; **`link`** adds reciprocal cross-links; **`triage`** routes aging inbox captures with an automatic processing-log audit trail
- **Bootstraps an empty vault from the bundled `scaffold/`** (folders, templates, anchor seeds, marker), repairs/migrates an existing one via `scripts/bootstrap.py` / `scripts/migrate.py`, and brings an upgraded vault up to spec (index + cross-links) via `scripts/sweep.py` — see `skills/chorus-memory/references/bootstrap.md`
- Exposes `/chorus-load`, `/chorus-save`, `/chorus-recall`, `/chorus-triage`, `/chorus-health`, `/chorus-sweep`, `/chorus-reflect`, `/chorus-doctor` slash commands as explicit entry points, and coordinates concurrent Claude/CoWork sessions via a cooperative advisory lock
- **Ships session hooks** (`hooks/hooks.json`): SessionStart auto-runs the cold-start load into context, and Stop nudges `/chorus-reflect` once per substantive session — the load/reflect discipline fires deterministically instead of depending on the model remembering (reflection still previews before writing)
Per field, an environment variable overrides the file: `CHORUS_OWNER`, `CHORUS_BASE` (endpoint), `CHORUS_KEY`. `config init` writes the template (shown above) when the file is absent; a copy also ships at the repo root (`chorus-memory.config.template.json`). The config is **never committed** and **never written into a vault note**; the bearer key stays out of the plugin tree entirely.
| `chorus-memory` | "remember that", "save to memory", "what do you know about me", "load my profile", "check my notes", "log this decision", "add to my inbox" — and proactively at the start of substantive conversations |