Skip to content

feat(mcp): capability-family taxonomy + substrate both-faces preset (one substrate, two faces)#217

Merged
clay-good merged 20 commits into
mainfrom
feat/unify-navigation-governance-substrate
Jun 27, 2026
Merged

feat(mcp): capability-family taxonomy + substrate both-faces preset (one substrate, two faces)#217
clay-good merged 20 commits into
mainfrom
feat/unify-navigation-governance-substrate

Conversation

@clay-good

@clay-good clay-good commented Jun 27, 2026

Copy link
Copy Markdown
Owner

What & why

Implements the unify-navigation-and-governance-substrate change. OpenLore's ~72 MCP tools had grown into a flat registry that read like two bolted-together products (navigation vs. governance/memory). This change names the shared spine — one structural substrate with two faces — and turns it into enforceable structure, with no new tool, no new dependency, no LLM, no persisted artifact.

Grounded in the north star (overview/spec.md, decision c6d1ad07): deterministic, locally-computed structural context, conclusion over graph.

What changed

  • Capability-family taxonomy (mcp-quality CapabilityFamilyTaxonomy). Every tool declares exactly one of six closed families — navigate · change · remember · verify · coordinate · federate — in TOOL_CAPABILITY_FAMILY (tool-contract.ts), parallel to the existing TOOL_OUTPUT_CLASS. The family is emitted in each tool's MCP annotations.family, so the full surface is discoverable by family on the wire.
  • Grouped rendering — three surfaces. annotations.family (machine-readable, on the wire); openlore mcp --list-tools (human-facing CLI — renderToolSurfaceByFamily()/renderActiveToolSurface() over groupToolsByFamily(), respects --preset/--all-tools, exits without starting the transport); and the docs Capability families section.
  • substrate both-faces preset. The navigation graph-traversal core plus the three highest-value governance readsrecall, verify_claim, blast_radius (reads only; no remember/record_decision write, no commit gate).
  • Evidence-gated default (ADR-0022). The active out-of-box default stays navigation; substrate ships as a selectable preset and flips to default only when an agent benchmark shows no regression. The flip is a one-line LEAN_DEFAULT_PRESET change, intentionally deferred to that benchmark run.
  • No redundant conclusions (mcp-quality NoRedundantConclusions). The four genuinely-adjacent tool groups are not merged; each names its near-sibling in its own description, enforced by ADJACENT_TOOL_GROUPS:
    • blast_radiusstructural_diffchange_impact_certificate
    • plan_parallel_workmap_in_flight_conflicts
    • find_clonesget_duplicate_report
    • report_coverage_gapsselect_tests
  • architecture UnifiedStructuralSubstrate spec (one graph / one anchored-fact store / one freshness lease; read-face vs write-face).
  • CI guards in tool-contract.test.ts: family completeness + closed-set + no-stale, plus the distinct-question cross-reference check.
  • Payload budgets bumped consciously (full 84_000 → 86_000, nav 13_300 → 13_700) for the family annotation key. Docs size figure updated (~83 KB / ~21k tokens).
  • Docs: README, CLAUDE.md, docs/mcp-tools.md, docs/install.md, docs/cli-reference.md, docs/agent-setup.md document the substrate preset, the six families, and --list-tools.

Adversarial review passes

Two rounds of multi-agent adversarial audit (family-assignment correctness, doc completeness, Pi-extension parity, annotation-consumer safety) drove hardening:

Round 1

  • Family-assignment audit: taxonomy sound, 0 hard errors. Moved check_spec_drift changenavigate so it shares a family with its spec↔code-parity sibling audit_spec_coverage; change is now cleanly diff-scoped. navigate 52→53, change 7→6.
  • Closed the taxonomy's missing production consumer: added openlore mcp --list-tools (groupToolsByFamily was exported + tested but rendered nowhere).
  • Fixed stale/incomplete preset enumerations in openlore install (was "all 62 tools", missing substrate/coordination) and openlore serve. Verified install/serve accept --preset substrate (validate dynamically against TOOL_PRESETS).

