ver 0.9
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# echo-memory — v0.7.1
|
||||
# echo-memory — v0.9.0
|
||||
|
||||
Persistent memory for Claude / CoWork sessions via the **ECHO** Obsidian vault, driven over the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api). No MCP server — the skill makes direct REST calls, now through a bundled validated client (`scripts/echo.sh`).
|
||||
Persistent memory for Claude / CoWork sessions via the **ECHO** Obsidian vault, driven over the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api). No MCP server — the skill makes direct REST calls, now through a bundled validated client (`scripts/echo.py`). The whole toolchain is **pure Python** (stdlib only), so it runs identically on Windows, macOS, and Linux — no bash, no platform-specific `date`.
|
||||
|
||||
Built for **Jason Stedwell** (Director of Technical Services / Systems Engineer, MPM / ALABAMA wISP), who is both the **operator** and the **architect** of this vault. This is a personal plugin, not for distribution.
|
||||
|
||||
@@ -29,15 +29,16 @@ Three consequences follow:
|
||||
The plugin is hardcoded for a single personal endpoint:
|
||||
|
||||
- **Server:** `https://echoapi.alwisp.com` (reverse proxy → backend Obsidian Local REST API). This is the **only** valid endpoint — never use LAN addresses (`10.x`, `192.168.x`, `:27124`); those belong to retired memory systems. Override per-run with `ECHO_BASE`.
|
||||
- **Auth:** a bearer token stored in the skill / `references` and injected by `scripts/echo.sh`. The key lives only in the plugin — **never inside a vault note** (per the vault's own safety rules). Override with `ECHO_KEY`.
|
||||
- **Auth:** a bearer token stored in the skill / `references` and injected by `scripts/echo.py`. The key lives only in the plugin — **never inside a vault note** (per the vault's own safety rules). Override with `ECHO_KEY`.
|
||||
- **TLS:** the endpoint presents a valid certificate, so `-k` is not needed.
|
||||
|
||||
Vault paths are addressed **at the root** (e.g. `GET /vault/_agent/context/current-context.md`). Prefer `scripts/echo.sh` over raw `curl`: it injects auth, checks HTTP status (a failed write exits non-zero instead of looking like success), retries transient 5xx, verifies PUTs, and does idempotent appends.
|
||||
Vault paths are addressed **at the root** (e.g. `GET /vault/_agent/context/current-context.md`). Prefer `scripts/echo.py` over raw `curl`: it injects auth, checks HTTP status (a failed write exits non-zero instead of looking like success), retries transient 5xx, verifies PUTs, and does idempotent appends.
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Python 3** in the session environment (stdlib only; invoke as `python3`, or `python` / `py -3` on Windows).
|
||||
- Obsidian running on the backend with the Local REST API plugin enabled.
|
||||
- HTTPS reachability to `https://echoapi.alwisp.com` from the Claude / CoWork session environment.
|
||||
|
||||
@@ -51,7 +52,7 @@ echo-v.05/
|
||||
├── echo-memory-<version>.plugin ← versioned build artifacts (history)
|
||||
├── eval/ ← credential-free A/B eval harness (0.6 vs 0.7); not bundled
|
||||
│ ├── mock_olrapi.py ← deterministic mock of the REST API + fault injection
|
||||
│ ├── run_eval.py ← orchestrator (runs the real echo.sh vs modeled raw curl)
|
||||
│ ├── run_eval.py ← orchestrator (runs the real echo.py vs modeled raw curl)
|
||||
│ └── README.md
|
||||
└── echo-memory.plugin.src/ ← tracked source tree (the plugin)
|
||||
├── .claude-plugin/plugin.json ← manifest (name, version, description)
|
||||
@@ -66,12 +67,18 @@ echo-v.05/
|
||||
│ ├── routing-map.md ← complete endpoint→logic routing map (human authority)
|
||||
│ ├── api-reference.md ← REST endpoint patterns + routing map
|
||||
│ └── session-log-template.md
|
||||
├── scripts/ ← executable logic (NEW in 0.7)
|
||||
│ ├── echo.sh ← validated API client (auth, status-check, retry, verify, lock)
|
||||
├── scripts/ ← executable logic — pure Python (run: python3, or 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.sh ← read-only invariant checker (Vault Health)
|
||||
│ ├── bootstrap.sh ← deterministic, idempotent vault setup/repair
|
||||
│ └── migrate.sh ← deterministic schema migration (dry-run by default)
|
||||
│ ├── 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
|
||||
├── echo-vault.md ← bootstrap marker
|
||||
├── README.vault.md ← thin human signpost
|
||||
@@ -83,25 +90,30 @@ echo-v.05/
|
||||
|
||||
---
|
||||
|
||||
## Bundled tooling (0.7)
|
||||
## Bundled tooling
|
||||
|
||||
Executable logic ships under `skills/echo-memory/scripts/`; the agent prefers it over hand-built curl.
|
||||
Executable logic ships under `skills/echo-memory/scripts/`; the agent prefers it over hand-built curl. Everything is **pure Python** (stdlib only) — invoke with `python3` (Windows: `python` / `py -3`).
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `echo.sh` | The validated API client. `get/ls/map/search/put/post/append/patch/fm/bump/delete/lock/unlock/scope`. Injects auth, **checks HTTP status** (non-zero exit on ≥400 — a failed write can't masquerade as success), one bounded retry on transient 5xx/connection errors, read-back verify on PUT, idempotent `append` (read-before-POST), correct `::` heading targets. `scope show` reports the active scope + its freshness; `scope set "<text>"` switches it atomically (archive prior → replace → stamp `scope_updated`). |
|
||||
| `routing.json` | The **canonical machine-readable** route manifest — one regex pattern per valid destination plus retired paths. The single source of truth for "what may be written where"; `vault-lint.sh` enforces it. |
|
||||
| `vault-lint.sh` | Read-only invariant checker (Vault Health). Real YAML parsing, clock injected via `ECHO_TODAY`, exits `3` if the vault isn't bootstrapped (instead of falsely reporting "clean"). Includes a **scope-drift** check (flags when ≥ `SCOPE_STALE_SESSIONS` session logs postdate `scope_updated`). |
|
||||
| `bootstrap.sh` | Deterministic, idempotent, probe-before-write vault setup/repair (`--dry-run` to preview). Resolves the scaffold relative to itself, so it works from any CWD. |
|
||||
| `migrate.sh` | Deterministic schema migration. Dry-run by default; destructive steps gated behind `--apply` and printed first. |
|
||||
| `echo.py` | The validated client + high-level CLI. Low-level verbs `get/ls/map/search/put/post/append/patch/fm/bump/delete/lock/unlock/scope/load` inject auth, **check HTTP status** (non-zero exit on ≥400), retry transient 5xx, read-back-verify PUT, idempotent whole-line `append`, correct `::` heading targets. High-level ops **`capture/resolve/recall/link`** do the routing/linking for you (see below). |
|
||||
| `capture / resolve / recall / link` | The input-reducing layer. **`capture "<title>" --kind <k>`** routes via the entity index, stamps frontmatter, indexes, auto-links mentioned entities, and writes the Agent-Log line in one call. **`resolve "<mention>"`** → canonical path (alias-aware). **`recall "<query>"`** → matching notes + their one-hop linked neighbourhood. **`link A B`** → reciprocal `## Related` links. |
|
||||
| `echo_index.py` | The **entity index** (`_agent/index/entities.json`): slug→{path, kind, title, aliases, last_seen}. Makes routing/resolve an O(1), alias-aware lookup and supplies the name→path map for linking and recall. Rebuilt automatically by `capture` and `sweep.py`. |
|
||||
| `echo_links.py` / `echo_ops.py` | Cross-link primitives (parse/add `## Related`, bidirectional linking) and the high-level ops layer (capture/recall/resolve/link/agent-log). |
|
||||
| `routing.json` | The **canonical machine-readable** route manifest — one regex pattern per valid destination plus retired paths. The single source of truth for "what may be written where"; `vault_lint.py` enforces it against the vault, `check_routing.py` against the docs. |
|
||||
| `vault_lint.py` | Read-only invariant + **graph-health** checker (Vault Health). Tolerant frontmatter parsing, clock injected via `ECHO_TODAY`, exits `3` if the vault isn't bootstrapped. Checks scope-drift, **broken wikilinks, orphan notes, and entity-index drift**. |
|
||||
| `sweep.py` | Brings an upgraded vault up to spec: creates `_agent/index/`, rebuilds the entity index from existing notes, symmetrizes `## Related` cross-links (adds only the missing reciprocal direction), and stamps `schema_version`. Dry-run by default; `--apply` to write. |
|
||||
| `check_routing.py` | Offline routing-doc consistency check: every vault path named in `SKILL.md` / `routing-map.md` / `api-reference.md` must match a route (or retired pattern) in `routing.json`, and every route must appear in the canonical map. No network. The `test_echo_client.py` suite runs it as a guard. |
|
||||
| `bootstrap.py` | Deterministic, idempotent, probe-before-write vault setup/repair (`--dry-run` to preview). Resolves the scaffold relative to itself, so it works from any CWD. |
|
||||
| `migrate.py` | Deterministic schema migration. Dry-run by default; destructive steps gated behind `--apply` and printed first. |
|
||||
|
||||
### Slash commands
|
||||
|
||||
`/echo-load` (cold-start read), `/echo-save <text>` (route + persist), `/echo-triage` (drain the inbox), `/echo-health` (run the linter) — explicit, reproducible entry points to the procedures below.
|
||||
`/echo-load` (cold-start read), `/echo-save <text>` (route + persist via `capture`), `/echo-recall <query>` (recall a topic's neighbourhood), `/echo-triage` (drain the inbox), `/echo-health` (run the linter), `/echo-sweep` (bring the vault up to spec) — explicit, reproducible entry points to the procedures below.
|
||||
|
||||
### Concurrency (shared vault)
|
||||
|
||||
ECHO is read/written by multiple clients (Claude Code **and** CoWork). Single-line files (`heartbeat/last-session.md`, `current-context.md::Scope`) and append targets (`inbox.md`, `## Agent Log`) assume one writer at a time. Before an overlapping burst of writes, take the cooperative advisory lock (`echo.sh lock <id>` → `_agent/locks/vault.lock`, TTL-reclaimable) and release it at session end. Idempotent append and status-checked writes are the second line of defense.
|
||||
ECHO is read/written by multiple clients (Claude Code **and** CoWork). Single-line files (`heartbeat/last-session.md`, `current-context.md::Scope`) and append targets (`inbox.md`, `## Agent Log`) assume one writer at a time. Before an overlapping burst of writes, take the cooperative advisory lock (`echo.py lock <id>` → `_agent/locks/vault.lock`, TTL-reclaimable) and release it at session end. Idempotent append and status-checked writes are the second line of defense.
|
||||
|
||||
---
|
||||
|
||||
@@ -145,7 +157,8 @@ ECHO is read/written by multiple clients (Claude Code **and** CoWork). Single-li
|
||||
├── templates/ ← canonical note templates (seeded from the plugin's scaffold/)
|
||||
├── skills/ ← active / archived capability catalog
|
||||
├── heartbeat/ ← last-session.md pointer (read at load, written at session end)
|
||||
└── locks/ ← vault.lock — cooperative advisory multi-writer lock (echo.sh lock/unlock)
|
||||
├── index/ ← entities.json — machine-maintained slug→{path,kind,aliases} registry
|
||||
└── locks/ ← vault.lock — cooperative advisory multi-writer lock (echo.py lock/unlock)
|
||||
```
|
||||
|
||||
### Memory model
|
||||
@@ -163,7 +176,7 @@ ECHO is read/written by multiple clients (Claude Code **and** CoWork). Single-li
|
||||
|
||||
### Cold-start loading
|
||||
|
||||
Load memory at the start of any substantive conversation (anything beyond a single quick factual question). The cold-start reads are **issued in parallel** (one batch of 5–6 GETs):
|
||||
Load memory at the start of any substantive conversation (anything beyond a single quick factual question). One command — `python3 echo.py load` — performs all six orientation reads and prints each labeled section (absent today's-note / inbox show as such, not errors):
|
||||
|
||||
1. `_agent/echo-vault.md` — the bootstrap marker. `404` → vault not set up (run bootstrap); `200` → check `schema_version` and migrate if older than the plugin's.
|
||||
2. `_agent/memory/semantic/operator-preferences.md` — Jason's profile.
|
||||
@@ -198,8 +211,8 @@ Promotion = move the file **and** update `status:` in the same change.
|
||||
`_agent/context/current-context.md` tracks one active scope. It is the **most churn-prone state** — several sessions a day across different topics — so without care a new session silently inherits a stale scope (the same failure class as inbox auto-fire). 0.7.1 hardens this three ways:
|
||||
|
||||
- **Freshness signal** — a `scope_updated:` frontmatter timestamp records when scope last changed.
|
||||
- **One-command switch** — `echo.sh scope set "<new scope>"` does it atomically: archive the prior scope to `## Scope History` (dated, truncated), replace `## Scope`, and stamp `scope_updated`. (Manual fallback: prepend history → replace `## Scope` → PATCH `scope_updated`; the field must already exist or PATCH returns `400 invalid-target`.) Scope History is trimmed to the last ~10 entries.
|
||||
- **Drift detection** — at load the agent runs `echo.sh scope show` (prints the scope, its `scope_updated`, and how many sessions have been logged since) and *states + confirms* scope before working, switching if it diverges. As a backstop, `vault-lint.sh` flags when ≥ `SCOPE_STALE_SESSIONS` (default 3) session logs postdate `scope_updated` — surfaced in `/echo-health`, so drift is mechanically **evaluable** rather than invisible.
|
||||
- **One-command switch** — `echo.py scope set "<new scope>"` does it atomically: archive the prior scope to `## Scope History` (dated, truncated), replace `## Scope`, and stamp `scope_updated`. (Manual fallback: prepend history → replace `## Scope` → PATCH `scope_updated`; the field must already exist or PATCH returns `400 invalid-target`.) Scope History is trimmed to the last ~10 entries.
|
||||
- **Drift detection** — at load the agent runs `echo.py scope show` (prints the scope, its `scope_updated`, and how many sessions have been logged since) and *states + confirms* scope before working, switching if it diverges. As a backstop, `vault_lint.py` flags when ≥ `SCOPE_STALE_SESSIONS` (default 3) session logs postdate `scope_updated` — surfaced in `/echo-health`, so drift is mechanically **evaluable** rather than invisible.
|
||||
|
||||
### Daily note — Agent Log
|
||||
|
||||
@@ -219,7 +232,7 @@ The journal is one append-only time-series stream; rollups are coarser-grained e
|
||||
|
||||
### Vault Health (monthly)
|
||||
|
||||
Agent self-maintenance (not a journal entry), written to `_agent/health/YYYY-MM-vault-health.md`. Run `scripts/vault-lint.sh` (or `/echo-health`) with `ECHO_TODAY` = the conversation's date so stale/aging math uses one clock. It mechanically asserts: folder↔status mismatch, duplicate slugs across lifecycle folders, wikilinks in frontmatter (swept across all folders), duplicate `## Agent Log` headings, stale active projects (`updated:` > 30 days), aging inbox items (> 14 days), **paths matching no route in `routing.json` or sitting at a retired path**, **frontmatter integrity** (missing required fields, `updated` < `created`, future dates, wikilinks leaking into `source_notes`), and **scope drift** (≥ `SCOPE_STALE_SESSIONS` session logs dated after `scope_updated`). Exit codes: `0` clean · `1` violations · `2` unreachable · `3` not bootstrapped. Findings are reported, not auto-fixed.
|
||||
Agent self-maintenance (not a journal entry), written to `_agent/health/YYYY-MM-vault-health.md`. Run `scripts/vault_lint.py` (or `/echo-health`) with `ECHO_TODAY` = the conversation's date so stale/aging math uses one clock. It mechanically asserts: folder↔status mismatch, duplicate slugs across lifecycle folders, wikilinks in frontmatter (swept across all folders), duplicate `## Agent Log` headings, stale active projects (`updated:` > 30 days), aging inbox items (> 14 days), **paths matching no route in `routing.json` or sitting at a retired path**, **frontmatter integrity** (missing required fields, `updated` < `created`, future dates, wikilinks leaking into `source_notes`), and **scope drift** (≥ `SCOPE_STALE_SESSIONS` session logs dated after `scope_updated`). Exit codes: `0` clean · `1` violations · `2` unreachable · `3` not bootstrapped. Findings are reported, not auto-fixed.
|
||||
|
||||
---
|
||||
|
||||
@@ -230,7 +243,7 @@ Agent self-maintenance (not a journal entry), written to `_agent/health/YYYY-MM-
|
||||
- **Bump `updated:` on substance.** PATCH the frontmatter `updated:` to today after a meaningful content change (status update, decision, scope switch). Skip it for routine log appends — bump on substance, not heartbeat.
|
||||
- **Preserve `created:`.** It is the earliest known date the entity was tracked anywhere — never reset it to "today" when merging.
|
||||
- **No `[[wikilinks]]` in frontmatter** — YAML parses them as nested lists and they break. Cross-references go in a `## Related` body section. `source_notes` holds plain relative-path strings (backward links to inputs only).
|
||||
- **Check the HTTP status (or use `echo.sh`).** A `PATCH` to a missing heading returns `400 invalid-target` (40080) and the write is *silently lost*; a transient `503` or an accepted-but-unpersisted `PUT` can do the same. `echo.sh` enforces this (exit ≠ 0, retry, read-back verify); raw `curl` must branch on `-w "%{http_code}"`. Treat ≥ 400 as a failed op — surface it, don't continue.
|
||||
- **Check the HTTP status (or use `echo.py`).** A `PATCH` to a missing heading returns `400 invalid-target` (40080) and the write is *silently lost*; a transient `503` or an accepted-but-unpersisted `PUT` can do the same. `echo.py` enforces this (exit ≠ 0, retry, read-back verify); raw `curl` must branch on `-w "%{http_code}"`. Treat ≥ 400 as a failed op — surface it, don't continue.
|
||||
|
||||
---
|
||||
|
||||
@@ -277,6 +290,7 @@ Server `https://echoapi.alwisp.com`, bearer auth, root-addressed paths.
|
||||
| Journal rollup | `journal/{weekly/YYYY-Www,monthly/YYYY-MM,quarterly/YYYY-Qn,annual/YYYY}.md` | PUT |
|
||||
| Vault-health audit (agent self-maintenance) | `_agent/health/YYYY-MM-vault-health.md` | PUT |
|
||||
| Session-end orientation pointer | `_agent/heartbeat/last-session.md` | PUT |
|
||||
| Entity index (machine-maintained) | `_agent/index/entities.json` (rebuilt by `capture` / `sweep.py`) | PUT |
|
||||
| Bootstrap marker (plugin-owned) | `_agent/echo-vault.md` (`schema_version`, date) | GET / PUT |
|
||||
|
||||
The complete endpoint→logic map — every path with its trigger and why it's distinct — is `skills/echo-memory/references/routing-map.md`.
|
||||
@@ -316,12 +330,12 @@ Observations are promoted into Fact / Pattern (dropping the date) once a pattern
|
||||
|
||||
## Bootstrap, repair & migration
|
||||
|
||||
The plugin carries everything needed to stand up a vault in `scaffold/`; there is no dependency on any in-vault control doc. In 0.7 these are scripts (`scripts/bootstrap.sh`, `scripts/migrate.sh`), not hand-run curl loops — the prose in `references/bootstrap.md` documents what they do and serves as the fallback.
|
||||
The plugin carries everything needed to stand up a vault in `scaffold/`; there is no dependency on any in-vault control doc. In 0.7 these are scripts (`scripts/bootstrap.py`, `scripts/migrate.py`), not hand-run curl loops — the prose in `references/bootstrap.md` documents what they do and serves as the fallback.
|
||||
|
||||
- **Probe** — GET `_agent/echo-vault.md`. `200` → bootstrapped (check `schema_version`); `404` → run a fresh bootstrap.
|
||||
- **Fresh bootstrap** (`bootstrap.sh`; idempotent, additive — never overwrites): create the folder tree (a one-line README seeds each leaf since Obsidian/git ignore empty dirs) → PUT the 8 templates to their mirrored vault paths → PUT the 3 anchor seeds only if absent (the operator-preferences seed is deliberately empty — no fabricated facts) → PUT the thin vault README → PUT the marker **last** (so the vault is only flagged "set up" once everything is in place) → write a first-run trace (daily note + session log). `--dry-run` previews.
|
||||
- **Repair** — `bootstrap.sh` again: GET-probes each path and creates only what's missing; malformed files are flagged, never replaced.
|
||||
- **Migrations** — `migrate.sh` reads the marker's `schema_version`, applies each intervening migration (dry-run by default; `--apply` to perform moves/deletes), and stamps the marker. `0 → 1` removed the old in-vault control docs (`CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md`); `1 → 2` folded `reviews/` into `journal/` + `_agent/health/`.
|
||||
- **Fresh bootstrap** (`bootstrap.py`; idempotent, additive — never overwrites): create the folder tree (a one-line README seeds each leaf since Obsidian/git ignore empty dirs) → PUT the 8 templates to their mirrored vault paths → PUT the 3 anchor seeds only if absent (the operator-preferences seed is deliberately empty — no fabricated facts) → PUT the thin vault README → PUT the marker **last** (so the vault is only flagged "set up" once everything is in place) → write a first-run trace (daily note + session log). `--dry-run` previews.
|
||||
- **Repair** — `bootstrap.py` again: GET-probes each path and creates only what's missing; malformed files are flagged, never replaced.
|
||||
- **Migrations** — `migrate.py` reads the marker's `schema_version`, applies each intervening migration (dry-run by default; `--apply` to perform moves/deletes), and stamps the marker. `0 → 1` removed the old in-vault control docs (`CLAUDE.md` / `BOOTSTRAP.md` / `STRUCTURE.md` / `index.md`); `1 → 2` folded `reviews/` into `journal/` + `_agent/health/`.
|
||||
|
||||
---
|
||||
|
||||
@@ -350,11 +364,13 @@ If the API returns a connection error, timeout, or `502` (usually Obsidian / the
|
||||
|
||||
| Version | Highlights |
|
||||
|---------|-----------|
|
||||
| **0.9.0** | Schema 3. **Recall + routing intelligence — five layered features aimed at less input to route and richer links to recall.** (1) **Entity index** (`_agent/index/entities.json`): a slug→{path,kind,title,aliases} registry so routing/`resolve` is an O(1), alias-aware lookup instead of a fuzzy search (dedup at the source). (2) **`recall`**: search + one-hop expansion along `## Related` and `source_notes` — returns a topic's connected neighbourhood, not an isolated note. (3) **Bidirectional auto-linking**: `link A B` and link-on-`capture` keep the graph symmetric. (4) **`capture`**: one call that routes, stamps canonical frontmatter, indexes, auto-links mentioned entities, and writes the Agent-Log line — collapsing the whole write discipline. (5) **Graph-health checks** in `vault_lint.py`: broken wikilinks, orphan notes, entity-index drift. Plus **`sweep.py`** to bring an existing vault up to spec (build the index + symmetrize links + stamp schema), `migrate.py` 2→3, and `/echo-recall` + `/echo-sweep` commands. New modules `echo_index.py` / `echo_links.py` / `echo_ops.py`; offline + mock-integration tests (`eval/test_features.py`). |
|
||||
| **0.8.0** | **Cross-platform + reliability pass.** Ported the entire toolchain from bash to **pure Python** (`echo.py`, `vault_lint.py`, `bootstrap.py`, `migrate.py`) so it runs identically on Windows/macOS/Linux — removes the bash and macOS-only `date` dependencies (the lock's TTL parse previously degraded silently on unsupported platforms); stdout is UTF-8-safe so non-ASCII output can't crash a legacy console. **Correctness:** `append` now skips only on an exact **whole-line** match (a substring no longer causes a false skip that silently drops a write); the advisory lock is **read-back-confirmed** after PUT so a racing writer backs off instead of proceeding under a false lock. **Routing consistency (`check_routing.py`):** mechanically verifies the routing docs against `routing.json` in both directions, run as a guard in `test_echo_client.py`; added the missing locks / leaf-README / decision-template rows to the canonical map. **Usability:** new one-call `echo.py load` cold start; `SKILL.md` slimmed — the duplicated raw-curl recipes now live only in `api-reference.md` (the *nix fallback). |
|
||||
| **0.3.0** | Source promoted from zip-only to a tracked tree (`echo-memory.plugin.src/`); `.plugin` becomes a build artifact. All 7 skill-improvement items applied: search-first before writes, resilient daily Agent Log, `created:` semantics, project lifecycle + folder↔status rule, canonical HHMM session filenames, read-most-recent-N sessions, `source_notes` defined as backward links. |
|
||||
| **0.4.0** | Efficiency + robustness pass: parallel cold-start loading, idempotent POST (read-before-append), doc-map-before-first-PATCH, scoped `updated:` bump, Inbox Triage, Scope Switching, monthly Vault Health, Rules-vs-Observations split, formal deprecation of `decisions/by-project/`, heartbeat pointer. |
|
||||
| **0.4.1** | Bugfix: daily-note Agent Log heading detection now greps raw markdown for `^## Agent Log` instead of the `::`-delimited doc-map JSON (which never matched and appended duplicate headings). Added Scope Switching cold-start test harness. |
|
||||
| **0.5.0** | Self-bootstrap + control-logic-in-plugin. Plugin becomes the single source of truth: bundled `scaffold/` (8 templates, 3 anchor seeds, thin vault README, marker) bootstraps an empty vault with no external/local-path dependency. New `operating-contract.md` (principles + safety from the old in-vault `CLAUDE.md`); `bootstrap.md` rewritten as a portable bootstrap/repair/migrate manifest. Cold-start probe moved from `/vault/BOOTSTRAP.md` to `_agent/echo-vault.md` (carries `schema_version`). Live vault migrated to data-only. |
|
||||
| **0.5.1** | Routing-doc consistency pass: decision-mirror heading unified to `## Key Decisions`; stale `Current status` PATCH examples corrected to `Status`; vault-layout inline project example refreshed to the real template. All 17 `projects/active/` notes normalized losslessly to the canonical template heading set; `android-mqtt-shell` moved to `incubating/` (was broken `status: upcoming` in active). Plugin repackaged (21 files). |
|
||||
| **0.6.0** | Schema 2. **#8 Inbox auto-fire:** the Loading procedure adds an inbox-depth GET and a load-time *Reconcile* step (inbox triage + scope-drift), so triage self-fires. **#10 Routing:** `reviews/` retired — weekly/monthly/quarterly/annual rollups fold into `journal/{weekly,monthly,quarterly,annual}/`, vault-health moves to `_agent/health/`; new `references/routing-map.md` is the complete audited endpoint→logic map. **Recs:** heartbeat pointer operationalized (read first at load, written at session end); new `scripts/vault-lint.sh` mechanically checks vault invariants. Dead refs pruned (`archive/`, `_agent/outputs/`, `resources/source-material`). Migration `1 → 2` in `bootstrap.md`. |
|
||||
| **0.7.1** | **Scope-drift fix.** Scope is the most churn-prone state (several sessions/day) and had no freshness signal, so sessions silently ran under stale scope (same failure class as #8). Added a `scope_updated:` frontmatter timestamp (maintained automatically), an `echo.sh scope show` / `scope set` command (atomic switch: archive prior → replace → stamp), and a `vault-lint.sh` **drift check** (flags when ≥ `SCOPE_STALE_SESSIONS`, default 3, session logs are dated after `scope_updated`) — making drift mechanically *evaluable* via `/echo-health`. Tightened the SKILL load-reconcile to *state and confirm* scope every session and switch before working. (Also fixed a bash nested-quote parse bug found while building `scope`, where `show` could fall through into `set`.) |
|
||||
| **0.7.0** | Schema 2 (unchanged layout). Hardening pass — gave the prose-and-curl skill an executable spine. **S2** `scripts/echo.sh`: one validated client wrapping every verb with auth, HTTP-status checking (failed writes exit non-zero instead of looking like success), one bounded retry on 5xx, read-back-verified PUT, and idempotent `append`. **S3** `scripts/routing.json`: canonical machine-readable route manifest; `vault-lint.sh` enforces it (flags unknown/retired paths). **S4** deterministic `scripts/bootstrap.sh` + `scripts/migrate.sh` (idempotent, dry-run, probe-before-write; fixes the old CWD-relative `@scaffold/...` empty-body bug). **S5** cooperative advisory lock (`_agent/locks/vault.lock`) + documented multi-writer model. **M1/M2/M5** linter rewrite: real YAML parsing, injected clock (`ECHO_TODAY`), exits `3` (not "clean") on an un-bootstrapped vault, plus routing-membership + frontmatter-integrity checks. **M3** status-check guidance throughout. **M4** four slash commands (`/echo-load`, `/echo-save`, `/echo-triage`, `/echo-health`). Added a credential-free A/B `eval/` harness (mock REST API + fault injection): isolates a **−76% generated-token** I/O layer and **4 → 0 silent write failures** vs 0.6. |
|
||||
| **0.6.0** | Schema 2. **#8 Inbox auto-fire:** the Loading procedure adds an inbox-depth GET and a load-time *Reconcile* step (inbox triage + scope-drift), so triage self-fires. **#10 Routing:** `reviews/` retired — weekly/monthly/quarterly/annual rollups fold into `journal/{weekly,monthly,quarterly,annual}/`, vault-health moves to `_agent/health/`; new `references/routing-map.md` is the complete audited endpoint→logic map. **Recs:** heartbeat pointer operationalized (read first at load, written at session end); new `scripts/vault_lint.py` mechanically checks vault invariants. Dead refs pruned (`archive/`, `_agent/outputs/`, `resources/source-material`). Migration `1 → 2` in `bootstrap.md`. |
|
||||
| **0.7.1** | **Scope-drift fix.** Scope is the most churn-prone state (several sessions/day) and had no freshness signal, so sessions silently ran under stale scope (same failure class as #8). Added a `scope_updated:` frontmatter timestamp (maintained automatically), an `echo.py scope show` / `scope set` command (atomic switch: archive prior → replace → stamp), and a `vault_lint.py` **drift check** (flags when ≥ `SCOPE_STALE_SESSIONS`, default 3, session logs are dated after `scope_updated`) — making drift mechanically *evaluable* via `/echo-health`. Tightened the SKILL load-reconcile to *state and confirm* scope every session and switch before working. (Also fixed a bash nested-quote parse bug found while building `scope`, where `show` could fall through into `set`.) |
|
||||
| **0.7.0** | Schema 2 (unchanged layout). Hardening pass — gave the prose-and-curl skill an executable spine. **S2** `scripts/echo.py`: one validated client wrapping every verb with auth, HTTP-status checking (failed writes exit non-zero instead of looking like success), one bounded retry on 5xx, read-back-verified PUT, and idempotent `append`. **S3** `scripts/routing.json`: canonical machine-readable route manifest; `vault_lint.py` enforces it (flags unknown/retired paths). **S4** deterministic `scripts/bootstrap.py` + `scripts/migrate.py` (idempotent, dry-run, probe-before-write; fixes the old CWD-relative `@scaffold/...` empty-body bug). **S5** cooperative advisory lock (`_agent/locks/vault.lock`) + documented multi-writer model. **M1/M2/M5** linter rewrite: real YAML parsing, injected clock (`ECHO_TODAY`), exits `3` (not "clean") on an un-bootstrapped vault, plus routing-membership + frontmatter-integrity checks. **M3** status-check guidance throughout. **M4** four slash commands (`/echo-load`, `/echo-save`, `/echo-triage`, `/echo-health`). Added a credential-free A/B `eval/` harness (mock REST API + fault injection): isolates a **−76% generated-token** I/O layer and **4 → 0 silent write failures** vs 0.6. |
|
||||
|
||||
Reference in New Issue
Block a user