feat(phase-32-wave-2): adapter-side consolidation — MCP helpers + FileJsonStore + shared specialist prompt#41
Open
fall-development-rob wants to merge 1 commit into
Open
Conversation
…eJsonStore + shared specialist prompt
Phase 32 Wave 2 of the architecture refactor planned in
docs/plans/phase-32-architecture.md. Three independent consolidations
shipped via parallel ruflo swarm; all touch packages/harness/ only.
A. MCP transport helpers centralized
• New `toCanonicalTool(wireTool, prefix)` and `unwrapMcpContent(result)`
in packages/harness/src/mcp-client/name-resolver.ts.
• `stdio.ts`, `sse.ts`, `http.ts` now import the shared helpers.
• Standardized on `.find()` semantics for content extraction (closes
the previous `[0]` vs `.find()` divergence — stdio + sse both used
`[0]`, only http used `.find()`; `.find()` is the more defensive
choice when servers return non-text leading parts like resource refs).
• LOC: −75 across 3 transports, +57 in name-resolver = net −18.
B. FileJsonStore<T> primitive extracted
• New packages/harness/src/persistence/file-json-store.ts (93 LOC) and
persistence/index.ts (8 LOC) — atomic writes via .tmp + rename,
mkdir-on-init, list/load/save/delete with optional filter + compare.
• src/audit/chain.ts: 77 → 27 LOC (createFileAuditSink is now a thin
wrapper that builds an AuditRecord-typed FileJsonStore + composes
the {agentId, since} filter).
• src/memory/session.ts: 90 → 38 LOC (createFileSessionStore similarly
thin; updates updated_at then delegates to the store; lists with
{agentId, status} filter).
• Public surface adds `createFileJsonStore`, `FileJsonStore`,
`FileJsonStoreOptions` exports for any downstream consumer that
wants a typed file store of their own.
C. Shared specialist prompt fragments
• New packages/harness/src/agents/specialists/shared-prompt.ts (78 LOC)
exports four template constants:
SPECIALIST_OPERATING_MODE — delegated-mode preamble
TOOL_CALLING_CONVENTION — bare-name + { input: {...} }
QUALITY_GATE_NO_LLM_ARITHMETIC — every number from a tool call
TRACEABILITY_TABLE_FOOTER — | # | Tool | Inputs | Output |
• All 8 specialist files (equity, credit, fixed-income, derivatives,
quant-risk, macro, private-markets, esg-regulatory) refactored to
interpolate the shared constants instead of carrying verbatim or
paraphrased copies. Domain-specific content (role, tool inventory,
calling examples) stays per-file.
• A few minor prose alignments where specialists had paraphrased
governance prose (credit, quant-risk) — converted to canonical
wording so a single edit propagates.
Tests:
• 159 passed | 8 skipped (was 110 at Wave 1 baseline) — net +49 tests:
file-json-store.test.ts (10), mcp-client.test.ts (+10 for the new
helpers), shared-prompt.test.ts (29 — `it.each` over 8 specialists ×
3 governance assertions + 5 constant-level checks).
• Existing tests (audit-chain, session-memory, mcp-client-sse,
mcp-client-http, providers-*, agents, core) unchanged and passing —
public APIs of all stores and transports preserved.
Net repo impact: 16 files modified + 4 new = 20 files, +328 / −369 LOC
inside packages/harness/ (~−40 net). The win is structural rather than
LOC-headline: future governance/transport edits become 1-file changes.
Phase 32 Wave 2 success metrics:
• toCanonicalTool / unwrapMcpContent declarations: 3 each → 1 each ✓
• Audit + Session file-store implementations: 2 → 1 (FileJsonStore<T>) ✓
• .find() vs [0] content-unwrap divergence: closed ✓
• Specialist governance prose duplication (8 × ~25 LOC): centralized ✓
Future: Phase 33 will replace prompt-fragment interpolation with a true
skill-driven specialist model (parse .claude/skills/*/SKILL.md frontmatter,
inject as system context, reduce specialist AgentDefs to ~10 lines each).
Wave 2C's shared-prompt.ts is the stepping stone — the canonical text
already lives in one place, ready to migrate verbatim into a skill file.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fall-development-rob
added a commit
that referenced
this pull request
May 10, 2026
Phase 34 closes the Phase 31 BC4 "Learning & Adaptation" bounded context
that was documented but never built. Uses ruvnet/RuVector (Rust core +
NAPI-RS bindings) for HNSW similarity search over past dispatch
trajectories.
Architecture:
• New packages/harness/src/reasoning/ — ReasoningBank port + RuVector
impl + indexer + embeddings helper
• agent-loop.ts gets a fire-and-forget reasoning.index() call after
each successful dispatch (never on the hot path; index failures
log but don't fail the dispatch)
• Chief specialist skill (Phase 33 output) gains a virtual
recall_similar(prompt, k) tool — same dispatch-loop intercept
pattern as delegate_to_*
• CLI gains --reasoning-dir <dir> mirroring --audit-dir / --session-dir
Why RuVector specifically:
• HNSW with GNN learning — routing patterns improve with corpus size
• Hyperedge knowledge graph — Cypher queries for issuer/jurisdiction/
instrument-type recall ("every Argentine private placement the
chief has analyzed")
• NAPI bindings — drops into the harness without adding a service
• .rvf cognitive container format — portable, single-file persistence
Why NOT RuVector for audit + session (the user's earlier question):
• Both stores have pure key-value access patterns, no similarity
search, no embeddings. FileJsonStore<T> from Phase 32 Wave 2B is
the correct primitive for those.
• RuVector is the right tool for similarity recall, NOT for append-only
state. They're complementary — same split AgentDB uses internally.
4 waves, ~9 days. Wave 1 ships the bank port + RuVector wrapper +
embeddings helper. Wave 2 wires the indexer into agent-loop. Wave 3 adds
recall_similar as a virtual tool the chief can invoke. Wave 4 adds
knowledge-graph (Cypher) queries + ADRs.
Depends on Phase 33 — the chief skill body (in .md form, not TS) is the
clean place to add the recall_similar paragraph. Adding it to a
TypeScript-defined chief specialist would require a code release for
every prose tweak.
Sequence: Phase 32 Wave 2 (PR #41) → merge → Phase 33 Waves 1-4 →
Phase 34 Waves 1-4. Phases 33+34 together net ~-1,500 LOC.
Open questions in the doc: embedding provider choice (OpenAI vs
RuVector's local model vs Voyage), multi-tenant isolation, PII
redaction at index time.
No code changes in this commit — planning doc only. Both Phase 33 and
Phase 34 plans now sit on the phase-33-skill-driven-planning branch
per user direction (one branch + one PR for the planning track).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fall-development-rob
added a commit
that referenced
this pull request
May 11, 2026
Phase 33 replaces the 8 code-defined specialist .ts files with skill-driven
specialists, consuming the existing four CFA surfaces in their proper roles:
Skills — domain prose + governance fragments (single source of
truth, works in Claude Code AND harness)
MCP plugins — the 623 callable tools (unchanged)
Plugin manifests — distribution (unchanged)
cfa CLI — manifest loader (harness reuses; doesn't reimplement)
Harness runtime — dispatch loop (Phase 31, unchanged)
Approach: a small skill loader (~200 LOC) in packages/harness/src/skills/
parses .claude/skills/<id>/SKILL.md, resolves `extends:` references,
assembles the final system prompt. Two strategies behind one interface:
direct fs read (no CLI dependency) and `cfa managed-agent deploy <slug>
--json` (when the CLI is on PATH).
Result:
• 8 specialist .ts files (~2,300 LOC) → 8 skill files (~50 LOC each)
• shared-prompt.ts (Wave 2C) migrates verbatim into a shared skill
• Persona updates no longer require a code release
• Same skill serves Claude Code interactive use AND harness dispatch
• cfa CLI becomes a real consumer of itself for the harness path
4 waves, ~7 days total. Wave 1 ships the loader and migrates chief-analyst
as a canary. Waves 2-4 are mechanical: 8-agent specialist migration swarm,
CLI loader integration, cleanup + ADRs.
Phase 33 partly revises Phase 31's ADR-037 (Agent Registry as Code) —
the registry stays code, but agent DEFINITIONS move to skills.
No code changes in this commit — planning doc only. Awaiting Phase 32
Wave 2 (PR #41) merge before kicking off Phase 33 Wave 1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fall-development-rob
added a commit
that referenced
this pull request
May 11, 2026
Phase 34 closes the Phase 31 BC4 "Learning & Adaptation" bounded context
that was documented but never built. Uses ruvnet/RuVector (Rust core +
NAPI-RS bindings) for HNSW similarity search over past dispatch
trajectories.
Architecture:
• New packages/harness/src/reasoning/ — ReasoningBank port + RuVector
impl + indexer + embeddings helper
• agent-loop.ts gets a fire-and-forget reasoning.index() call after
each successful dispatch (never on the hot path; index failures
log but don't fail the dispatch)
• Chief specialist skill (Phase 33 output) gains a virtual
recall_similar(prompt, k) tool — same dispatch-loop intercept
pattern as delegate_to_*
• CLI gains --reasoning-dir <dir> mirroring --audit-dir / --session-dir
Why RuVector specifically:
• HNSW with GNN learning — routing patterns improve with corpus size
• Hyperedge knowledge graph — Cypher queries for issuer/jurisdiction/
instrument-type recall ("every Argentine private placement the
chief has analyzed")
• NAPI bindings — drops into the harness without adding a service
• .rvf cognitive container format — portable, single-file persistence
Why NOT RuVector for audit + session (the user's earlier question):
• Both stores have pure key-value access patterns, no similarity
search, no embeddings. FileJsonStore<T> from Phase 32 Wave 2B is
the correct primitive for those.
• RuVector is the right tool for similarity recall, NOT for append-only
state. They're complementary — same split AgentDB uses internally.
4 waves, ~9 days. Wave 1 ships the bank port + RuVector wrapper +
embeddings helper. Wave 2 wires the indexer into agent-loop. Wave 3 adds
recall_similar as a virtual tool the chief can invoke. Wave 4 adds
knowledge-graph (Cypher) queries + ADRs.
Depends on Phase 33 — the chief skill body (in .md form, not TS) is the
clean place to add the recall_similar paragraph. Adding it to a
TypeScript-defined chief specialist would require a code release for
every prose tweak.
Sequence: Phase 32 Wave 2 (PR #41) → merge → Phase 33 Waves 1-4 →
Phase 34 Waves 1-4. Phases 33+34 together net ~-1,500 LOC.
Open questions in the doc: embedding provider choice (OpenAI vs
RuVector's local model vs Voyage), multi-tenant isolation, PII
redaction at index time.
No code changes in this commit — planning doc only. Both Phase 33 and
Phase 34 plans now sit on the phase-33-skill-driven-planning branch
per user direction (one branch + one PR for the planning track).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 32 Wave 2 of the architecture refactor planned in
docs/plans/phase-32-architecture.md. Three independent consolidations shipped via parallel ruflo swarm; all touchpackages/harness/only.toCanonicalTool+unwrapMcpContentcentral inname-resolver.ts; 3 transports consume. 3 → 1 declarations each, closes the[0]vs.find()divergence.FileJsonStore<T>primitivesrc/persistence/.audit/chain.ts77 → 27 LOC.memory/session.ts90 → 38 LOC. Two structurally identical stores → one typed primitive.shared-prompt.ts; 8 specialists refactored to interpolate. Single source of truth for the 4 cross-cutting rules (operating mode / tool envelope / no-LLM-arithmetic / traceability footer).Tests: 159 passed (110 → 159, +49). Typecheck clean. Lockfile guard passes.
Why
wireToolToCanonical(stdio) /sdkToolToCanonical(sse) /sdkToolToCanonical(http) were three near-identical 10-line copies. The content-unwrap helpers had a real bug surface — stdio and sse usedresult.content[0]while http used.find(). When a server returns a non-text leading part (resource ref), stdio/sse would crash. Standardized on.find().{ "input": { ... } }envelope, traceability table mandate, delegated-mode preamble) were repeated across 8 specialist files. A future strengthening edit would have required 8 file changes; now it's 1. A test asserts every specialist still mentions the canonical phrases — silent drift becomes a CI failure.Architecture invariants closed
toCanonicalTool/unwrapMcpContentdeclarations.find()vs[0]content-unwrap divergence.find())Files
New
packages/harness/src/persistence/{file-json-store,index}.ts— typed file-backed storepackages/harness/src/agents/specialists/shared-prompt.ts— 4 governance constantspackages/harness/tests/file-json-store.test.ts— 10 testspackages/harness/tests/shared-prompt.test.ts— 29 tests (8 specialists × 3 governance asserts + 5 constant-level)Modified (consumed shared helpers / refactored)
mcp-client/{stdio,sse,http,name-resolver}.ts— 3 transports consume central helpersaudit/chain.ts(77 → 27 LOC),memory/session.ts(90 → 38 LOC) — thin wrappers overFileJsonStore${SPECIALIST_OPERATING_MODE}etc.index.ts— public exports forcreateFileJsonStoretests/mcp-client.test.ts— +10 tests for new helpersDeleted: nothing — all consolidations are non-breaking.
Test plan
bash scripts/check-no-workspace-lockfiles.sh)npm run typecheckclean across harnessnpm testin harness: 159 passed | 8 skippedWhat's next (Phase 33)
Wave 2C centralized governance prose into TypeScript constants, but the deeper architectural answer is skill-driven specialists:
.claude/skills/cfa/*already carry structured frontmatter; the harness should consume them instead of baking prose into agent code. Phase 33 will:.claude/skills/<id>/SKILL.mdfrontmatter at startupskill_invokevirtual tool)AgentDefto ~10 lines ({ id, model, skills: [...], tools: [...] })The shared-prompt fragments from this PR migrate verbatim into a new
corp-finance-analyst-sharedskill file. The 8 specialist.tsfiles shrink by ~95%.🤖 Generated with Claude Code