Round 2

  • Test gap closed: the --list-tools option registration and the startMcpServer short-circuit were untested in CI (only the pure renderer was). Extracted renderActiveToolSurface() (selection ∘ grouping; throws on unknown preset) and added tests for multi-family grouping (minimal → navigate+change+remember), unknown-preset throw (→ exit 2, never starts the server), and the mcpCommand --list-tools registration guard.
  • Pi-extension parity: verified genuinely moot — NAV_TOOLS is a native curated superset of substrate, and family/preset/breadth are MCP-wire concepts the Pi host never emits or consumes. Refreshed the extension.ts header comment to post-taxonomy vocabulary (doc-only).
  • Annotation-consumer safety: audited every reader/serializer of MCP annotations (presets/size-figure/conformance tests, agent-eval scorecard, serve). Adding family is safe everywhere; the two byte-size guards were already bumped for it.
  • Deliberately NOT changed: openlore serve /health reports tool names as a flat array — advisory only, nothing consumes family there; adding it would be speculative. Discoverability is delivered by the wire annotations + --list-tools + docs.
  • Consolidated openspec/specs/{architecture,mcp-quality} are intentionally not hand-edited — this repo consolidates change-dir deltas at archive time (verified).

Verification

  • npm run build clean; tsc --noEmit clean; eslint clean on changed files.
  • Full suite green: vitest run src examples → 279 files / 5531 passed, 2 skipped.
  • e2e dogfood: --list-tools across every preset (navigation 10/1-family, substrate 13/4, minimal 6/3, memory 3/2, federation 10/4, coordination 5/2, full 72/6 — correct grouping + pluralization); install --preset substrate accepted, --preset bogus rejected (error lists substrate); bogus --list-tools exits 2 without starting the server; live stdio tools/list carries annotations.family on all 72 tools across 6 families.

Notes / follow-ups

  • Active default unchanged by design — flipping to substrate awaits a benchmark run (tracked in the change's tasks.md).
  • Pi parity intentionally skipped (behavior) per the above — only a doc-comment refresh was warranted.

🤖 Generated with Claude Code

clay-good and others added 20 commits June 26, 2026 23:32
…one substrate, two faces)

Implements the unify-navigation-and-governance-substrate change: turns the ~72-tool
surface from a flat registry into one discoverable-by-family substrate.

- TOOL_CAPABILITY_FAMILY (tool-contract.ts): every tool declares one of six closed
  families (navigate/change/remember/verify/coordinate/federate), parallel to
  TOOL_OUTPUT_CLASS. Emitted in each tool's MCP annotations.family so the full
  surface is groupable on the wire; groupToolsByFamily() helper for docs/help.
- substrate preset: navigation core + recall + verify_claim + blast_radius (both
  faces, governance READS only). Active default stays navigation; substrate flips
  to default only on benchmark evidence (ADR-0022) — shipped as a selectable preset.
- NoRedundantConclusions: ADJACENT_TOOL_GROUPS + sibling cross-references on the
  four adjacent groups (blast_radius/structural_diff/change_impact_certificate,
  plan_parallel_work/map_in_flight_conflicts, find_clones/get_duplicate_report,
  report_coverage_gaps/select_tests).
- tool-contract.test.ts guards: family completeness/closed-set/no-stale +
  distinct-question cross-reference. Payload budgets bumped consciously
  (full 84_000->86_000, nav 13_300->13_700) for the family annotation key.
- Docs: CLAUDE.md + docs/mcp-tools.md grouped-by-family section + substrate preset.

