1
0
forked from jason/echo

Phase 3: per-member namespacing — schema 5 (the core group conversion)

One shared vault, per-member namespaces for all churn-prone state:
- _agent/members/<member>/{preferences,current-context,heartbeat,inbox}.md
  + _agent/sessions/<member>/ session logs; shared group-profile.md
  (with auto-rostered ## Members) and inbox/captures/group.md.
- Self-onboarding: load detects a bootstrapped vault lacking THIS
  member's namespace and seeds it (bootstrap.member_bootstrap()).
- load = 8 reads (marker, group profile, my prefs/context/heartbeat,
  shared daily, my inbox, group inbox); heartbeat fallback lists my
  sessions dir; scope show/set is per member.
- Member-tagged shared writes: daily Agent Log lines and entity-update
  dated blocks are '- YYYY-MM-DD [member]: …'; capture --inbox targets
  my inbox; triage lists both inboxes and writes attributed audit lines.
- routing.json: member-anchors / inbox-group / member-segmented session
  routes; single-user anchor paths retired (schema 5). vault_lint runs
  aging-inbox + scope-drift per member. migrate.py 4->5 for alpha vaults.
- Scaffold: member-* seeds ({{MEMBER}}-stamped), group-profile/group-inbox
  seeds, marker schema 5. Docs (SKILL, vault-layout, routing-map,
  bootstrap) synced; manifest -> 2.0.0-alpha.3; rebuilt plugin (81 files).

Verified: all suites green (25/25 unit, scaffold, routing-sync 36 routes,
4 mock e2e, run_eval unchanged) + 19-check two-member smoke: bootstrap ->
self-onboard -> interleaved tagged daily log -> cross-member update
attribution -> independent scopes -> mine/group triage -> lint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-21 15:16:13 -05:00
parent b3bc5272d5
commit 33a2d73a22
31 changed files with 449 additions and 184 deletions
+5 -5
View File
@@ -121,14 +121,14 @@ def main():
# 6. inbox capture (unknown home)
h.chorus(CHORUS, "capture", "stray thought", "--inbox")
inbox = h.ground("inbox/captures/inbox.md")
inbox = h.ground("_agent/members/eval-member/inbox.md")
check("inbox capture lands", inbox and "stray thought" in inbox)
# 7. sweep --apply rebuilds the index, symmetrizes, stamps schema 3
r = h.chorus(SWEEP, "--apply")
marker = h.ground("_agent/chorus-vault.md")
check("sweep runs clean", r.returncode == 0, r.stdout + r.stderr)
check("sweep stamps schema 4", marker and "schema_version=4" in marker.replace(": ", "="), marker)
check("sweep stamps schema 5", marker and "schema_version=5" in marker.replace(": ", "="), marker)
idx2 = h.ground("_agent/index/entities.json")
check("sweep rebuilt index has all entities",
idx2 and all(s in idx2 for s in ["bob-smith", "mpm", "alpha", "beta"]))
@@ -188,7 +188,7 @@ def main():
capture_output=True, text=True,
env=dict(os.environ, CHORUS_BASE=base, CHORUS_KEY=KEY, CHORUS_MEMBER="eval-member", CHORUS_TODAY="2026-06-21"))
bob3 = h.ground("resources/people/bob-smith.md") or ""
check("v1.5 update keeps the dated bullet", "- 2026-06-21: met at expo" in bob3, r.stdout + r.stderr)
check("v1.5 update keeps the dated bullet", "- 2026-06-21 [eval-member]: met at expo" in bob3, r.stdout + r.stderr)
check("v1.5 update keeps EVERY body line",
" second line survives" in bob3 and " third line too" in bob3, bob3)
@@ -259,7 +259,7 @@ def main():
and primary[0].get("status") == "active", json.dumps(primary[:1]))
# 15. one-tap triage: structured list, then route with an audit trail.
h.seed("inbox/captures/inbox.md",
h.seed("_agent/members/eval-member/inbox.md",
"- 2026-06-01: prefers uv over pip\n- 2026-06-20: try the new espresso place\n")
r = h.chorus(CHORUS, "triage", "--list", "--json")
try:
@@ -282,7 +282,7 @@ def main():
check("v1.5 triage writes the processing-log audit line",
"prefers uv over pip" in plog and "_agent/memory/semantic/prefers-uv-over-pip.md" in plog, plog)
check("v1.5 triage keeps the original capture",
"prefers uv over pip" in (h.ground("inbox/captures/inbox.md") or ""))
"prefers uv over pip" in (h.ground("_agent/members/eval-member/inbox.md") or ""))
# 16. lint flags incomplete entity frontmatter; sweep backfills it.
h.seed("resources/companies/driftco.md",