forked from jason/echo
f2bfd70dd4
The final phase of CHORUS-PLAN.md. Code- and doc-complete for group use; rc pends live deployment at chorusapi.mpm.to. - Repo README rewritten for CHORUS: group model (schema 5), concurrency posture, configuration, baked-build onboarding, layout, testing, 2.0 version history (ECHO history referenced at the fork tag). - Operator→member voice sweep across SKILL.md (incl. the trigger description, now group-aware), all references, 8 command docs, plugin README; member preferences / semantic layer / triage guidance describe the group model. - docs/ONBOARDING.md: member runbook — vault stand-up, per-member config, bake, deliver, self-onboarding first load, norms, offboarding. - docs/USAGE.md rewritten as the member usage guide. - New icon: chorus-icon.svg + 1024/512/64 PNGs (three voices, one center). - Removed ECHO-era assets (icons, spec PDF, perf briefs); ECHO planning docs retired to docs/history/. All preserved at echo-fork-point. - eval/README documents test_multimember.py. Manifest -> 2.0.0-rc.1; rebuilt chorus-memory.plugin. Verified: routing-sync, 25/25 unit, scaffold, 5 mock e2e suites, run_eval metrics green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
126 lines
10 KiB
Markdown
126 lines
10 KiB
Markdown
# chorus-memory
|
||
|
||
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 **group-agnostic**: the group, member id, endpoint, and API key are not shipped in it — each machine supplies them through a local config file (see **Configuration**).
|
||
|
||
Architected by **Jason Stedwell**.
|
||
|
||
**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.
|
||
|
||
## What it does
|
||
|
||
- Loads the group profile, your member preferences, current context, and relevant project notes at the start of substantive conversations
|
||
- **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
|
||
- Logs working sessions so future conversations can pick up where they left off
|
||
- **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)
|
||
|
||
## Configuration
|
||
|
||
The plugin ships **no** group, member, endpoint, or key. On each machine it installs on, provide a machine-local JSON config:
|
||
|
||
```
|
||
~/.claude/chorus-memory/config.json (honors $CLAUDE_CONFIG_DIR; file path overridable with $CHORUS_CONFIG)
|
||
{
|
||
"group": "Group Name — the team/group sharing this vault",
|
||
"member": "<your-member-id — kebab-case slug, e.g. jason>",
|
||
"endpoint": "https://your-obsidian-rest-endpoint.example.com",
|
||
"key": "<obsidian-local-rest-api-bearer-token>"
|
||
}
|
||
```
|
||
|
||
`member` is **required** — it is stamped as `author:` on every agent write, so the shared vault always knows which member's session wrote what.
|
||
|
||
Set it up on a fresh install by copying the bundled template and filling it in, or via the client:
|
||
|
||
```bash
|
||
python3 skills/chorus-memory/scripts/chorus.py config init # writes the template if absent → edit it
|
||
python3 skills/chorus-memory/scripts/chorus.py config set --group "…" --member "your-id" --endpoint "https://…" --key "…"
|
||
python3 skills/chorus-memory/scripts/chorus.py config # show resolved config (key redacted) + source
|
||
```
|
||
|
||
Per field, an environment variable overrides the file: `CHORUS_GROUP`, `CHORUS_MEMBER`, `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.
|
||
|
||
## Vault layout (root-addressed)
|
||
|
||
```
|
||
/vault/
|
||
├── README.md ← thin human signpost (not read for routing)
|
||
├── inbox/ (captures, imports, processing-log)
|
||
├── journal/ (daily, weekly, monthly, quarterly, annual, templates) — one time-series stream; rollups live here, not in a separate reviews/ tree
|
||
├── projects/ (active, incubating, on-hold, archived)
|
||
├── areas/ (business, personal, learning, systems)
|
||
├── resources/ (companies, concepts, references, people, meetings)
|
||
├── decisions/ (by-date)
|
||
└── _agent/
|
||
├── chorus-vault.md ← bootstrap marker (schema_version + date)
|
||
├── context/ ← task-scoped context bundles
|
||
├── memory/ ← working / episodic / semantic
|
||
├── sessions/ ← YYYY-MM-DD-HHMM-<slug>.md
|
||
├── health/ ← YYYY-MM-vault-health.md (monthly self-maintenance audit)
|
||
├── templates/ ← canonical note templates (seeded from the plugin's scaffold/)
|
||
├── skills/ ← active / archived
|
||
├── heartbeat/ ← last-session.md orientation pointer (read at load, written at session end)
|
||
├── index/ ← entities.json — machine-maintained slug→{path,kind,aliases} registry
|
||
└── locks/ ← vault.lock — cooperative advisory multi-writer lock
|
||
```
|
||
|
||
Control logic and the master scaffold live in the plugin, not the vault:
|
||
|
||
```
|
||
commands/ ← slash commands: chorus-load, chorus-save, chorus-recall, chorus-triage, chorus-health, chorus-sweep, chorus-reflect, chorus-doctor
|
||
skills/chorus-memory/
|
||
├── SKILL.md ← operating procedure (authoritative)
|
||
├── references/
|
||
│ ├── operating-contract.md ← durable principles + safety + concurrency
|
||
│ ├── bootstrap.md ← bootstrap / repair / migrate an empty vault
|
||
│ ├── vault-layout.md ← canonical layout + frontmatter
|
||
│ ├── routing-map.md ← complete endpoint→logic map (human authority)
|
||
│ ├── api-reference.md ← REST endpoint patterns + routing map
|
||
│ └── session-log-template.md
|
||
├── scripts/ ← pure Python; run with python3 (Windows: python / py -3)
|
||
│ ├── chorus.py ← validated client + high-level CLI (capture/resolve/recall/link/load/scope/lock/config)
|
||
│ ├── chorus_config.py ← resolves group/member/endpoint/key from the machine-local config (env-overridable)
|
||
│ ├── chorus_index.py ← entity index (registry, resolve, name→path map)
|
||
│ ├── chorus_links.py ← cross-link primitives (Related parsing, bidirectional linking)
|
||
│ ├── chorus_ops.py ← high-level ops (capture, recall, resolve, link, agent-log)
|
||
│ ├── routing.json ← canonical machine-readable route manifest (linter enforces it)
|
||
│ ├── vault_lint.py ← read-only invariant + graph-health checker (Vault Health)
|
||
│ ├── check_routing.py ← verifies routing docs stay in sync with routing.json (offline)
|
||
│ ├── test_chorus_client.py ← offline regression tests + the routing-sync guard
|
||
│ ├── bootstrap.py ← deterministic, idempotent vault setup/repair
|
||
│ ├── migrate.py ← deterministic schema migration (dry-run by default)
|
||
│ └── sweep.py ← bring an upgraded vault up to spec (build index + symmetrize links)
|
||
└── scaffold/ ← verbatim files the bootstrap writes into the vault
|
||
├── README.vault.md chorus-vault.md
|
||
├── templates/ (8 note templates)
|
||
└── anchors/ (group-profile, group-inbox + member preferences/context/inbox seeds)
|
||
```
|
||
|
||
## Skills & commands
|
||
|
||
| Skill | Triggers |
|
||
|-------|----------|
|
||
| `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 |
|
||
|
||
| Command | Does |
|
||
|---------|------|
|
||
| `/chorus-load` | Cold-start context read (profile, scope, latest session, today, inbox) |
|
||
| `/chorus-save <text>` | Route + persist via one-call `capture` (index-resolved, auto-linked) |
|
||
| `/chorus-recall <query>` | Recall a topic's matching notes plus their linked neighbourhood |
|
||
| `/chorus-triage` | Drain aging inbox captures to their homes, logging each move |
|
||
| `/chorus-health` | Run `vault_lint.py` and summarize invariant + graph-health violations |
|
||
| `/chorus-sweep` | Bring the vault up to current spec (build index + symmetrize links) |
|
||
| `/chorus-reflect` | Extract durable items from the session, preview, and apply on approval |
|
||
| `/chorus-doctor` | Readiness check: config, endpoint reachability, auth, bootstrap/schema |
|
||
|
||
## Requirements
|
||
|
||
- **Python 3** available in the session environment (the scripts use only the standard library; invoke as `python3`, or `python` / `py -3` on Windows)
|
||
- Obsidian running on the backend with the [Local REST API plugin](https://github.com/coddingtonbear/obsidian-local-rest-api) enabled
|
||
- HTTPS access from the Claude/CoWork session environment to the endpoint configured in `~/.claude/chorus-memory/config.json`
|
||
- A machine-local config (`~/.claude/chorus-memory/config.json`) supplying the group, member id, endpoint, and API key — see **Configuration**
|