Build clean; vitest run src examples green (279 files / 5525 tests); e2e-dogfooded
over a live stdio tools/list (all 72 tools carry annotations.family across 6
families; substrate resolves to 13 both-faces tools).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ng (PR #217 review pass)

Adversarial review of the capability-family taxonomy surfaced gaps; this pass closes them.

- mcp --list-tools: prints the active surface grouped by capability family and exits
  (renderToolSurfaceByFamily over groupToolsByFamily). This is the human-facing
  production consumer of the taxonomy — previously groupToolsByFamily was exported and
  tested but rendered nowhere; the spec's "discoverable by family" now has a CLI surface
  beyond the on-the-wire annotations.family and the static docs. Respects --preset/--all-tools;
  bogus preset exits 2 without starting the transport.
- Family-assignment audit fix: moved check_spec_drift change -> navigate so it shares a
  family with its spec<->code-parity sibling audit_spec_coverage; `change` is now cleanly
  diff-scoped (detect_changes stays). navigate 52->53, change 7->6, total unchanged.
- Stale/incomplete preset enumerations fixed: openlore install help ("all 62 tools",
  missing substrate/coordination) and openlore serve advisory help now list substrate.
  Verified install/serve accept --preset substrate (both validate dynamically against
  TOOL_PRESETS).
- Docs: README + docs/install.md + docs/cli-reference.md document the substrate preset,
  the six capability families, and --list-tools.
- Tests: +3 renderToolSurfaceByFamily cases (grouping/coverage, pluralization, all-six).

Build/typecheck/lint clean; vitest run src examples green (279 files / 5528 tests);
e2e-dogfooded: --list-tools across presets, install accept/reject, exit codes, stdio
annotations.family on all 72 tools after the check_spec_drift move.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ty + docs)

Second adversarial review pass (Pi-parity + annotation-consumer audits) found one real
test gap and two minor doc/comment refinements; this closes them.

- Test gap: the `--list-tools` option registration and the startMcpServer short-circuit
  were untested in CI — only the pure renderToolSurfaceByFamily was. Extracted
  renderActiveToolSurface() (selection ∘ family-grouping; throws on unknown preset, like
  selectActiveTools) so the composition is unit-testable, and the short-circuit is now thin
  glue over it. Added: multi-family grouping (minimal → navigate+change+remember), unknown
  preset throws (→ exit 2, never starts the server), and an mcpCommand --list-tools option
  registration guard (mirrors the existing --minimal/--preset guards).
- Pi parity: confirmed genuinely moot (NAV_TOOLS is a native curated superset of `substrate`;
  family/preset/breadth are MCP-wire concepts the Pi host never emits or consumes). Refreshed
  the extension.ts header comment to the post-taxonomy vocabulary (doc-only; no behavior).
- Docs: agent-setup.md (the deferred full-surface + Tool Search doc) now notes the six
  capability families + `--list-tools`, where family discoverability is most relevant.
- Deliberately NOT changed: serve /health reports tool names as a flat array — advisory only,
  nothing consumes family there; adding it would be speculative (discoverability is delivered
  by the MCP wire annotations + --list-tools + docs).

