v3/docs/adr/ADR-150-metaharness-integration-surfaces.md
npx rufloStatus: Implemented (Phase 1 ✅ iters 1–3 · Phase 2 ✅ iters 4–32 · Phase 3 §3.1 ✅ iters 33–99 · KRR retrain pending production data · Phase 3 §3.2-§3.5 scoped in ADR-151)
Date: 2026-06-16 (revised 2026-06-17 — 100 iterations of /loop)
Related: ADR-148 (cost-optimal router lifecycle via @metaharness/router), ADR-149 (per-model cost-optimal routing), ADR-026 (3-tier model routing), ADR-097 (federation budget circuit breaker), ADR-124 (optional native dependencies), ADR-144 (agent-authorization-propagation)
External reference: ruvnet/agent-harness-generator — the upstream that publishes metaharness + @metaharness/*. Same author (rUv), explicitly designed around ruflo primitives.
Research dossier: published as a gist (linked from the tracking issue) with full graded-evidence sourcing.
We just shipped [email protected] (also @claude-flow/[email protected], [email protected]). ADR-148/149 already wired @metaharness/router as an optionalDependency for cost-optimal model routing behind a triple gate. The remaining MetaHarness surface — twenty-plus @metaharness/* packages: kernel, host adapters (9), verticals (13), scaffold/eject CLI — is unused by ruflo despite being authored by the same maintainer specifically around ruflo's architecture.
Three signals make this the right time to commit a broader integration:
[email protected]), same ADR numbering convention (kernel docs reference ADR-011/022/033/036/040/041/043), explicit framing: "Scaffold your own focused AI agent harness — like ruflo, uniquely yours." The buildRegistryEntry() doc comment says: "Mirrors the ruflo plugin registry shape so the same UI can browse it." The @metaharness/host-claude-code adapter emits .claude/settings.json in exactly ruflo's format.@metaharness/router@^0.3.2 is in optionalDependencies; neural-router.ts imports it behind CLAUDE_FLOW_ROUTER_NEURAL=1. The bundled KRR is trained on hand-coded seed scores rather than measured routing outcomes — leaving the DRACO Pareto win unrealized.| Fact | Source | Grade |
|---|---|---|
[email protected] ships 24 subcommands across two binaries (metaharness factory + harness lifecycle) | dist/index.d.ts, dist/subcommands.d.ts, all *-cmd.d.ts | HIGH |
20+ @metaharness/* packages published; full ecosystem (kernel + 5 host adapters + 13 verticals + 5 platform NAPI binaries) | npm search @metaharness | HIGH |
@metaharness/[email protected] exports Router (k-NN), TrainedRouter (KRR), NativeRouter (FastGRNN via tiny-dancer), zero runtime deps, 53 kB unpacked | dist/*.d.ts, npm registry | HIGH |
@metaharness/[email protected] exports loadKernel, ToolDispatcher (claims-checked), SelfEvolvingRouter, TrajectoryStore, rankWithDecay | kernel-pkg/package/dist/*.d.ts | HIGH |
metaharness factory exports buildRepoScorecard(), buildGenomeReport(), buildScorecard(), buildThreatModel(), scanMcp(), buildOiaManifest(), buildRegistryEntry() — all pure reads, well-typed | dist/repo-scorecard.d.ts etc. | HIGH |
Velocity: metaharness 0.1.0 → 0.1.11 in ~23h; @metaharness/router 0.1.0 → 0.3.2 in 2.7h on 2026-06-15 | npm time field | HIGH |
| Both packages MIT-licensed, same maintainer as ruflo | npm registry | HIGH |
Existing benchmark proves @metaharness/router native backend loads on the test host: mh_native_available: true | docs/benchmarks/runs/router-4way-seed99-2026-06-15T14-12-40Z.json | HIGH |
MetaHarness may augment ruflo. MetaHarness must never become a required runtime dependency for core orchestration, memory, routing, MCP dispatch, agent execution, or federation.
Every integration in this ADR, and every future ADR that extends it, must satisfy:
npm ls with all @metaharness/* packages removed must still produce a working CLI. The triple-gate pattern used for @metaharness/router (env flag + artifact + import success) is the reference implementation.package.json: @metaharness/* packages MUST appear in optionalDependencies or peerDependencies (optional), never in dependencies.@metaharness/* symbol must catch MODULE_NOT_FOUND and fall back to a built-in path (or a clearly-degraded but functional state).--ignore-optional (or equivalent) and assert ruflo still passes its smoke contract. This is the only structural defense against accidentally promoting an optional dep to required.The intent of this constraint is to prevent ruflo from becoming a hidden second orchestration framework wrapped around its sibling's runtime. Reviewer's framing: "Ruflo remains operational if every MetaHarness package is removed." That sentence is now part of the API surface contract — any PR that breaks it is a breaking change requiring its own ADR.
Adopt MetaHarness as ruflo's downstream sibling tool, surfaced through three integration channels that match its three distinct contributions:
harness-score, harness-genome, harness-threat-model, harness-mcp-scan as a new plugins/ruflo-metaharness/ plugin. Subprocess invocation of the metaharness / harness CLI binaries; no static library dependency added to ruflo's boot path. Read-only operations only.CLAUDE_FLOW_ROUTER_TRAJECTORY=1 recorder; retrain train-bundled-krr.mjs against real data. This unlocks the Pareto win ADR-149 forecast but never measured.harness mcp scan . and metaharness score . --json to v3-ci.yml. Both are static, fast, and machine-readable. Asserts no HIGH MCP findings and a non-zero readiness score on every PR.Three concrete things we ARE NOT doing in this ADR (deferred to Phase 2+):
@metaharness/kernel's ToolDispatcher into the MCP dispatch core. The kernel is v0.1.0 and the dispatch path is too high-blast-radius for an early-stage replacement.@metaharness/router from optionalDependency to dependency. The triple gate is the right posture until the API stabilizes at 1.0.from-repo <git-url> as an MCP tool callable by Claude Code without explicit user confirmation. Untrusted-Git-clone is a deliberate human-in-the-loop step.Phase 0 — Measurement spike (1–3 days, no code shipped to npm).
npx metaharness score . and npx metaharness genome . against the ruflo repo to establish baseline scorecards.CLAUDE_FLOW_ROUTER_TRAJECTORY=1 for ≥50 routing decisions; verify the .swarm/model-router-trajectories.jsonl shape matches what train-bundled-krr.mjs expects.import('@metaharness/router') succeeds from v3/@claude-flow/cli and exercise Router.fromExamples(...) with the existing benchmark corpus.harness mcp scan . to baseline ruflo's own MCP threat-model score.Exit criteria: baseline numbers in hand; no surprises in trajectory format or mcp scan output.
Phase 1 — MVP (3–7 days, one MINOR release: 3.12.0).
plugins/ruflo-metaharness/ with three skills (harness-score, harness-genome, harness-mint), conventional structure (plugin.json, skills/*/SKILL.md with allowed-tools: Bash, scripts/smoke.sh). Skills shell out to npx metaharness / npx harness — no library imports. Covered by the fleet meta-smoke and the three existing audits (exit-bypass, frontmatter, manifest).v3-ci.yml: npx metaharness score . --json (assert exitCode === 0) and npx harness mcp scan . (assert no HIGH findings). Both are additive jobs on the existing matrix.scripts/train-bundled-krr.mjs, regenerate the bundled artifact. Validate routedBy: 'metaharness-krr' activates on real decisions in the next bench run.Exit criteria: plugins/ruflo-metaharness/scripts/smoke.sh passes; meta-smoke shows 33/33 plugins green; CI score + mcp-scan jobs green on main; new bench run shows routedBy: 'metaharness-krr' for ≥ 1 routing decision driven by measured-seed KRR.
Semver: MINOR — additive plugin, additive CI gates, additive MCP tools. No breaking changes.
Phase 2 — Expansion (1–4 weeks, one or two MINOR releases).
npx ruflo eject command wrapping metaharness --from-existing ./ for one-shot harness extraction (attribution preserved via the <!-- ruflo-attribution-block --> convention).SelfEvolvingRouter (from @metaharness/kernel) parallel-logged alongside the Thompson bandit in model-router.ts for two weeks. Promotion criteria (AND, not OR — must satisfy all three):
qualityScore improvement > 2% (where qualityScore is the existing per-task verdict-weighted reward used by the bandit)usdPerDecision increase < 1% (no expensive regressions hiding behind quality wins)type: 'harness' in discovery.ts; surface via npx ruflo plugins list --type harness.oia-audit that runs buildOiaManifest() + buildThreatModel() + scanMcp() on a schedule and stores results in the metaharness-audit memory namespace.Each Phase-2 item is independently scoped and can ship as separate MINOR releases.
Phase 3 — Harness Intelligence Layer (future, scope-only — separate ADR per item).
A class of capability that exists nowhere else in the agent-framework space, made possible by buildGenomeReport() + buildRepoScorecard() + buildRegistryEntry()'s shared schema:
compare <a> <b> already exists in harness CLI; lift it into a fleet-aware diff that answers "which harness in our fleet has the closest capability set to this task?".plugins/X/ and a target harness, predict whether the plugin's allowed-tools requirements are satisfied by the harness's MCP server declarations.These are scope-only in this ADR. Each item gets its own ADR before implementation. They are listed here so the architectural constraint (above) covers them up front — the Harness Intelligence Layer must also satisfy the four removable/optional/graceful/CI-coverage rules.
model-router.ts dispatch logic changes, no top-level command surface change, no IPFS registry change. Backward-compatible MINOR bump.metaharness and @metaharness/router are 0.x and ship rapid patch releases. A breaking change in @metaharness/[email protected] would require immediate neural-router.ts updates. Mitigation: pin to ~0.3.2 in optionalDependencies; add scripts/check-metaharness-compat.mjs to CI exercising the Router constructor with a trivial example to catch runtime breakage before publishing.harness from-repo <url> clones arbitrary Git URLs. Phase-1 skills NEVER expose this to Claude Code; only analyze/score/genome (pure reads) and harness-mint (writes to user-specified target dir, never project root).harness validate uses GCP Secret Manager via gcloud. Ruflo CI must skip those subcommands (or mock them) — explicit --skip-gcp flag from the harness validate command surface handles this.--json flag everywhere.ruflo-metaharness plugin doubles documentation surface for two sibling tools. Mitigation: skill descriptions explicitly point to the upstream MetaHarness docs as canonical for the underlying functionality; the plugin only documents the ruflo-side adaptation.Alternative A: Ignore MetaHarness, build all scaffolding/score/genome natively in ruflo.
Rejected. buildRepoScorecard(), buildGenomeReport(), scanMcp(), buildThreatModel() are already-tested implementations exposing clean TypeScript APIs. Reimplementing them in ruflo is pure duplication cost with no advantage. The eject path's rewriteContent() with attribution-block preservation is subtle.
Alternative B: Use MetaHarness only as a CLI subprocess everywhere, never as a library import.
Partially adopted (this is the Phase-1 plugin posture). Wrong for @metaharness/router — sub-ms routing latency demands a library import, which ADR-148/149 already accepted.
Alternative C: Promote @metaharness/router from optionalDependency to dependency.
Rejected for now. The triple gate (CLAUDE_FLOW_ROUTER_NEURAL=1 + artifact + import success) is the right posture until the API stabilizes at 1.0.
Alternative D: Wait for MetaHarness 1.0 before any further integration beyond ADR-148/149.
Rejected. The static-analysis surface (score, genome, mcp scan, threat-model) is already mature (475 files, well-typed, pure reads). Waiting creates a window where users discover MetaHarness independently and are confused about its relationship to ruflo. The Phase-1 plugin answers that question without incurring API-stability risk because the integration is via CLI subprocess, not library import.
Alternative E: Wire @metaharness/kernel's ToolDispatcher as the primary MCP dispatch in Phase 1.
Rejected. Touching the MCP dispatch core affects all 314 tools and is too high-blast-radius for an early-stage (v0.1.0) component. Deferred to a Phase-3 ADR after the kernel ships a 1.0 with API-stability commitments.
harness-mint skill require explicit user confirmation in the Claude Code UI before writing any files? Lean yes — destructive-action-confirmation matches ruflo's "executing actions with care" principle.oia-audit background worker (Phase 2) belong in ruflo-loop-workers or in ruflo-metaharness? Probably the latter, since the audit output is MetaHarness-specific.--ignore-optional smoke run) interact with the existing all-plugins-smoke.yml workflow? Probably a new sibling workflow no-metaharness-smoke.yml that re-runs the same matrix with --ignore-optional; lighter than adding a second axis to the existing matrix.The integration shipped across eight /loop iterations on branch
feat/metaharness-integration-research. Status of each Phase milestone:
typescript-sdk-harness,
template recommendation vertical:coding, scaffoldReady true.node_mcp_ci, risk_score 0.27 (low),
publish_readiness 0.9, mcp_surface remote.plugins/ruflo-metaharness/ with 6 skills (one more than ADR-150
originally proposed — harness-oia-audit was lifted forward from
Phase 2 in iter 7): harness-score, harness-genome,
harness-mcp-scan, harness-threat-model, harness-oia-audit,
harness-mint.scripts/_harness.mjs bridge — single subprocess
invocation point, 60s hard timeout, JSON-mode default, graceful
degradation via emitDegradedJsonAndExit.npx ruflo metaharness <subcommand> top-level dispatcher in
v3/@claude-flow/cli/src/commands/metaharness.ts (iter 3).metaharness@~0.1.11 and @metaharness/router@~0.3.2 in
optionalDependencies of BOTH @claude-flow/cli/package.json and
ruflo/package.json (iter 3). Tilde pin, not caret — per
review-round-1 (upstream had 5 releases in 2.7h).metaharness-ci.yml — score, mcp-scan, router-compat jobsno-metaharness-smoke.yml — enforces architectural constraint rule
#4 by greping every package.json for non-optional metaharness deps
AND drilling each skill with an unresolvable npm registryscripts/check-metaharness-compat.mjs — API-stability tripwire,
9/9 against current @metaharness/[email protected]npx ruflo eject (iters 4–5) — Phase-2 differentiator wrapping
metaharness --from-existing. Dry-run default; refuses in-repo
target + existing-target overwrites. CI dry-run job in
metaharness-ci.yml validates BOTH the plan output AND the safety
refusal.'harness' PluginType in plugin registry (iter 6) — schema
extension only, zero runtime overhead. npx ruflo plugins list --type harness filter works by construction.harness-oia-audit composite worker (iter 7–8) — bundles
oia-manifest + threat-model + mcp-scan into one timestamped record;
persistence to metaharness-audit memory namespace; weekly cron
workflow .github/workflows/oia-audit-weekly.yml at Sundays 04:17 UTC.SelfEvolvingRouter parallel-logging — BOTH HALVES LANDED:
Analyzer (iter 10):
plugins/ruflo-metaharness/scripts/router-parallel-analyze.mjs reads
paired routing decisions from a JSONL trajectory file and computes
the 3-criteria AND-gate from review-round-1. Verified end-to-end with
synthetic fixtures (✓ PROMOTABLE / ⚠ NOT promotable paths both work,
insufficient-data path exits cleanly at n<30). @metaharness/kernel
added to optionalDependencies of @claude-flow/cli AND
ruflo/package.json so the future Recording side can dynamic-import
SelfEvolvingRouter without a static dep.
Recorder primitive (iter 11):
v3/@claude-flow/cli/src/ruvector/router-parallel-recorder.ts
exports recordPair(task, bandit, ser) + recordPairOutcome(task, outcome) + parallelRecorderStatus(). Env-gated via
CLAUDE_FLOW_ROUTER_PARALLEL_LOG=1 — no-op when unset (default).
Every appendFileSync wrapped in try/catch with debug-only stderr
logging; ADR-150 rule #3 satisfied (never throws from the routing
path). 10MB rotation. Default output path
.swarm/router-parallel.jsonl matches the iter-10 analyzer's
default --input.
Dispatch wiring (iter 12 — LAST MILE):
The one-line edit in model-router.ts route() shipped in iter 12.
Fire-and-forget recordPair({task, bandit, ser}) inside the
existing if (abEnabled) block — same place the A/B disagreement
counter already lives. Env-gated by
CLAUDE_FLOW_ROUTER_PARALLEL_LOG === '1'; no-op when unset, which
means ZERO overhead on the default routing path. The dynamic-import
is lazy (one Promise per process); the recordPair call is wrapped
in try/catch with .catch(() => {}) on the import promise — the
routing path NEVER throws, even when the optional kernel is
completely absent.
Both arms are attributed at the call site: bandit.backend = 'thompson-bandit' ser.backend = neuralPrior ? 'metaharness-router-hybrid' : 'bandit-only'
The pipeline is now end-to-end: route() → recordPair() → .swarm/router-parallel.jsonl → router-parallel-analyze.mjs → 3-criteria AND-gate verdict
Requires production trajectory data. The pipeline is wired:
CLAUDE_FLOW_ROUTER_TRAJECTORY=1 writes JSONL;
scripts/train-bundled-krr.mjs rebuilds the artifact. The blocker is
data collection — needs a 50+ decision production sample. Plan: enable
the recorder on the next merged-to-main release; collect a week of
real routing data; retrain in a follow-up PR.
scripts/smoke-all-plugins.mjs (was 32; +1 for
ruflo-metaharness)plugins/ruflo-metaharness/scripts/smoke.shAdditional Phase-2 surface landed over iters 13-32, all on the same
feat/metaharness-integration-research branch:
audit-trend.mjs — diff two oia-audit records (drift
detection). Pulls baseline + current snapshots from
metaharness-audit namespace; reports composite severity delta +
per-component status + introduced/cleared findings.audit-list.mjs — enumerate timestamped records in
metaharness-audit namespace, with --since 30d-style filtering.metaharness-tools.ts MCP surface — 7 tools registered:
score, genome, mcp-scan, threat-model, oia-audit, audit-list,
audit-trend. Each backed by subprocess invocation through the same
_harness.mjs bridge. test-mcp-tools.mjs enforces the runtime
contract: {success, data, degraded, exitCode} shape, never-throws
invariant.cwd: dirname(target) + basename(target) as cliName
workaround for upstream --target bug (now fixed at [email protected])..harness/mcp-policy.json + manifest.json — security
posture: default-deny, allow shell/network/file-write: false,
audit-log on; iter-31 exact-pins close LOW severity vector; iter-32
manifest documents witness-key gap.Phase-3 §3.1 from ADR-152 shipped across 27 iterations. The implementation is now deeply integrated across 14 distinct surfaces:
| # | Surface | Iter |
|---|---|---|
| 1 | Spike with 2 invariants (selfMatch, verticalAffinity) | 35 |
| 2 | Production module _similarity.mjs (5 exports) | 36 |
| 3 | CLI skill similarity.mjs (file + memory inputs) | 36 |
| 4 | MCP tool metaharness_similarity | 36 |
| 5 | CLI dispatcher entry | 36 |
| 6 | MCP runtime contract test (74→115 assertions) | 37, 43, 52 |
| 7 | Pipeline consumers (oia-audit fingerprint + audit-trend) | 38 |
| 8 | 53 unit-test assertions over 8 phases | 39 |
| 9 | Dedicated CI job similarity-tests | 40 |
| 10 | Performance benchmark with regression gate | 41 |
| 11 | End-to-end pipeline roundtrip test | 47, 49, 51 |
| 12 | CI job metaharness-real-data running roundtrip | 48 |
| 13 | Doctor health check distinct from upstream | 45, 52 |
| 14 | drift-from-history one-command primitive + MCP tool | 53, 54 |
End-to-end roundtrip caught FOUR latent bugs that synthetic-fixture tests had missed for 9+ iterations each:
_similarity.mjs. Fixed by
routing score+genome through runMetaharness.audit-trend read json.findings
expecting an array, but mcp-scan emitted text-only. Flagged.parseMcpScanText parser in
_harness.mjs, wired into both mcp-scan.mjs and oia-audit.mjs.context.args (positionals) were
forwarded to subprocess. Now reads context.flags and re-kebabs
camelCase→kebab. Affects ALL metaharness subcommands.success = (exitCode === 0) (was
!degraded). Affects all 9 metaharness MCP tools. Documented 3
observable cases.Composite operations now use Promise.all where dependency graph allows:
timing.{wallMs, sumComponentMs, parallelSpeedup}
field in oia-audit output. Smoke gate asserts speedup > 2.0 to catch
silent serialization regression.The architectural-constraint workflow (no-metaharness-smoke.yml)
drilled only 4 skills pre-iter-55. Extended to 7. Discovered 3 latent
gaps (oia-audit timeout, mint marker missing, drift-from-history exit
code), all closed in iters 56-57.
Two issues filed at ruvnet/agent-harness-generator:
A second wave of work after iter 59 focused on three orthogonal hardening axes: parallelization, anti-regression infrastructure, and upstream-contract tripwires.
timing.{wallMs, sumComponentMs, parallelSpeedup} so the speedup is observable and gated against
silent serial regression.--baseline-file fast-path: skips audit-list AND
audit-trend memory roundtrip → ~19x speedup (1.4s wall on Apple
Silicon vs ~26s slow path). Iter 66's --baseline-key was the
intermediate ~14x step.| Tripwire | Surface | Iter |
|---|---|---|
check-metaharness-compat.mjs | @metaharness/router public API | 12 |
check-mcp-scan-format.mjs | harness mcp-scan text-output format | 80 |
check-fingerprint-schema.mjs | metaharness score/genome JSON fields | 81 |
Each tripwire runs in CI metaharness-real-data job BEFORE the
roundtrip — upstream drift fails with a SPECIFIC error pointing at
which surface broke, instead of cascading to downstream symptoms.
@metaharness/* imports outside neural-router.ts.The roundtrip test surfaced 4 latent bugs that hand-built-fixture testing had missed:
--baseline-key fast-path (~14x)--baseline-file fastest-path (~19x)gh run downloadif: always() && has_prior so
failure-path artifacts (the most valuable) still get uploaded--alert-on-new-severity orthogonal alert gate
(catches "new CRITICAL finding with similarity intact")--alert-on-new-severity high,
closing the production wiringAll 9 MCP tools have CLI-level flag parity. Iter 71 specifically fixed drift-from-history (iter-66/67 flags were CLI-only until then). Iter 73's anti-mint negative guard enforces the deliberate asymmetry: 10 CLI subcommands, 9 MCP tools (mint cli-only per §Sandboxing).
| Artifact | Workflow | Iter |
|---|---|---|
oia-audit-${run_id} | weekly cron | 7 |
drift-trend-${run_id} | weekly cron | 69 |
bench-similarity-${run_id} | per-PR CI | 82 |
All 90-day retention for cross-artifact comparability.
Eighteen more iters of hardening after iter 82's ADR refresh. Two coherent arcs: cross-reference integrity matrix and fast-path observability.
Eight cross-reference surfaces now smoke-gated. Each detects a specific class of "thing X must point at thing Y" drift before it reaches production:
| Source | Target | Iter |
|---|---|---|
| description string | SUBCOMMANDS keys | 73 |
| SUBCOMMANDS values | scripts/*.mjs | 89 |
| MCP handler runScript() | scripts/*.mjs | 90 |
| SKILL.md inline refs | scripts/*.mjs | 91 |
| MCP enum | SEVERITY_RANK keys | 92 |
| MCP tool names | CLAUDE.md catalog | 93 |
| SUBCOMMANDS keys | CLAUDE.md catalog | 94 |
| CI workflow run steps | tripwire scripts | 84 |
Plus 3 negative-guard invariants from iters 73+74 (mint-not-in-MCP,
no from-repo skill/script/MCP tool, no new static @metaharness/*
imports outside neural-router.ts).
iter-66/67 added the --baseline-key (~14x) and --baseline-file
(~19x) fast-paths. iter-95-99 made them observable at every consumption
layer:
timing.path field in JSON payloadPath: file (wall N ms)GITHUB_STEP_SUMMARY shows the sameA creeping regression (e.g., fastpath quietly degrading from 1.4s to 15s over weeks) is now visible in the Actions UI's wall annotation before it breaches the 30s ceiling.
The integration shipped across 100 /loop iterations spanning the major arcs documented above. Two patterns emerged that are worth naming:
Bug-discovery via end-to-end tests (iters 47-51, 87) — every significant latent bug surfaced when a test exercised the REAL CLI/MCP chain end-to-end, not when smoke greps verified source markers. iter-47's schema bug hid for 9 iters; iter-50's parser gap hid for 28 iters; iter-87's JSON-contamination hid for 5 iters. The lesson: smoke-grep on source is a complement to, not a substitute for, real-output verification.
Cross-reference integrity (iters 73, 84, 89-94) — when one source file references another by name, drift is the default without an explicit gate. Eight surfaces are now gated; each produces a specific named failure when the reference rots.
The dep is now: production code with 14+ surfaces, 102 smoke steps, 120 MCP runtime assertions, 66 roundtrip pipeline assertions, 94 unit tests, 8 cross-reference gates, 3 negative-guard invariants, 3 compat tripwires, 4 CI workflows, weekly autonomous drift detection, two upstream issues filed (#15, #16, both still open).
The single non-test ruflo source file that statically imports a
@metaharness/* package is:
v3/@claude-flow/cli/src/ruvector/neural-router.ts ← @metaharness/router
(dynamic import,
triple-gated)
All other ruflo code reaches MetaHarness exclusively through the
_harness.mjs subprocess bridge. The no-metaharness-smoke.yml
workflow continually enforces this with both a static grep (every
package.json) and a runtime drill (each skill against an unresolvable
npm registry, asserting graceful degradation).
@metaharness/router.[email protected] on npm: https://www.npmjs.com/package/metaharness@metaharness/[email protected] on npm: https://www.npmjs.com/package/@metaharness/router@metaharness/[email protected] on npm: https://www.npmjs.com/package/@metaharness/kernel