MUSEHUB-ROADMAP.md markdown
742 lines 65.4 KB
Raw
sha256:cf6265cea8c21d9228d90dec13ef6ec2dab5103d466db9cc4590681832de4bf8 docs(KD-STAGING): sync governance after KD-6b DONE Human 13 days ago

MuseHub Roadmap

Program: Knowtation domain — vault-native VCS intelligence for agent knowledge systems.

Authority: This document governs work in the MUSE_HUB workspace (gabriel-muse, musehub, and related repos). It is separate from Scooling's docs/ROADMAP.md. Scooling consumes Knowtation via REST/MCP adapters in parallel; it does not block this track.

Source spec: gabriel/muse issue #2 (frozen phase order — each phase unlocks the next for new work; local code may span multiple phases).

Handover relay: docs/MUSEHUB-OVERSEER-HANDOVER.md — paste the NEXT SESSION block into a fresh chat.


Phase Model Key

Label Meaning
Thinking Contract, architecture, open-question resolution, test matrix — freeze spec before build
Auto Mechanical implementation against a frozen spec; run tests; Muse commit on feature branch
Thinking → Auto Split into {step}a (Thinking) then {step}b (Auto) in the handover doc
Operator + Auto Tier 3 human authorization for staging push / live gate; Auto for implementation

Handover rule: Every next-step table and paste block must include Model:.


Next step at a glance (2026-07-10)

Item Status
Active track Knowtation domain — staging push + attestation verification
Plugin code (Phases 1–4, 7, KD-5b) DONE locallygabriel-muse/muse/plugins/knowtation/ + muse/mcp/ (36 MCP tests, 1606 knowtation tests green)
Staging plugin repo DONEaaronrene/gabriel-muse @ sha256:660fcac1… (2026-06-21) — pre-KD-5b; re-push needed
Marketplace registration DONE@aaronrene/knowtation on staging (2026-07-05); viewer_type: generic (optional fix)
Vault activation smoke DONEknowtation-vault-smoke (5 PASS / 3 PARTIAL — see handover matrix)
Open questions (KD-OQ) DONE (2026-07-10) — all 5 issue #2 questions resolved (see table below)
MCP surface (KD-5b) DONE (2026-07-10) — 9 tools / 8 resources / 4 prompts at muse/mcp/; activation gate; 7-tier + Claude Desktop stdio integration green on knowtation-vault-smoke
Vault UI contract (KD-6a) DONE (2026-07-10) — §KD-6a frozen: 4 page groups (landing, note detail, proposals, vault search), routes, MCP read-mapping, error enums, 7-tier matrix + Playwright E2E
Vault UI (KD-6b) DONE (2026-07-10) — knowtation_view adapter, ui_vault.py, templates/SCSS, harmony diff, 7-tier + Playwright E2E green locally
NEXT KD-STAGING — Tier 3 push gabriel-muse (KD-5b) + musehub (KD-6b) to staging; KD-7 attestation smoke on staging vault
Parked
Parallel (Scooling) Phase 9A overseer gates — independent

Build status table

ID Phase Repo(s) Model Status
KD-0 Recovery + rc14 re-baseline gabriel-muse Auto DONE (2026-06-20) — corrupt rc3 history discarded; code intact; 1570 tests green
KD-SD8-PUSH Push plugin to staging gabriel-muse Auto (Tier 3) DONE (2026-06-21) — aaronrene/gabriel-muse @ 660fcac1…
KD-SD8-REG Marketplace registration musehub (API) Auto (Tier 3) DONE (2026-07-05) — @aaronrene/knowtation; viewer_type: generic (fix optional)
KD-1 Domain foundation (detector, parser, plugin, symbols, domain-info) gabriel-muse Auto DONE — proven on vault smoke (domain-info PASS; symbols CLI PARTIAL)
KD-2 Semantic diff & harmony merge gabriel-muse Auto DONE — differ/merger API proven; CLI merge/diff PARTIAL (see handover)
KD-3 Code intelligence (deps, impact, hotspots, dead, clones, entangle, velocity) gabriel-muse Auto DONE — deps/impact/hotspots/dead PASS on test vault
KD-4 Memory timeline (event schema, symbol-log, consolidation hook, prime) gabriel-muse Auto DONE — log event_type PASS; prime_context API PASS (no CLI hook)
KD-7 Attestation & ICP push hook gabriel-muse Auto DONE (local; attestation smoke post-activation)
KD-ACTIVATE Vault activation + Phase 1–4 smoke gabriel-muse + test vault Auto DONE (2026-07-10) — knowtation-vault-smoke; 5 PASS / 3 PARTIAL
KD-OQ Resolve issue #2 open questions (5 items) gabriel-muse + musehub Thinking DONE (2026-07-10) — 5/5 resolved with source-backed rationale; gate cleared for KD-5a
KD-5a MCP domain surface — contract + test matrix gabriel-muse + musehub Thinking DONE (2026-07-10) — contract frozen (§KD-5a); open items (a)–(e) resolved; 7-tier matrix + Claude Desktop integration test specified
KD-5b MCP domain surface — implementation (9 tools, 8 resources, 4 prompts) gabriel-muse + musehub Auto DONE (2026-07-10) — muse/mcp/ server + namespace; 36 MCP tests + stdio E2E green on knowtation-vault-smoke
KD-6a MuseHub vault UI — contract + test matrix musehub Thinking DONE (2026-07-10) — contract frozen (§KD-6a); 4 page groups, routes, MCP read-mapping, error enums, 7-tier matrix + Playwright E2E specified
KD-6b MuseHub vault UI — implementation musehub Auto DONE (2026-07-10) — knowtation_view adapter, ui_vault.py, vault templates/SCSS, harmony diff, 7-tier + Playwright E2E green locally
KD-STAGING Staging push (KD-5b plugin + KD-6b musehub) + KD-7 attestation smoke gabriel-muse + musehub Operator + Auto (Tier 3) NEXT

Repo boundaries

Repo Role in this program VCS
gabriel-muse Canonical home of muse/plugins/knowtation/ — detector, parser, merger, code intel, attestation Muse; staging remote aaronrene/gabriel-muse
musehub Marketplace API, domain registration, Phase 6 vault-centric UI, MCP server mount Muse / git per repo convention
knowtation (product) Vault store, Hub API, MCP — not the Muse domain plugin Separate; Scooling adapter target
knowtation-vault-smoke KD-ACTIVATE test vault — not product repo Local Muse repo; domain=knowtation
scooling Consumer UI — parallel track; wires domain features after KD-5/KD-6 land See Scooling governance docs

Important: The Knowtation product repo (.museattributesdomain = "code") is not a vault repo. Activation uses a vault repo — Markdown notes with Knowtation frontmatter (source_type, source_id, project, tags, entity).