Build/typecheck/lint clean; vitest run src examples green (279 files / 5531 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…es.ts (slice 1/5)

First safe slice of modularize-call-graph-builder, behind the stable barrel. Moves the
TYPES section (edge/node/class model, CallGraphResult/SerializedCallGraph, CALL_DISTANCE_COSTS,
callDistance, layerOf, classifyLayerEdge) out of the 5,425-line call-graph.ts into a new
dependency-light call-graph-types.ts. call-graph.ts re-exports every public name, so none of
the 155 importers move; RawEdge and CALL_DISTANCE_FALLBACK stay internal (off the surface).
call-graph.ts: 5,425 → 5,150 lines.

Behavior-preserving, verified four ways:
- Byte-level snapshot oracle (multi-language CallGraphBuilder.build() + the moved pure helpers,
  serialized canonically + SHA-256'd) hashes IDENTICALLY before/after: 131ba4c6…
- Public export surface byte-for-byte identical (multi-line-aware diff of call-graph.ts exports).
- tsc compiles all 155 importers clean; build/lint/typecheck green.
- Full suite green: 279 files / 5531 tests.

New `stable call-graph barrel` test locks the invariant (re-export identity === source binding +
moved-helper behavior) so the remaining slices (nodes/extract/dispatch/grammar-loader) can't
silently break the surface. No feature, no dependency, no LLM, no persisted artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ph-extract.ts (slice 3)

Next safe slice of modularize-call-graph-builder. Moves the DOCSTRING / SIGNATURE
EXTRACTION HELPERS section (extractDocstringBefore, extractDeclaration) out of
call-graph.ts into call-graph-extract.ts — two pure string-scanning functions with
zero dependency on the rest of the analyzer (no tree-sitter, no module state).

They were file-internal helpers (never on call-graph.ts's public surface), so they
are imported back, NOT re-exported — the public import surface is unchanged.
Taken before slice 2 as the safest small slice. call-graph.ts: 5,150 → 4,951 lines.

Behavior-preserving, verified four ways:
- Snapshot oracle FIRST strengthened to serialize each node's docstring + signature
  (fixture now has a JSDoc'd TS fn, an exported async fn, and a Python docstring +
  annotated signature, so both moved functions are exercised across TS and Python),
  then captured before/after: IDENTICAL — SHA-256 58107ac0…
- Public export surface byte-identical (multi-line-aware diff: 0 added, 0 removed).
- tsc compiles all importers clean; build/lint/typecheck green.
- Full suite green: 279 files / 5534 tests.

No feature, no dependency, no LLM, no persisted artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rnal.ts (slice 3b)

Next safe slice of modularize-call-graph-builder. Moves the EXTERNAL NODE HELPER
section (classifyExternal, the EXTERNAL_* regex/set tables, getOrCreateExternalNode)
out of call-graph.ts into call-graph-external.ts — pure external-call classification
+ leaf-node interning, depending only on the ExternalKind/FunctionNode types.

All file-internal helpers (never on call-graph.ts's public surface): only
getOrCreateExternalNode is imported back; classifyExternal + the tables stay private
to the new module. Dropped the now-unused internal ExternalKind import (it is still
re-exported on the barrel — surface unchanged). call-graph.ts: 4,951 → 4,887 lines.

Behavior-preserving, verified four ways:
- Snapshot oracle first extended to exercise external nodes across externalKind
  http/db/unknown, then captured before/after: IDENTICAL — SHA-256 3a118017…
- Public export surface byte-identical (multi-line-aware diff: 0 added, 0 removed;
  ExternalKind still exported).
- tsc compiles all importers clean; build/lint/typecheck green.
- Full suite green: 279 files / 5534 tests.

No feature, no dependency, no LLM, no persisted artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-graph-complexity.ts (slice 3c)

Next safe slice of modularize-call-graph-builder. Moves the CYCLOMATIC COMPLEXITY
section (computeCyclomaticComplexity + the CC_PATTERN_* regex tables) out of
call-graph.ts into call-graph-complexity.ts — a pure, dependency-free McCabe estimator.

computeCyclomaticComplexity was exported from call-graph.ts (though no external
importer today), so it is imported back AND re-exported on the barrel to preserve
the public surface exactly; the CC_PATTERN_* tables stay private to the new module.
call-graph.ts: 4,887 → 4,879 lines.

Behavior-preserving, verified four ways:
- Snapshot oracle first extended to exercise cyclomaticComplexity > 1 (branchy TS +
  Python fixtures: risky cc=5, handler cc=3), then captured before/after: IDENTICAL —
  SHA-256 7b765f31…
- Public export surface byte-identical (0 added, 0 removed; computeCyclomaticComplexity
  still exported).
- tsc compiles all importers clean; build/lint/typecheck green.
- Full suite green: 279 files / 5534 tests.

No feature, no dependency, no LLM, no persisted artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (slice 3d)

Next safe slice of modularize-call-graph-builder. Moves the CFG / DATA-FLOW OVERLAY
HELPER section (buildCfgFor) out of call-graph.ts into call-graph-cfg.ts — a pure,
fail-soft wrapper around buildFunctionCfg (./cfg.js) that body-resolves a declaration
wrapper (const-arrow, decorated-Python def) before building the per-function CFG
overlay.

File-internal (referenced only in test COMMENTS, never imported), so imported back,
NOT re-exported — surface unchanged. Dropped the now-unused buildFunctionCfg import
from call-graph.ts (FunctionCfg/CfgNode still used). call-graph.ts: 4,879 → 4,846 lines.

Behavior-preserving, verified four ways:
- Snapshot oracle FIRST extended to serialize the full per-function `cfgs` overlay
  (blocks/edges/defUse/params) and to exercise buildCfgFor's body-digging via an
  arrow-assigned-to-const and a decorated Python def; then captured before/after:
  IDENTICAL — SHA-256 34c7bce5…
- Public export surface byte-identical (0 added, 0 removed).
- tsc compiles all importers clean; build/lint/typecheck green.
- Full suite green: 279 files / 5534 tests.

call-graph.ts is now 5,425 → 4,846 lines across five extracted sibling modules
(types, extract, external, complexity, cfg). No feature, no dependency, no LLM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-graph-builtins.ts (slice 3e)

Next safe slice of modularize-call-graph-builder. Moves the callee-filtering sub-part
of the grab-bag CONSTANTS section (the *_IGNORED per-language tables,
IGNORED_BY_LANGUAGE / ALL_IGNORED_CALLEES, isIgnoredCallee, SELF_CALL_RECEIVERS,
isSelfReceiver) out of call-graph.ts into call-graph-builtins.ts — pure data + string
predicates, zero deps, zero state. The safest remaining slice (no module state, no
re-export juggling).

File-internal: only the two predicates (isIgnoredCallee, isSelfReceiver) are imported
back; the *_IGNORED tables stay private. HUB_THRESHOLD and the style-tally helper stay
put (different concerns). call-graph.ts: 4,846 → 4,741 lines.

Behavior-preserving, verified four ways:
- Snapshot oracle FIRST extended with ignored-builtin calls (print/len/JSON/Math) so
  isIgnoredCallee's drop-or-keep outcome is captured (print/len/JSON dropped as ignored;
  Math.max kept), then captured before/after: IDENTICAL — SHA-256 5fbe0719…
- Public export surface byte-identical (0 added, 0 removed).
- tsc compiles all importers clean; build/lint/typecheck green.
- Full suite green: 279 files / 5534 tests.

call-graph.ts is now 5,425 → 4,741 lines across six extracted sibling modules
(types, extract, external, complexity, cfg, builtins). No feature, no dependency, no LLM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… slices won't-do / deferred

Records the scope decision for the call-graph modularization. The change is now
SUBSTANTIALLY COMPLETE and intentionally bounded: the StableCallGraphBarrel invariant
plus a proven, byte-identical-verified extraction methodology is satisfied (demonstrated
six times). call-graph.ts: 5,425 → 4,741 lines across six sibling modules
(types, extract, external, complexity, cfg, builtins).

Remaining candidates deliberately not taken, on a value-vs-risk basis:
- call-graph-nodes.ts — WON'T DO. 27-fan-in hub + mutable CFG side-table + IaC coupling;
  low-churn core machinery (little merge-contention value) and the highest-risk code in
  the file (a CFG side-table regression already occurred here). Net-negative ROI.
- grammar-loader.ts — DEFERRED. Not the clean leaf the illustrative table implied: grammar
  loading is two subsystems split ~1,500 lines apart (native singletons/getters + a
  _grammarHandleCache handle system), coupled by the shared __resetGrammarCacheForTests
  reset a test imports. A two-location stateful job, not a small slice.
- call-graph-dispatch.ts — DEFERRED. Largest/highest-churn section (dispatch synthesis);
  best future payoff but needs the oracle extended to synthesized edges first.

The barrel pattern + snapshot-oracle recipe are documented, so any deferred extraction can
be picked up opportunistically later — the trigger this proposal always wanted. Doc-only;
no source change (code byte-identical to the last CI-green commit).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…→ 4,745, wc -l)

Final adversarial review pass found one inaccuracy: the proposal's headline undercounted
the post-refactor call-graph.ts by 4 lines. True size is 4,745 (`wc -l`), so the net is
−680, not −684 — the difference is the import-back lines re-added at the top of the barrel
after each slice's assembly count. Corrected the headline and noted that the per-slice
figures are the post-extraction assembly snapshots (which match the commit messages).

Doc-only; no source change. Verified this pass: full suite green (279 files / 5534 tests);
real `openlore analyze` e2e over the whole repo exit-0 with sane artifacts; public export
surface byte-identical to origin/main (23 names, 0 added/removed); 6 new modules acyclic
with no dead code; substrate feature live (substrate 13/4 families, full 72/6 families, all
72 tools carry annotations.family).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…EADME demo

Stages the v2.1.4 release (cut the tag after merge):
- Bump package.json + package-lock.json (root + packages['']) 2.1.3 → 2.1.4. The CLI and
  MCP server read the version from package.json, so both report 2.1.4 automatically.
- CHANGELOG: convert [Unreleased] → [2.1.4] (2026-06-27) with a summary; add the PR #217
  items (capability-family taxonomy + substrate preset + --list-tools in Added; call-graph
  modularization in Changed); fresh empty [Unreleased]; Full Changelog compare link.
- New RELEASE-v2.1.4.md narrative covering everything since v2.1.3 (PRs #183#217): the
  substrate unification, the call-graph split, the new conclusion tools, substrate-correctness
  work, onboarding/distribution, new IaC + cross-service coverage, and Pi parity.
- README: replace the top demo with a REAL terminal recording (charmbracelet/vhs) of the
  actual `openlore` CLI on this repo — `openlore --version` → `orient --task` (relevant
  functions + insertion points, no API key) → `mcp --list-tools` grouped by capability family.
  Updated alt-text/caption to match; tests badge 5400+ → 5500+.

Everything additive and backward-compatible; deterministic and local-first (no LLM in any
serving path). Build/lint/typecheck clean; full suite green (279 files / 5,534 tests);
doc-count + version guards pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… auto-recorded

Replaces the top README GIF with the complete new-user journey, recorded from a real
terminal (charmbracelet/vhs) on a brand-new sample repo — no edits, no faked output:

  1. `ls src/`                                  — a fresh project, OpenLore not set up
  2. `openlore install`                         — detects the agent, wires MCP, builds the
                                                  index in ~180ms (no API key); ends on
                                                  "✓ Index built — orient() will return
                                                  results in your next session."
  3. `openlore orient --task "add auth ..."`    — one deterministic call returns the
                                                  relevant functions + insertion points

So a new user sees exactly what to do, start to finish. Updated the alt-text/caption to
describe the onboarding flow. The .tape recipe is in memory for one-command re-recording.

Doc-only (README + the GIF binary); doc-count guard passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rnance · proof

Replaces the top README GIF with three clean beats, auto-recorded from a real terminal
(charmbracelet/vhs) on a real ~114-file TypeScript project (proxilion) — no edits, no cuts:

  1. memory      `openlore orient --task "add rate limiting to the proxy"`
                 → the relevant functions (rate-limiter, threat-intelligence, load-balancer)
                   and insertion points, in one deterministic call — no grep-and-read.
  2. governance  `openlore blast-radius`
                 → flags a config-hub change before commit: "highest risk: critical;
                   1 hub affected. Hubs: getConfig (6 callers)".
  3. proof       `openlore prove --estimate`
                 → "Cost -37%, Round-trips -50%, Verdict: ✅ OpenLore helps on this repo"
                   (deterministic estimate, no API key).

One clean screen per beat: saves memory, governs risk, and pays off — all on a real repo.
Updated the alt-text/caption to match. Doc-only (README + GIF); doc-count guard passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ect help

A methodical pre-v2.1.4 e2e dogfood (clean-room install on real TS + Python repos,
idempotency, merge-never-clobber, uninstall, --json purity, MCP stdio, docs audit).
Onboarding/auto-setup verified solid: install wires CLAUDE.md block + .mcp.json +
SessionStart/UserPromptSubmit hooks + settings.local permission + AGENTS.md, is
idempotent, MERGES into pre-existing user files (never clobbers), and uninstall strips
only its own block. MCP e2e (initialize → tools/list → tools/call orient) works.

Two real issues found and fixed:

1. install printed a CONTRADICTORY agent-onboarding epilogue. `openlore install` runs
   analyze internally, which then printed "Agent config files: not generated / Re-run
   with --ai-configs" and "Run 'openlore generate'" — directly contradicting install's
   own "[did create] AGENTS.md" / "[did update] CLAUDE.md" / "Index built" output, on the
   primary first-run path. Root cause: analyze's human agent-setup tips have no business
   running when install owns the agent wiring. Fix: a hidden `analyze --embedded` flag
   (set by install's buildIndex) suppresses the agent-setup block, the "not generated"
   tip, and the "run generate" next-step. Standalone `openlore analyze` is unchanged.

2. `openlore connect --help` was stale: "all 62 tools" (the surface is 72) and omitted
   the `substrate` + `coordination` presets it actually accepts. Fixed to match the
   install command's wording (72 tools; full current preset list).

Also: README "5400+ unit tests" → "5500+" (align with the badge; real count ~5,536).

Regression tests (fail before, pass after): install-analyze asserts the contradictory
epilogue is absent from install output; connect.test asserts the --preset help lists
substrate+coordination+72 and not 62.

Build/typecheck/lint clean; full suite 279 files / 5536 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o (no narration)

Replaces the top README GIF with the complete OpenLore lifecycle, recorded straight from
a real terminal (charmbracelet/vhs) on a real Rust project (proxilion, 81 source files /
5,050 functions) — the actual CLI, no commentary, no edits, one clean screen per step:

  openlore install                                  one command sets it up, no API key →
                                                    "✓ Index built — orient() will return
                                                     results in your next session" (5s)
  openlore orient --task "enforce the rate limit"   finds the relevant code across the
                                                    proxy adapters (memory)
  openlore blast-radius                             "highest risk: high; 1 hub affected;
                                                     xff (6 callers)" before commit (governance)
  openlore prove --estimate                         "Cost -84%, Round-trips 17→3 (-82%),
                                                     Verdict: ✅ OpenLore helps" (proof)

So a newcomer clicking the repo sees, in ~25s, exactly what OpenLore does and how trivial
it is to set up. Optimized to ~757 KB (gifsicle). Updated alt-text/caption; doc-count
guard passes. Recorded against the local 2.1.4 build (the published 2.1.3 still has the
install-epilogue bug just fixed). Real proxilion repo untouched (recorded on a temp copy).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e jargon

The old strapline was a 38-word run-on of abstractions ("intelligence graph… unifies
code, infrastructure, and architectural decisions into a single, safety-gated governance
runtime") — accurate but unscannable, and it led with jargon instead of the pain/value.

New tagline is concrete and reads in 3 seconds: what it is (deterministic, local-first
memory + governance), the pain it kills (stop re-reading the same files every task), what
one call returns (the code a task touches + the risk of changing it), and the
differentiators (no API key, no LLM in the hot path). The demo GIF + benchmark section
carry the numbers. Doc-only; doc-count guard passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e hero

The gallery.png banner repeated the H1 ("OpenLore — memory & knowledge graph for AI
agents") and carried a "GraphRAG" pill that contradicts the core positioning (deterministic,
no LLM in the hot path). Now that the demo GIF concretely shows setup → memory → governance
→ proof on a real repo, the banner only delayed the asset that actually sells. Removed the
reference so the hero reads: name → value tagline → trust badges → the real-terminal demo.
(The PNG file is left in place, unreferenced, in case a value-accurate banner is wanted later.)
Doc-only; doc-count guard passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fix broken links/tape

Pre-release deep-dive QA dogfood (two adversarial audit agents + manual onboarding/edge
testing) before cutting v2.1.4. Findings fixed:

- orient: `openlore orient "<task>"` (a bare positional — the most natural thing a
  user/agent types) silently fell through to the no-task session primer and exited 0,
  doing no orientation; a stray --limit also went unvalidated. Now the positional is
  honored (--task still wins); no task still prints the primer so the SessionStart hook
  (`orient --json`) is unaffected. Regression test added (+2).

- README honesty: the hero GIF caption claimed "−84% cost, −82% round-trips" with no
  label, while the MEASURED agent benchmark 35 lines down is −26% — at odds with the
  README's own honesty contract. Caption + alt now mark −84%/−82% as a deterministic
  `prove --estimate` PROJECTION and link to the measured −26% scorecard.

- README broken links: `docs/telemetry.md` (never existed; telemetry is documented
  in-README) removed; `adopt-agent-behavioral-governance/` repointed to its `archive/`
  path. All docs/ links now resolve.

- docs/openlore-demo.tape was the stale Django version (narration style, ends at orient)
  and no longer matched the GIF. Rewritten to the current 4-beat Rust lifecycle
  (install → orient → blast-radius → prove) with an honest header (per-repo estimate;
  hero recorded on a large real Rust repo).

Verified clean by dogfooding: .mcp.json merge preserves a pre-existing OTHER server,
install idempotent + merge-never-clobber, MCP full surface (72/6 families) initialize +
non-orient get_map over stdio, --json purity, exit codes, doctor/prove/update.
typecheck + lint clean; full suite 279 files / 5538 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, add hygiene + gate docs

v2.1.4 pre-release QA, contributor-experience pass (fresh-clone build verified ALL_GREEN:
npm ci → build → typecheck → CLI runs 2.1.4). Two broken commands a newcomer hits
immediately, plus the missing "feel at home" scaffolding:

Broken commands (P0 — a newcomer is misled):
- README "Development" said `npm test` — but that's vitest WATCH mode, which hangs a
  newcomer who copy-pastes the block (and typecheck never runs). Now `npm run test:run`
  (one-shot), matching CONTRIBUTING and CI.
- CONTRIBUTING referenced `npm run embed:up` (a Docker embed server) twice — that script
  no longer exists; the zero-config on-device path superseded it. Now `openlore embed
  --local` (no Docker, no API key).

Feel-at-home scaffolding (P1):
- CONTRIBUTING "Agent Context Setup" now explains the repo dogfoods its own MCP tools and
  how to wire them (`openlore install --preset full` — the lean default omits
  record_decision/search_specs that CLAUDE.md's decisions workflow needs; .mcp.json is
  intentionally git-ignored and regenerated, merges-never-clobbers CLAUDE.md).
- New CONTRIBUTING "The commit gate (decisions)" section — a newcomer whose `git commit`
  is blocked with `{"gated": true}` JSON now knows it's expected and how to resolve it
  (this backs README's existing "decision gate ... documented" claim).
- Added CODE_OF_CONDUCT.md (Contributor Covenant 2.1) and SECURITY.md (private disclosure
  to hi@claygood.com / GH advisory), both linked from the README Development section.
- Added .github/ISSUE_TEMPLATE/bug_report.md + PULL_REQUEST_TEMPLATE.md, and a .nvmrc (24).

Verified: all README + CONTRIBUTING root-relative links resolve; doc-count guard passes;
full suite 279 files / 5538 passed. No source changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clay-good clay-good merged commit e2dcdf5 into main Jun 27, 2026
4 checks passed
@clay-good clay-good deleted the feat/unify-navigation-governance-substrate branch June 27, 2026 15:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant