1
0
forked from jason/echo
Files
chorus/chorus-memory.plugin.src/README.md
T
jason f2bfd70dd4 Phase 5: group-voice docs, onboarding runbook, CHORUS icon — v2.0.0-rc.1
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>
2026-07-21 15:41:58 -05:00

126 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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**