Phase detail (frozen from issue #2)

KD-1 — Domain Foundation

Goal: Muse recognises Knowtation vault files as a distinct domain and introspects them structurally.

Deliverables (verified in tree):

  • detector.py, parser.py, plugin.py, symbols.py, stats.py
  • defaults.museattributes snippet
  • muse domain-info --json shape; muse code symbols --file note.md

Exit criteria: KD-ACTIVATE smoke PASS on a real vault repo — MET (domain-info PASS; symbols CLI routes through code AST — gap recorded).


KD-2 — Semantic Diff & Harmony Merge

Goal: Section-aware diff; policy-based merge for tags, entities, source_id conflicts.

Deliverables (verified in tree):

  • differ.py, merger.py, policies.py, strategies.py, rerere.py
  • Harmony policies for tag union, entity union, prefer-newer-date, §Summary escalation

Exit criteria: muse merge resolves tag/entity conflicts without raw-text panics — PARTIAL (merge_notes union PASS; muse merge CLI file-conflict on tag-only divergence).


KD-3 — Code Intelligence

Goal: muse code deps, impact, hotspots, gravity, dead, clones, entangle, velocity on vault repos.

Deliverables (verified in tree):

  • link_index.py, code_intel.py, note_metrics.py, cli_hooks.py

Exit criteria: All six commands return meaningful JSON on test vault — MET (deps, impact, hotspots, dead verified).


KD-4 — Memory Timeline

Goal: Memory event types in commit metadata; symbol-log as memory replay; prime bootstrap from commit graph.

Deliverables (verified in tree):

  • events.py (15 event kinds, schema locked v1.0.0)
  • hooks.py (consolidation pre-merge)
  • prime_context.py (knowtation://prime from commit graph)

Exit criteria: muse log --json surfaces event_type; prime JSON smoke PASS — MET (log PASS; prime via build_prime_context API, no CLI).


KD-5 — MCP Domain Surface (KD-5a contract frozen; KD-5b implementation DONE)

Status (KD-5b): DONE (2026-07-10). Server at muse/mcp/; 9 tools / 8 resources / 4 prompts; activation gate on repo.json domain==knowtation; 36 MCP tests + stdio E2E green on knowtation-vault-smoke.

Goal: Knowtation domain ops via Muse MCP (knowtation/search, get-note, history, consolidate, impact, dead, prime, propose, attest — 9 tools + 8 resources + 4 prompts per issue #2 Phase 5).

Entry criteria: KD-ACTIVATE PASS; KD-OQ resolved. Both MET (2026-07-10).

Frozen inputs from KD-OQ: search backend = Muse structural index + Knowtation live vector index (OQ2); knowtation/consolidate = async dispatch, non-blocking (OQ3); knowtation/attest = generic MuseAttestationProvider reusing the ICP canister (OQ4); no agent.md merge (OQ5); detection = frontmatter-primary with optional marker (OQ1).

Model: Thinking → Auto (KD-5a Thinking DONE — contract frozen below; KD-5b Auto is NEXT).


KD-5a Contract — Muse MCP Domain Surface (knowtation namespace) — FROZEN 2026-07-10

Status: DONE (Thinking). This section is the frozen spec KD-5b (Auto) implements against. Do not redesign during Build. Interfaces below are the contract; the seven-tier test matrix is in §KD-5a.F. Implementation-only (KD-5b) items are tagged [KD-5b new work].

Authority chain: issue #2 Phase 5 tables (9 tools / 8 resources / 4 prompts) + KD-OQ frozen decisions (OQ1–OQ5). The prompt count is 4 (issue #2 §5.3 lists 3 and adds vault/knowledge-gaps in its deliverables line; the corrected count is 4 — see change log 2026-07-10).

KD-5a.0 — Transport, envelope & shared conventions

  • Protocol: JSON-RPC 2.0 per MCP (tools/list, tools/call, resources/list, resources/read, prompts/list, prompts/get).
  • Tool names: knowtation/<verb> (slash-namespaced). Resource URIs: knowtation://… scheme. Prompt names: vault/<name>.
  • Repo binding: every call operates on the server's bound repo root (the process CWD's .muse/); no tool takes a filesystem root argument (prevents path-escape and cross-repo reads).
  • ref grammar (shared): HEAD | branch name | full/abbrev sha256 commit id. Resolved via muse.core.store.resolve_commit_ref; unknown ref → REF_NOT_FOUND.
  • path grammar (shared): vault-relative POSIX path. Reject absolute paths, .. segments, and any resolved path escaping the repo root → PATH_INVALID (reuses the link_index._normalise_rel_path escape check). Non-.md/.markdown/.mdxNOT_A_NOTE.
  • Error envelope: JSON-RPC error {code, message, data:{reason, detail?}} where reason is a stable UPPER_SNAKE token (enumerated per tool). Human detail is control-char sanitised (sanitize_display). No stack traces, no secrets, no absolute host paths in message/data.
  • Determinism: read tools are pure/idempotent; write/dispatch tools (consolidate, propose, attest) are the only side-effecting members and are individually gated (see below).
  • Bounds (DoS): every commit walk is capped (max/max_commits, clamp 1..100000, default per tool); every note body read reuses the 16 MiB cap (link_index._MAX_NOTE_BYTES); every HTTP response is byte-capped (attestation 64 KiB; hub calls 256 KiB).

KD-5a.A — Resolution of the five open contract items (a)–(e)

(a) knowtation/search fan-out — FROZEN. Two backends, merged by the server:

  1. Muse lexical/structural (owned by Muse, OQ2): live-vault content grep + build_link_index title/heading/frontmatter hits. [KD-5b new work] — no content_grep helper exists in the plugin today; KD-5b adds muse/plugins/knowtation/search.py::lexical_search(root, query, *, top_k) returning [{path, score∈[0,1], section_address?, snippet}].
  2. Knowtation vector (canonical for semantic at HEAD, OQ2): HTTP GET to the local hub (http://localhost:<KNOWTATION_HUB_PORT>/api/v1/search?q=…&k=…) — Muse never rebuilds or versions data/. [KD-5b new work] — thin client, SSRF-guarded port validation reused verbatim from hooks._resolve_port.
  • Merge/rank: normalise each backend's score to [0,1]; combined score = w_lex·lex + w_vec·vec with frozen weights w_lex=0.4, w_vec=0.6 (semantic favoured at HEAD, per OQ2). A result present in only one backend uses that backend's normalised score with the missing side treated as 0.
  • Dedupe key: vault-relative path (case-insensitive basename collision resolved the same way link_index resolves it — first walk-order path wins; the other is dropped and counted in deduped). When both backends return the same path, scores are combined (not summed twice).
  • Tie-breakers (stable): higher combined score → then more recent HEAD mtime → then lexicographic path.
  • Fallback / timeout: vector call timeout 2.0 s; on timeout/connection-refused/non-200 the server returns lexical-only results with degraded=true, backends.vector="unavailable", and a populated index_freshness (or null) — never an error. If the lexical side raises, return vector-only with backends.lexical="error". Both down → results:[], degraded=true (still a success response so agents can proceed).

(b) knowtation/consolidate return schema — FROZEN. The tool wraps KnowtationMergeHook.pre_merge_hook (OQ3, fire-and-forget). Output is the dispatch receipt exactly mirroring hooks.hook_result_to_json: {hook_name:string, fired:bool, out_of_band:bool, message:string, error:string|null, dispatched_at:iso8601, hub_port:int}.

  • Async completion is NOT observable through this tool (by design — merge never blocks). The agent observes completion out-of-band via knowtation://memory/recent (a later commit with event_type∈{consolidation,consolidation_pass}) or knowtation/history. This is documented in the tool description so agents do not poll.
  • Port-validation failure and dispatch failure are returned in error with fired=falsethe tool never raises for hub-side problems (parity with the hook contract).

(c) knowtation/attest runtime wiring — FROZEN.

  • Who registers: the MCP server bootstrap registers both providers when the bound repo's active domain is knowtation — it calls attestation.register_knowtation_attestation_provider(cfg) and icp_push_hook.register_knowtation_icp_push_hook() at server start. Today only the merge hook auto-registers in plugins/knowtation/__init__.py; the attest/ICP registration is [KD-5b new work] (a bootstrap_knowtation_mcp(root) call — it must not be moved into __init__.py, to keep import side-effect-free per OQ4).
  • Required vs optional mode: driven by .muse/air.yaml air.required (loaded via attestation.load_air_config). The tool accepts an optional required?:bool that overrides for this call only. required=true + endpoint unreachable → AttestationRequiredError surfaced as error reason=ATTESTATION_REQUIRED. required=false → placeholder record returned with anchored=false (never an error).
  • Provider unregistered: the tool returns a structured error reason=PROVIDER_UNREGISTERED (never a silent success, never a placeholder masquerading as real). ICP anchoring is out-of-band (out_of_band=true) and its failure is reported in anchor as null with anchor_error, never failing the tool.

(d) .museignore data/ — FROZEN: YES (ignore for snapshots; keep readable on disk). KD-5b adds a [domain.knowtation] section to .museignore with patterns = ["data/", ".obsidian/"] so Muse never snapshots/versions Knowtation's vector/sqlite index (consistent with OQ2 "not rebuilt/versioned by Muse"). This is a snapshot-exclusion rule only: stats.collect_vault_stats still stat()s data/ on the live filesystem for index_freshness (a filesystem read, unaffected by .museignore), and link_index/code_intel already skip non-.md files so the vector store is never parsed as a note. .knowtation remains an always-ignored marker via plugin._ALWAYS_IGNORE_DIRS; data/ is domain-scoped ignore (only when active domain is knowtation).

(e) MCP-scope activation semantics — FROZEN: explicit repo.json domain, detector is advisory. The knowtation/* namespace mounts/advertises only when .muse/repo.json domain == "knowtation" (explicit activation via muse init --domain knowtation). detector.classify_repo is advisory only: the server MAY surface detected_domain + confidence as a capability hint (so a misconfigured repo can be diagnosed) but never auto-mounts vault tools on a repo whose active domain is code/mist. This prevents a code repo containing a few notes from exposing vault write/attest surfaces. When domain≠knowtation the server returns an empty knowtation/* tool list.

KD-5a.B — Tool contracts (9)

Legend: Backing = existing plugin/CLI API the tool wraps; [KD-5b new work] = no backing API, implement in KD-5b. All inputs validated against §KD-5a.0 grammars before dispatch.

# Tool Input (JSON-RPC params) Output (result) Backing API Error reasons
1 knowtation/search {query:string!, top_k?:int=10 (1..100), project?:string, mode?:"hybrid"\|"lexical"\|"semantic"="hybrid", ref?:string="HEAD"} {query, mode, results:[{path, score, source:"muse-lexical"\|"knowtation-vector"\|"both", snippet, section_address?, frontmatter:{project,tags,source_type}}], index_freshness:string\|null, degraded:bool, deduped:int, backends:{lexical:"ok"\|"error", vector:"ok"\|"unavailable"}} lexical [KD-5b new work] (search.lexical_search) + link_index + hub vector client [KD-5b new work]; stats.collect_vault_stats for freshness QUERY_INVALID, REF_NOT_FOUND (never errors on backend outage — see A(a))
2 knowtation/get-note {path:string!, ref?:string="HEAD", format?:"json"\|"raw"="json"} {path, ref, exists:bool, frontmatter:object, body:string, symbols:[symbol…], content_hash:string} muse cat@ref (core.store manifest+object read) + symbols.extract_symbols PATH_INVALID, NOT_A_NOTE, NOTE_NOT_FOUND, REF_NOT_FOUND
3 knowtation/history {address:string!, from_ref?:string="HEAD", max?:int=500 (1..100000)} {address, start_ref, total_commits_scanned, truncated, events:[{event, commit_id, message, committed_at, address, detail, new_address, event_type, agent_id, model_id}]} cli/commands/symbol_log.py (_find_events_in_commit + walk_commits_bfs) — existing ADDRESS_INVALID, REF_NOT_FOUND
4 knowtation/consolidate {branch?:string, ours_ref?:string, theirs_ref?:string} (metadata passthrough; hook ignores today) dispatch receipt (see A(b)): {hook_name, fired, out_of_band, message, error, dispatched_at, hub_port} hooks.KnowtationMergeHook.pre_merge_hook + hook_result_to_jsonexisting (never raises; failures in error)
5 knowtation/impact {path:string!, direction?:"reverse"\|"forward"="reverse", depth?:int=0 (>=0), include_attachments?:bool=true} {note, direction, depth_limit, by_depth, total, include_attachments} code_intel.impact_for_note/note_impactexisting PATH_INVALID, NOTE_NOT_FOUND, DEPTH_NEGATIVE
6 knowtation/dead {use_mtime?:bool=true, mtime_days_threshold?:int=180 (>=0), project?:string} {total_notes_indexed, dead_count, dead_notes:[{path, mtime?}]} note_metrics.note_dead (+ build_link_index) — existing NOT_KNOWTATION_REPO
7 knowtation/prime {max_commits?:int=100 (1..100000), hot_note_count?:int=10 (1..100)} PrimeContext.to_dict: {schema_version, source, commits_scanned, last_consolidation, hot_notes} (+ active_projects, suggested_next enrichment) prime_context.build_prime_contextexisting; active_projects/suggested_next via stats [KD-5b new work] (never fatal; partial on graph-read error)
8 knowtation/propose {path:string!, title:string!, proposed_body?:string, proposed_frontmatter?:object, base_ref?:string="HEAD", scope?:"personal"\|"project"\|"org"="personal", rationale?:string} {proposal_id, status:"created", hub_url, path, base_ref, scope} muse hub proposal create → Knowtation Hub proposal endpoint — [KD-5b new work] (no proposal API in plugin today) PATH_INVALID, NOTE_NOT_FOUND, HUB_UNREACHABLE, SCOPE_UNAUTHORIZED, VALIDATION_FAILED
9 knowtation/attest {commit_id:string!, action?:string="write", required?:bool} {record:{id, action, path, timestamp, content_hash, algorithm, provider_id, sig?}, anchored:bool, anchor:{tx_id, anchor_url, provider_id}\|null, anchor_error?:string, provider_registered:bool} attestation.KnowtationHmacAttestationProvider (compute+anchor) + icp_push_hookexisting; runtime registration [KD-5b new work] (see A(c)) PROVIDER_UNREGISTERED, COMMIT_NOT_FOUND, ATTESTATION_REQUIRED

Write/side-effect gating: tools 4, 8, 9 are the only non-read members. propose is review-before-write (scope enforced server-side, per Scooling boundary rules); consolidate/attest are dispatch/opt-in. Read tools (1,2,3,5,6,7) have zero durable side effects.

KD-5a.C — Resource contracts (8)

# Resource URI Content (result) Backing API Notes
1 knowtation://vault {notes:[{path, title, project, tags, source_type}], stats:VaultStats} stats.collect_vault_stats + note-level walk (parse_frontmatter/extract_symbols) — listing walk [KD-5b new work] Root listing + frontmatter summary
2 knowtation://vault/{path} note at HEAD — same body as knowtation/get-note (ref=HEAD) get-note core {path} obeys shared path grammar
3 knowtation://vault/{path}@{ref} note at {ref} — same body as knowtation/get-note get-note core URI-template @{ref} parsed then validated
4 knowtation://prime PrimeContext.to_dict prime_context.build_prime_contextexisting Mirrors knowtation/prime (no args)
5 knowtation://graph {notes_indexed, forward:{src:[edge…]}, backward:{tgt:[edge…]}, broken_links:[edge…], entities:{label:[path…]}} link_index.build_link_index + JSON serializer [KD-5b new work] (LinkIndex has no to_json today) Edge = describe_link shape
6 knowtation://memory/recent {events:[{commit_id, committed_at, message, event_type, agent_id, model_id}], count} (last 20) walk_commits_bfs + filter metadata.event_type present — composition [KD-5b new work] Event kinds validated against events.MemoryEventKind
7 knowtation://projects {projects:[{project, note_count, last_modified}]} stats.collect_vault_stats.projects + _query.group_by_project + mtime — composition [KD-5b new work]
8 knowtation://hotspots note_hotspots JSON: {commits_analysed, total_notes_touched, ranking:[{path, changes}]} (top 10) note_metrics.note_hotspots + make_snapshot_loaderexisting top=10 fixed for the resource

KD-5a.D — Prompt contracts (4)

MCP prompts return messages[]; each composes the tools/resources above (no new backend).

# Prompt Arguments Composition (backing) Output
1 vault/daily-brief {since_hours?:int=24 (1..168), project?:string} walk_commits_bfs filtered to window + knowtation://memory/recent Prompt messages summarising last-24h commits/projects
2 vault/search-synthesis {query:string!, top_k?:int=5 (1..20)} knowtation/search (top_k) → format top-5 + synthesis instruction Prompt messages: results + synthesis directive
3 vault/memory-session {project?:string} knowtation/prime + knowtation://memory/recent Prompt messages: prime + recent events to resume session
4 vault/knowledge-gaps {} knowtation/dead × link_index.entity_index cross-reference Prompt messages: dead notes joined with entity coverage gaps

KD-5a.E — Namespace mount point (gabriel-muse) & musehub hosting

  • Server home [KD-5b new work]: gabriel-muse/muse/mcp/ — no MCP server exists today (confirmed: no muse/mcp/ tree; prime_context.py only anticipates Phase 5). KD-5b scaffolds muse/mcp/server.py (a MuseMCPServer with a namespace registry) + muse/mcp/namespaces/knowtation.py (registers the 9 tools / 8 resources / 4 prompts under the knowtation/ tool prefix and knowtation:// resource scheme).
  • Activation gate (A(e)): on start, the server reads .muse/repo.json; it registers the knowtation namespace iff domain == "knowtation". It then calls bootstrap_knowtation_mcp(root) which registers the attestation provider + ICP push hook (A(c)). When domain≠knowtation, tools/list returns no knowtation/* entries.
  • musehub hosting: musehub launches the Muse MCP server per repostdio transport for local MCP clients (Claude Desktop, Cursor), and a hosted HTTP+SSE transport for remote agents. The server process runs with the repo root as CWD so all binding is implicit (no path args cross the wire). The marketplace listing @aaronrene/knowtation (already registered, KD-SD8-REG) gains its MCP capability descriptor in KD-5b; the vault UI is KD-6.
  • Secret hygiene at the mount: the server never echoes MUSE_AIR_HMAC_KEY, air.endpoint, MUSE_ICP_IDENTITY_PEM, KNOWTATION_HUB_PORT internals, or absolute host paths in any tool/resource/prompt result, log line, or error data. Attestation sig (an HMAC output, not key material) MAY be returned; the HMAC key MUST NOT.

KD-5a.F — Seven-tier test matrix (per group + Claude Desktop integration)

All tiers run in gabriel-muse (pytest tests/test_knowtation_mcp_*.py — new files in KD-5b) against ~/MUSE_HUB/knowtation-vault-smoke. Each row is the required minimum for KD-5b Definition of Done.

Tier Tools (1–9) Resources (1–8) Prompts (1–4)
1 Unit Each tool's input-schema validation (grammar A.0), output serialization shape, error-reason mapping; per-tool arg defaults/clamps Each resource URI parse (incl. @{ref} template), output shape, empty-vault case Argument schema + message assembly for each prompt (mocked tool outputs)
2 Integration Tool → backing API on the smoke vault (search fan-out both backends; get-note@ref; history events; consolidate receipt; impact/dead/prime/hotspots real JSON; propose→hub stub; attest→provider stub) Resource → backing on smoke vault; graph/memory/recent/projects composition correctness Prompt → real tool chain on smoke vault (search-synthesis, memory-session)
3 E2E tools/list+tools/call over JSON-RPC through the mounted server (domain=knowtation) resources/list+resources/read round-trip prompts/list+prompts/get round-trip
4 Stress 5k-note vault: search/impact/dead/hotspots within perf budget; max clamps honoured; vector-backend timeout path under load graph on 5k notes; vault listing pagination bound daily-brief over 500-commit window; knowledge-gaps over large entity index
5 Data-integrity history/memory/recent event_type parity vs events.EVENTS_SCHEMA_HASH; get-note content_hash matches store; attest id determinism (compute_attestation_id) resource payloads round-trip; graph edges match describe_link; index_freshness == data/ mtime prompt outputs cite only real notes (no fabricated paths)
6 Performance search < 2 s hybrid (lexical budget < 1 s + vector timeout 2 s); impact/dead/hotspots < 2 s on 5k vault (reuse §3.3 budgets); prime < 1 s / 100 commits graph build < 10 s / 5k (reuse link_index budget) prompt assembly < 500 ms excluding model call
7 Security path-traversal reject (get-note/impact/propose); SSRF-guard on search-vector + consolidate port + attest endpoint + ICP canister-id (reuse existing regex guards); no secret in any result/log/error; air.required rejection; PROVIDER_UNREGISTERED never silent-success; sensitive-key scan (events._has_sensitive_keys) on surfaced note data; activation gate blocks knowtation/* on domain≠knowtation resource path-escape reject; memory/recent strips sensitive metadata prompt injection: note bodies are data-not-instructions; control-char sanitised

Claude Desktop integration test (required, Tier 3/E2E): register the KD-5b server in Claude Desktop's MCP config bound to knowtation-vault-smoke; verify tools/list shows the 9 tools, resources/list shows the 8 resources, prompts/list shows the 4 prompts, and one live knowtation/search + knowtation://prime round-trip returns valid payloads. Evidence captured in the KD-5b handover matrix.

KD-5a.G — Security invariants (frozen)

  1. No secrets anywhere on the wire: HMAC key, AIR endpoint, identity PEM path, hub port internals, absolute host paths are never in results, logs, or error data (§E).
  2. Reuse existing guards: _normalise_rel_path (path escape), hooks._resolve_port + attestation._validate_endpoint_url + icp_push_hook._is_valid_canister_id (SSRF), body/response byte caps, events._has_sensitive_keys (payload scrub).
  3. Misuse-resistant verification: attest never returns a placeholder as if real; verify partial-failures are hard errors (per core.attestation contract).
  4. Bounded everything: commit walks, note reads, HTTP responses all capped (§0).
  5. Activation gate is a security control, not a convenience: it prevents non-vault repos from exposing vault write/attest tools (A(e)).

KD-5a.H — KD-5b new-work summary (no backing API today)

  • knowtation/search lexical helper (search.lexical_search) + hub vector client + fan-out merge.
  • knowtation/proposemuse hub proposal create + Knowtation Hub proposal endpoint wiring.
  • Attestation/ICP runtime registration (bootstrap_knowtation_mcp) — not in __init__.py.
  • .museignore [domain.knowtation] section (data/, .obsidian/).
  • Resource serializers: knowtation://graph, ://memory/recent, ://projects, ://vault listing.
  • prime enrichment (active_projects, suggested_next).
  • The MCP server scaffold itself: muse/mcp/server.py + muse/mcp/namespaces/knowtation.py.

Everything else (tools 2,3,5,6,7 and resources 2,3,4,8) maps to existing, tested plugin/CLI APIs.


KD-6 — MuseHub UI for Vault Repos (KD-6a contract frozen; KD-6b implementation TODO)

Goal: Domain-aware repo landing, note detail page, knowledge proposals UI, vault search.

Entry criteria: KD-1 symbols + KD-2 diff available on staging vault; KD-5 MCP tools landed (KD-5b DONE). All MET (2026-07-10).

Repo: musehub/ primarily.

Model: Thinking → Auto (KD-6a Thinking DONE — contract frozen in §KD-6a below; KD-6b Auto is NEXT).


KD-6a Contract — MuseHub Vault UI (musehub) — FROZEN 2026-07-10

Status: DONE (Thinking). This section is the frozen spec KD-6b (Auto) implements against. Do not redesign during Build. Interfaces below are the contract; the seven-tier test matrix is in §KD-6a.F. Implementation-only (KD-6b) items are tagged [KD-6b new work]. The KD-5b MCP surface (9 tools / 8 resources / 4 prompts) is a read dependency consumed as-is — do not redesign KD-5 MCP interfaces (hard stop).

Authority chain: issue #2 Phase 6 (vault-centric UI) + KD-5a frozen MCP contract (§KD-5a) + existing MuseHub UI conventions verified in tree (api/routes/musehub/ui_*.py, templates/musehub/pages/, src/scss/). Boundary rules from Scooling CROSS-REPO-COORDINATION.md apply: MuseHub enriches (version/provenance/marketplace); it does not own note bodies; Knowtation is the canonical vault store + permission authority; review-before-write; scope is authorization enforced server-side.

KD-6a.0 — Surface conventions & shared contract

  • URL scheme (reuse, do not fork): vault pages are domain-conditional branches of the existing repo route tree /{owner}/{repo_slug}/… (api/routes/musehub/ui_repo.py::repo_page + siblings), not a new /vault/… tree. Ref selection reuses the existing ?ref=<branch|sha> query param.
  • Domain activation gate (mirrors KD-5a.E — security control, not convenience): a page renders its vault variant iff the repo's active marketplace domain resolves to knowtation (_nav_ctx._resolve_repo_domain / _resolve_domain_viewer_type → domain @aaronrene/knowtation). A code/mist repo that merely contains a few notes never shows vault tabs, the note-detail variant, or the knowledge-proposal write surface. detector.classify_repo is advisory only (may power a "looks like a vault — activate?" hint), never auto-mounts.
  • Content negotiation (frozen, reuse verbatim): ?format=json or Accept: application/json → structured JSON (camelCase, by_alias); HX-Request: true → bare HTMX fragment (partial swap target); default → full SSR page. Canonical machine-readable REST lives under /api/…; UI routes are the same-URL negotiated surface (established pattern in ui_repo.py, ui_domains.py).
  • Read surface split (frozen):
    1. Note bodies, tree, commits, diffs, refs are served from MuseHub's own versioned snapshot store (services/musehub_repository, muse_cli/snapshot.py) — exactly as code repos are today. This is versioned enrichment, not body ownership; the canonical body still lives in the Knowtation vault.
    2. Domain intelligence (hybrid search, backlinks/impact, dead notes, link graph, prime, memory timeline, hotspots, history) is read from the mounted Muse domain MCP knowtation/* surface (KD-5b) — the 9 tools / 8 resources / 4 prompts, consumed as-is.
  • Adapter boundary (frozen): no Jinja template or route handler calls an MCP tool / provider SDK inline. All MCP reads go through a hub-side services/knowtation_view adapter [KD-6b new work] that (i) resolves the mounted per-repo Muse MCP server (stdio for local, hosted HTTP+SSE per KD-5a.E), (ii) issues tools/call + resources/read, (iii) normalises the JSON-RPC envelope into hub view-models, and (iv) maps MCP error reason tokens → UI states (§KD-6a.E). This is the KD-6 analog of the Scooling "no component calls a provider directly" rule.
  • Write surface (frozen — review-before-write): knowledge-proposal creation dispatches to knowtation/propose (→ Knowtation Hub proposal endpoint; scope personal|project|org enforced server-side). MuseHub renders, lists, threads, and reviews proposals via the existing proposals surface (ui_proposals.py, MusehubProposal); it never writes note bodies directly and never enforces scope in the UI layer.
  • Resilience / degradation (frozen): the MuseHub-owned data path (bodies/tree/history from the snapshot store) is independent of the MCP path. If the mounted MCP server is unavailable or a tool returns degraded=true, vault-intel panels render a non-fatal "domain intelligence unavailable" / "semantic search unavailable — showing lexical results" state; the page still renders bodies, tree, and history. A domain-intel outage is never a 5xx.
  • Error envelope: HTML → standard hub error pages (403/404/410/500) with domain-aware empty states; JSON → existing hub error shape {error:{code,message}}; MCP-sourced problems surface as the UI-state enum in §KD-6a.E, not as raw JSON-RPC errors.
  • Bounds & determinism: reuse hub cursor pagination for lists; note-body render reuses the 16 MiB cap; search/impact/history reuse the MCP tool clamps (KD-5a.0); no unbounded walks initiated from the UI.
  • Secret hygiene: never render KNOWTATION_HUB_PORT internals, air.endpoint, MUSE_AIR_HMAC_KEY, MUSE_ICP_IDENTITY_PEM, or absolute host paths in any HTML, JSON, data-* attribute, OG tag, or JSON-LD block. Attestation sig (an HMAC output) MAY render; key material MUST NOT.

KD-6a.A — Resolution of the five open UI contract items (a)–(e)

(a) Note-body rendering & sanitisation — FROZEN: server-side render, sanitised, wikilinks resolved. Markdown → HTML is rendered server-side reusing the hub's existing renderer path (the README/blob pipeline behind _ui_helpers._fetch_readme + blob.html), extended [KD-6b new work] with a Knowtation post-processor that (i) resolves [[wikilinks]] and [[wikilink#section]] to /{owner}/{repo_slug}/note/{path} (broken links get a broken class, never a raw link), and (ii) renders frontmatter as a metadata panel, never executed or reflected into script context. Raw inline HTML in note bodies is sanitised (allowlist; no <script>/event handlers) — bodies are data, not instructions (parity with KD-5a.G prompt-injection stance). Attachments/images resolve through the existing blob route; external URLs are not fetched server-side.

(b) Vault search backend — FROZEN: knowtation/search hybrid, not hub DB global_search. The vault search page calls the Muse domain MCP knowtation/search (hybrid: w_lex=0.4, w_vec=0.6, KD-5a.A(a)) through the knowtation_view adapter, with project? filter and mode toggle (hybrid|lexical|semantic). It does not reuse musehub_repository.global_search (which is commit-message keyword search, cross-repo). On degraded=true (vector backend down) the page shows lexical-only results with a banner and index_freshness. Cross-repo global search (/api/search, global_search.html) is unchanged and remains hub-DB keyword search.

(c) Proposals UI ownership split — FROZEN: MuseHub renders/reviews; Knowtation owns create+scope. MuseHub owns proposal listing, detail, review threads, comments, and section-aware diff display (reuse ui_proposals.py + proposal_detail.html; the diff panel renders the KD-2 section-aware harmony diff — tag/entity/§Summary semantics — rather than a raw text diff [KD-6b new work]: a differ-output → HTML view). Proposal creation and scope authorization are Knowtation-canonical via knowtation/propose; the "Propose edit" affordance on the note-detail page opens a form that POSTs to a thin hub route which delegates to the adapter's propose call. Scope (personal|project|org) is displayed as a badge but enforced server-side by Knowtation.

(d) Domain-intel freshness & failure isolation — FROZEN. Every vault-intel panel surfaces the MCP-reported index_freshness (or null). The MCP read path is isolated from the snapshot-store read path (§KD-6a.0 resilience): a mounted-server outage degrades only intel panels. The repo-landing intel strip reuses _ui_helpers._load_intel_strip's slot, populated for vault repos by dead/hotspots/prime [KD-6b new work] instead of the code-intel loaders.

(e) Activation semantics & viewer_type — FROZEN: gate on active domain; vault viewer_type optional. The vault UI variant mounts iff active domain == knowtation (as (§KD-6a.0) — the same gate as KD-5a.E), independent of the marketplace viewer_type. The existing ViewerType enum (symbol_graph|piano_roll|generic, api/routes/musehub/domains.py) currently classes @aaronrene/knowtation as generic. Adding a first-class vault viewer_type is an optional, deferred palette change (musehub#117 lineage) — KD-6b MUST NOT block on it and MUST NOT force an enum migration; the domain gate is the source of truth.

KD-6a.B — Page contracts (4 groups)

Legend: Store = MuseHub snapshot/DB read; MCP = knowtation_view adapter → KD-5b surface; [KD-6b new work] = net-new template/route/adapter code.

# Page group Purpose Primary sections Data sources
1 Vault repo landing (variant of repo_home.html) Domain-aware home for a knowtation repo Vault header (note count, projects, index_freshness); note tree (folders); recent memory timeline; intel strip (dead / hotspots); prime "resume here" card; clone/MCP-connect hints Store: tree, recent commits, README. MCP: knowtation://vault (listing+stats), knowtation://projects, knowtation://memory/recent, knowtation://hotspots, knowtation/dead, knowtation://prime
2 Note detail (note_detail.html [KD-6b new work]) Rendered note @ref with provenance & graph Rendered body (A(a)); frontmatter panel; symbol outline (headings/wikilinks/entities); backlinks / forward-links (impact); change history timeline; provenance/attestation strip; "Propose edit" affordance Store: body/manifest @ref, commit list. MCP: knowtation/get-note, knowtation/impact (reverse+forward), knowtation/history, knowtation://graph (neighbourhood), knowtation/attest (read-only provenance strip — no new attest issued from UI)
3 Knowledge proposals (reuse proposal_list.html + proposal_detail.html) List/review vault-note proposals; section-aware diff Proposal list (scope badges, status); detail with KD-2 harmony diff (tag/entity/§Summary); review threads/comments; scope badge; create form → propose Store: MusehubProposal rows, review/comment threads, base/proposed manifests. MCP: knowtation/propose (create only); KD-2 differ output rendered for the diff panel
4 Vault search (vault_search.html [KD-6b new work]) Hybrid vault search with project filter Query box + mode toggle (hybrid/lexical/semantic) + project filter; result cards (path, snippet, section address, score, source badge lexical/vector/both); degraded/index_freshness banner MCP: knowtation/search (A(b)); optional vault/search-synthesis prompt for an agent "synthesise" action (deferred, not required for KD-6b DoD)

KD-6a.C — Route / API contracts

All routes are content-negotiated (§KD-6a.0). New HTML routes live in a new api/routes/musehub/ui_vault.py [KD-6b new work]; proposals reuse ui_proposals.py.

# Method + Route Handler (module) Response (HTML / JSON) Notes
1 GET /{owner}/{repo_slug} ui_repo.py::repo_page (existing; branch on domain [KD-6b new work]) vault repo_home.html variant / RepoResponse+vault meta Reuses existing route; adds vault landing branch when domain==knowtation
2 GET /{owner}/{repo_slug}/note/{path:path} ui_vault.py::note_detail_page [KD-6b new work] note_detail.html / {path, ref, frontmatter, body_html, symbols, backlinks, forward_links, history, provenance, freshness} ?ref=; {path} obeys the KD-5a.0 path grammar (reject ../absolute/non-.md)
3 GET /{owner}/{repo_slug}/vault/search ui_vault.py::vault_search_page [KD-6b new work] vault_search.html / {query, mode, results[], degraded, index_freshness, backends} ?q=&mode=&project=&top_k=; rate-limited (reuse SEARCH_LIMIT)
4 GET /{owner}/{repo_slug}/vault/graph ui_vault.py::vault_graph_fragment [KD-6b new work] HTMX fragment / knowtation://graph JSON Backlink/neighbourhood panel; lazy hx-get from note detail & landing
5 GET /{owner}/{repo_slug}/vault/memory ui_vault.py::vault_memory_fragment [KD-6b new work] HTMX fragment / knowtation://memory/recent JSON Recent memory timeline strip
6 GET /{owner}/{repo_slug}/proposals · /proposals/{id} ui_proposals.py (existing; vault diff renderer [KD-6b new work]) proposal_list.html / proposal_detail.html Domain-aware diff panel (KD-2 section-aware) for vault repos
7 POST /{owner}/{repo_slug}/proposals/new (vault) ui_vault.py::create_note_proposal [KD-6b new work] redirect / {proposal_id, status, hub_url, scope} Thin delegate → adapter propose; CSRF-protected (reuse hub session/MSign); scope enforced server-side

No new canonical REST namespace is introduced for domain intelligence — the machine-readable surface for those reads is already the Muse domain MCP (knowtation/*, KD-5b). The hub UI's JSON negotiation exists for its own SSR data; agents that want raw domain intel use MCP directly.

KD-6a.D — MCP tool/resource → UI mapping (read surfaces, KD-5b consumed as-is)

KD-5b surface Kind Consumed by (page/panel) UI use
knowtation/search tool Vault search (B4) Hybrid results, mode toggle, degraded banner
knowtation/get-note tool Note detail (B2) Body @ref cross-check + symbols/content_hash (bodies primarily from store)
knowtation/history tool Note detail history timeline (B2) Per-address event timeline (event_type, agent/model)
knowtation/impact tool Note detail backlinks/forward (B2) Reverse + forward link neighbourhood by depth
knowtation/dead tool Landing intel strip (B1) Dead-note count + list panel
knowtation/prime tool Landing "resume here" card (B1) Hot notes, active projects, suggested next
knowtation/propose tool Proposal create (B3, C7) Review-before-write creation only
knowtation/attest tool Note/commit provenance strip (B2) Read-only render of existing attestation record; UI issues no new attest
knowtation/consolidate tool (not surfaced in KD-6b UI) Out-of-band; observed via memory timeline — no UI trigger in KD-6
knowtation://vault resource Landing note tree + stats (B1) Listing + VaultStats
knowtation://vault/{path}[@{ref}] resource Note detail (B2) Note payload at ref (parity with get-note)
knowtation://prime resource Landing (B1) Prime card (no-arg)
knowtation://graph resource Graph fragment (C4), note detail neighbourhood Forward/backward edges, broken links, entities
knowtation://memory/recent resource Memory fragment (C5), landing (B1) Last-20 memory events
knowtation://projects resource Landing projects panel (B1) Project → note-count/last-modified
knowtation://hotspots resource Landing intel strip (B1) Top-10 churn ranking
vault/daily-brief, vault/search-synthesis, vault/memory-session, vault/knowledge-gaps prompts Optional agent affordances (deferred) Not required for KD-6b DoD; wired only as opt-in "ask an agent" buttons if time permits

KD-6a.E — UI error / empty-state enum (stable tokens)

The knowtation_view adapter maps MCP reason tokens + hub HTTP outcomes into these stable UI states (each renders a specific empty/banner/error template, never a stack trace or secret):

UI state token Trigger (MCP reason / hub) Rendered as
VAULT_DOMAIN_INACTIVE active domain ≠ knowtation 404-style "no vault view for this repo" (gate)
NOTE_NOT_FOUND NOTE_NOT_FOUND / store miss 404 note page with tree fallback
REF_NOT_FOUND REF_NOT_FOUND Inline "unknown ref" notice, default to HEAD
PATH_INVALID / NOT_A_NOTE PATH_INVALID, NOT_A_NOTE 400 "invalid note path" (path grammar reject)
DOMAIN_INTEL_UNAVAILABLE mounted MCP server unreachable / tool timeout Non-fatal panel banner; body/tree/history still render
SEARCH_DEGRADED search degraded=true "Semantic search unavailable — lexical results" banner
PROPOSAL_SCOPE_UNAUTHORIZED SCOPE_UNAUTHORIZED 403 on create; badge + reason, no write
PROPOSE_HUB_UNREACHABLE HUB_UNREACHABLE Retryable "proposal service unavailable" notice
PROPOSE_VALIDATION_FAILED VALIDATION_FAILED Inline form validation errors
PROVENANCE_UNAVAILABLE PROVIDER_UNREGISTERED / COMMIT_NOT_FOUND Provenance strip shows "not attested" (never fake)

KD-6a.F — Seven-tier test matrix (per page group + browser E2E)

All UI tiers run in musehub (pytest tests/… + vitest/Playwright for browser E2E) against a knowtation-domain fixture repo mirroring ~/MUSE_HUB/knowtation-vault-smoke. Each row is the required minimum for KD-6b Definition of Done.

Tier Landing (B1) Note detail (B2) Proposals (B3) Vault search (B4)
1 Unit Domain-gate branch selects vault variant; view-model assembly from mocked adapter; empty-vault render Wikilink/frontmatter render + sanitisation (A(a)); symbol outline; path-grammar validation Scope-badge render; harmony-diff view-model from mocked KD-2 differ; create-form validation Query/mode/project param parse; result-card view-model; degraded banner logic
2 Integration Route → knowtation_view adapter → live KD-5b tools on fixture (vault/projects/memory/hotspots/dead/prime) note/{path} → store body + get-note/impact/history/graph compose correctly list/detail → MusehubProposal + KD-2 diff; create → adapter propose (stubbed hub) search page → knowtation/search hybrid on fixture; project filter
3 E2E (browser) Playwright: load vault landing, tree + intel strip visible Navigate note → backlinks → linked note; history expands Open proposal → diff renders → add review comment Type query → results render → click result → note detail
4 Stress 5k-note vault landing within perf budget; tree pagination bound note detail with 500-commit history + large backlink set proposal list pagination; large section-aware diff search over 5k vault; rapid query debounce; vector-timeout path
5 Data-integrity tree/stats match store; index_freshness == MCP report rendered body content_hash matches store; history event_type parity vs events.EVENTS_SCHEMA_HASH; provenance record matches attest diff reflects true base↔proposed; scope badge matches server decision results cite only real note paths (no fabricated); scores in [0,1]
6 Performance landing SSR < 2 s on 5k vault (reuse repo-home budget) note detail < 2 s incl. impact/history proposal detail render < 2 s search round-trip < 2 s hybrid (lexical < 1 s + 2 s vector timeout)
7 Security activation gate blocks vault tabs on domain≠knowtation; no secret in HTML/JSON/OG/JSON-LD path-traversal reject on note/{path}; markdown/wikilink XSS-sanitised; bodies-as-data scope enforced server-side (UI cannot bypass); CSRF on create; review actions authz rate-limit (SEARCH_LIMIT); query injection-safe; degraded never leaks internals

Browser integration test (required, Tier 3/E2E): a Playwright run against the fixture vault repo that (i) loads the vault landing and asserts tree + intel strip + prime card, (ii) opens a note detail and asserts rendered body + backlinks + history, (iii) runs a vault search and clicks through a result, and (iv) opens a knowledge proposal and asserts the section-aware diff renders. Evidence captured in the KD-6b handover matrix (analog to the KD-5b Claude Desktop test).

KD-6a.G — Security invariants (frozen)

  1. Activation gate is a security control: vault write/proposal/attest surfaces never appear on a non-knowtation repo (§KD-6a.0, .A(e)).
  2. Bodies are data, not instructions: server-side markdown sanitisation (allowlist), wikilink resolution never emits executable content, frontmatter never reflected into script context (A(a)).
  3. No secrets on the wire: hub port internals, AIR endpoint, HMAC key, identity PEM path, absolute host paths never in HTML/JSON/data-*/OG/JSON-LD (§KD-6a.0). Attestation sig MAY render; key material MUST NOT.
  4. Scope is server-side authorization: the UI displays scope but never enforces it; propose scope + all durable writes are authorised by Knowtation (SCOPE_UNAUTHORIZED → 403).
  5. Path grammar reuse: note/{path} reuses the KD-5a.0 path escape rules (reject .., absolute, non-note extensions) before any store/MCP read.
  6. CSRF + rate limits: proposal-create POST is CSRF-protected via the existing hub session/MSign path; search reuses SEARCH_LIMIT.
  7. Failure isolation: a mounted-MCP outage degrades intel panels only and never a 5xx (§KD-6a.0); provenance never renders a placeholder as if real (PROVENANCE_UNAVAILABLE).

KD-6a.H — KD-6b new-work summary (net-new vs reused)

Net-new [KD-6b new work]:

  • services/knowtation_view adapter (MCP mount resolution + envelope normalisation + error mapping).
  • api/routes/musehub/ui_vault.py (note detail, vault search, graph/memory fragments, proposal-create delegate).
  • templates/musehub/pages/note_detail.html + vault_search.html; vault variant of repo_home.html; SCSS (_note-detail.scss, _vault.scss; reuse _repo-home.scss, _search.scss, _diff.scss, _proposals.scss).
  • Markdown+wikilink+frontmatter Knowtation post-processor with sanitisation (A(a)).
  • KD-2 section-aware harmony-diff → HTML renderer for the vault proposal detail (A(c)).
  • Vault intel-strip loader (dead/hotspots/prime) filling the existing _load_intel_strip slot (A(d)).
  • Playwright browser E2E fixture + suite (§KD-6a.F).

Reused as-is: repo route tree + content negotiation (ui_repo.py); domain resolution (_nav_ctx); proposals list/detail/threads (ui_proposals.py, MusehubProposal); snapshot/manifest store (services/musehub_repository, muse_cli); blob/README render pipeline; rate limits; the entire KD-5b MCP surface (9 tools / 8 resources / 4 prompts — not redesigned).


KD-7 — Attestation (done locally, verification pending)

Goal: HMAC attestation, ICP push hook, verify-commit --attest, provenance strip on Hub.

Deliverables (verified in tree): attestation.py, icp_push_hook.py, quorum.py

Exit criteria: Attestation smoke on staging vault with --attest flag (post KD-ACTIVATE).


Open questions (issue #2 — resolved in KD-OQ, 2026-07-10)

All five closed. Each decision is grounded in shipped plugin source (not a guess); the "Evidence" column cites the file that already implements or constrains the choice.

# Question Options (summary) Decision Evidence
1 Vault detection boundary Frontmatter-only vs require .knowtation / config/local.yaml marker DECIDED — Detector is frontmatter fingerprint primary; .knowtation marker is an optional override (not required). Note (verified): the detector classifies; a repo's active domain is still set explicitly via muse init --domain knowtation.muse/repo.json, so detection informs classification rather than auto-activating a repo. Marker is an escape hatch for sparse-frontmatter vaults. detector.py classify_note rules 1–4 (frontmatter) + classify_repo rule A (marker, conf 1.0) → rule B (majority ≥0.50) → rule C (mist); activation via repo.json
2 Vector index ownership Muse parallel index vs query Knowtation data/ index directly DECIDED — Split by capability. Muse owns structural/lexical intel — link graph, symbols, hotspots from live-vault parsing (build_link_index/code_intel), plus commit-graph history/hot-notes (prime_context); Knowtation's live data/ vector index stays canonical for semantic search (queried at HEAD, not rebuilt or versioned by Muse). Muse surfaces index_freshness (mtime of data/) so agents know vector recency. KD-5a must resolve: whether data/ needs .museignore (today only .knowtation is always-ignored) and the knowtation/search fan-out/ranking. link_index.py build_link_index(root) + code_intel.py walk live files; prime_context.py walks commit graph; stats.py reads data/ mtime only ("no vector store"); plugin.py _ALWAYS_IGNORE_DIRS excludes .knowtation (not data/)
3 Consolidation daemon coupling muse merge --consolidate pre-hook vs async watcher DECIDED — Pre-merge hook that dispatches asynchronously. --consolidate is the explicit opt-in trigger (default off); execution is fire-and-forget background POST to the local hub daemon so merge never blocks on LLM/network latency. Hook errors are caught by the merge CLI and the registry, so they never fail the merge. hooks.py KnowtationMergeHook.pre_merge_hook (default consolidate=False) → _post_consolidate_in_background, out_of_band=True; auto-registered at import via __init__.py
4 ICP canister reuse Knowtation Motoko canister vs generic Muse attestation interface DECIDED — Both layers: generic MuseAttestationProvider interface in core, implemented by the knowtation plugin, which REUSES the existing Knowtation Motoko canister (dejku-syaaa-aaaaa-qgy3q-cai) + AIR HMAC daemon. No new ICP infra. Note (verified): the interface + implementation + registration helpers exist, but only the merge hook is auto-registered at import today — wiring the attestation provider / ICP push hook into the runtime commit/push path is KD-5a/5b work. core MuseAttestationProvider protocol + registry; attestation.py KnowtationHmacAttestationProvider, icp_push_hook.py KnowtationICPPushHook; helpers register_knowtation_attestation_provider / _icp_push_hook (not yet called in __init__.py); canister-ID SSRF guard
5 SKILL.md agent discovery Merge into Muse agent.md vs keep separate DECIDED — Keep separate. muse agent-config stays a canonical (.muse/agent.md) → derived-adapter generator; it does NOT auto-discover/inline product SKILL.md files. Optional (prospective, not built): a reference pointer to the skill when a knowtation domain is detected — no content merge. cli/commands/agent_config.py source→adapter model (_ADAPTERS, run_sync); no SKILL.md scan exists; SKILL.md owned by product .cursor/skills/ (11 files)

Downstream effect on KD-5a: these answers freeze the MCP contract's search ownership split (OQ2), consolidate coupling (OQ3 async dispatch), attest architecture (OQ4 generic interface + canister reuse), and confirm no agent.md merge work (OQ5). Contract-level detail the decisions deliberately left to the contract — (a) knowtation/search fan-out algorithm/weights/dedupe/timeout; (b) knowtation/consolidate return schema; (c) knowtation/attest runtime registration + required-mode; (d) whether Muse must .museignore data/; (e) MCP-scope activation semantics — is now RESOLVED and frozen in §KD-5a Contract (KD-5a.A), 2026-07-10.


Cross-repo coordination (read-only pointers)

Document Repo Purpose
docs/CROSS-REPO-COORDINATION.md scooling SD-8 namespace decision; canonical-first ordering
docs/KNOWTATION-MUSEHUB-WIRING.md scooling How Scooling will consume domain features long-term
docs/VERIFICATION-MATRIX.md scooling Source-backed facts on plugin manifest
musehub/docs/issues/custom-domain-registration.md musehub Marketplace URL + author-identity hardening notes

Scooling Phase 1 rule: must not require live MuseHub or production Knowtation Domain. Domain activation does not block Scooling Phase 9A.


Governance hygiene (manual until orchestrator is live)

At session end for any KD phase:

  1. Update this file — build status table, "Next step at a glance", phase Status lines.
  2. Update docs/MUSEHUB-OVERSEER-HANDOVER.md — rotate NEXT SESSION, verified snapshot, VCS table, change log, paste-ready prompt.
  3. Muse commit on feature branch (Tier 1); staging push / merge to main only with Tier 3 authorization.
  4. Run test suite for touched areas before commit.

A session that ends without both governance docs updated is incomplete.

Orchestrator: The cross-workspace overseer orchestrator (Scooling session) is not required for this track yet. Use these two docs manually until that tooling ships.


Verified snapshot (2026-07-10)

Fact Source
Plugin path ~/MUSE_HUB/gabriel-muse/muse/plugins/knowtation/ — 26 .py files
Test files ~/MUSE_HUB/gabriel-muse/tests/test_knowtation_*.py — 27 files
Last full-suite count 1570 passed, 0 failed (2026-06-20 recovery)
Staging plugin repo https://staging.musehub.ai/aaronrene/gabriel-muse — HTTP 200
Marketplace listing @aaronrene/knowtation — version 1.0.0, 6 dimensions, install_count: 0
Test vault ~/MUSE_HUB/knowtation-vault-smoke — 3 notes, domain=knowtation, Harmony policies
Issue tracker gabriel/muse #2 — assigned aaronrene
OQ resolution basis Shipped plugin source — detector.py, link_index.py, stats.py, hooks.py, attestation.py, icp_push_hook.py, cli/commands/agent_config.py

Change log

  • 2026-07-10KD-6a DONE (Thinking). Froze the MuseHub vault UI contract for the musehub repo (§KD-6a Contract): 4 page groups (vault repo landing, note detail, knowledge proposals, vault search) with page/route/MCP-mapping/error-enum tables and a seven-tier test matrix + required Playwright browser E2E. Resolved five open UI contract items: (a) server-side sanitised markdown+wikilink+frontmatter render (bodies-as-data); (b) vault search = knowtation/search hybrid (not hub-DB global_search), lexical-degrade banner; (c) proposals ownership split — MuseHub renders/reviews (KD-2 section-aware harmony diff), Knowtation owns create + server-side scope via knowtation/propose; (d) domain-intel freshness + MCP/store read-path failure isolation (intel outage never 5xx); (e) activation gate on active domain==knowtation (not viewer_type), vault viewer_type deferred/optional. Frozen conventions: reuse /{owner}/{repo_slug} route tree + content negotiation; no template calls MCP inline — hub-side services/knowtation_view adapter boundary; KD-5b MCP surface (9 tools / 8 resources / 4 prompts) consumed as-is (no redesign). Flagged KD-6b new work (adapter, ui_vault.py, note_detail.html/vault_search.html, markdown post-processor, KD-2 diff renderer, vault intel-strip loader, Playwright suite). Muse commit on feat/kd-6a. NEXT → KD-6b (Auto).
  • 2026-07-10KD-5b DONE (Auto). Implemented the frozen §KD-5a MCP domain surface: muse/mcp/server.py + muse/mcp/namespaces/knowtation.py with activation gate (repo.json domain==knowtation), bootstrap_knowtation_mcp (attestation + ICP hook registration), search.lexical_search + vector client + hybrid fan-out, hub propose, resource serializers, prime enrichment, 4 vault prompts, stdio entry (python -m muse.mcp.stdio_server). Seven-tier test matrix: 36 tests in tests/test_knowtation_mcp_*.py + Claude Desktop stdio integration against knowtation-vault-smoke (9 tools / 8 resources / 4 prompts list + search/prime round-trip). Full knowtation suite: 1606 passed. Muse commit on feat/kd-5b. NEXT → KD-6a (Thinking).
  • 2026-07-10KD-5a DONE (Thinking). Froze the Muse MCP domain-surface contract for the knowtation namespace (§KD-5a Contract): 9 tools, 8 resources, 4 prompts — each with JSON-RPC input/output schema, backing plugin API mapping, and error-reason enum. Resolved the five open contract items: (a) search fan-out w_lex=0.4/w_vec=0.6, path dedupe, 2 s vector timeout → lexical-only degraded; (b) consolidate dispatch-receipt schema, async completion observed via memory/recent; (c) attest runtime registration via bootstrap_knowtation_mcp (not __init__.py), air.required mode, PROVIDER_UNREGISTERED structured error; (d) .museignore [domain.knowtation] ignores data/ for snapshots while stats still reads its mtime; (e) namespace mounts only on .muse/repo.json domain==knowtation, detector advisory. Specified the muse/mcp/ mount point (server + knowtation namespace, both KD-5b new work) and musehub stdio/SSE hosting. Defined the seven-tier test matrix + Claude Desktop integration test against knowtation-vault-smoke. Flagged KD-5b new work (search lexical+vector, propose→hub, attest registration, resource serializers, MCP server scaffold). Muse commit on feat/kd-5a. NEXT → KD-5b (Auto).
  • 2026-07-10KD-OQ review pass (independent model, read-only). Verified all 5 decisions against source; decisions stand. Corrected: prompt count 3→4 (issue #2 Phase 5.3) and KD-5 tool list now includes consolidate (9 tools); tightened OQ1 (detector classifies; activation via repo.json), OQ2 (link_index/code_intel are live-file, not commit-snapshot; data/ not auto-ignored), OQ4 (registration helpers exist but only the merge hook auto-registers — runtime wiring is KD-5a/5b). Added explicit KD-5a open contract items (search fan-out, consolidate return schema, attest wiring, data/ ignore, activation semantics).
  • 2026-07-10KD-OQ DONE. All 5 issue #2 open questions resolved with source-backed rationale (see table). Decisions: OQ1 frontmatter-primary + optional .knowtation marker; OQ2 Muse structural index + Knowtation live vector index (split); OQ3 async-dispatch pre-merge hook; OQ4 generic MuseAttestationProvider reusing the ICP canister; OQ5 keep SKILL.md separate. NEXT → KD-5a (MCP contract, Thinking).
  • 2026-07-10KD-ACTIVATE DONE. Vault knowtation-vault-smoke activated; smoke 5 PASS / 3 PARTIAL. NEXT → KD-OQ. CLI gaps documented (merge dispatch, symbols routing, diff granularity).
  • 2026-07-10 — Initial MuseHub Roadmap created. Phases 1–4 + 7 marked DONE (local); KD-ACTIVATE set as NEXT.
File History 1 commit
sha256:cf6265cea8c21d9228d90dec13ef6ec2dab5103d466db9cc4590681832de4bf8 docs(KD-STAGING): sync governance after KD-6b DONE Human 13 days ago