# echo-memory

Persistent memory for Claude via the **ECHO** 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/echo.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). Built for **Jason Stedwell** (Director of Technical Services / Systems Engineer, MPM / ALABAMA wISP), who is both the operator and the architect of this vault.

**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/echo-memory/`. The vault itself holds **data only**: there are no `CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md` control docs in it. This makes ECHO 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 operator preferences, current context, and relevant project notes at the start of substantive conversations
- **One-call `capture`** routes a memory to its canonical home, stamps frontmatter, 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
- **`recall`** returns a topic's matching notes *and* their one-hop linked neighbourhood (Related links + `source_notes`) for comprehensive context; **`resolve`** maps any mention to its canonical path; **`link`** adds reciprocal cross-links
- 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/echo-memory/references/bootstrap.md`
- Exposes `/echo-load`, `/echo-save`, `/echo-recall`, `/echo-triage`, `/echo-health`, `/echo-sweep` slash commands as explicit entry points, and coordinates concurrent Claude/CoWork sessions via a cooperative advisory lock

## Configuration

The plugin is hardcoded for:

- **Server:** `https://echoapi.alwisp.com` (reverse proxy → backend Obsidian Local REST API)
- **API Key:** stored in the skill (personal plugin, not for distribution)

The endpoint presents a **valid TLS certificate**, so `-k` is not required. The bearer key lives only in the plugin — never inside the vault (per the vault's own safety rules).

## 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/
    ├── echo-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: echo-load, echo-save, echo-recall, echo-triage, echo-health, echo-sweep
skills/echo-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)
│   ├── echo.py                    ← validated client + high-level CLI (capture/resolve/recall/link/load/scope/lock)
│   ├── echo_index.py              ← entity index (registry, resolve, name→path map)
│   ├── echo_links.py              ← cross-link primitives (Related parsing, bidirectional linking)
│   ├── echo_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_echo_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  echo-vault.md
    ├── templates/  (8 note templates)
    └── anchors/    (operator-preferences, current-context, inbox seeds)
```

## Skills & commands

| Skill | Triggers |
|-------|----------|
| `echo-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 |
|---------|------|
| `/echo-load` | Cold-start context read (profile, scope, latest session, today, inbox) |
| `/echo-save <text>` | Route + persist via one-call `capture` (index-resolved, auto-linked) |
| `/echo-recall <query>` | Recall a topic's matching notes plus their linked neighbourhood |
| `/echo-triage` | Drain aging inbox captures to their homes, logging each move |
| `/echo-health` | Run `vault_lint.py` and summarize invariant + graph-health violations |
| `/echo-sweep` | Bring the vault up to current spec (build index + symmetrize links) |

## 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 to `https://echoapi.alwisp.com` from the Claude/CoWork session environment
