* docs(adr): ADR-164 — AgentBBS federated business-management autopilot
Draft ADR proposing agentbbs@0.1.0 integration as a federation-peer kind +
business pod scaffolding. Covers the 4 new MCP tools, 7 domain pod templates
(sales/marketing/finance/ops/support/hr/exec), upstream changes required in
both ruflo and ruvnet/agentbbs, 5-phase rollout, and 7 honest risks.
Builds on the optional-dep + graceful-degraded pattern shipped today in PR
#2500 (agenticow) and ADR-150 (metaharness).
Status: Draft. Implementation gated on upstream confirmation of agentbbs
persistence semantics + latency baseline.
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* docs(adr): amend ADR-164 + add ADR-164.1 (budget atomicity)
ADR-164 amendments (Draft v2, 1193 → 1412 lines, +219 net):
- Rewrite agentbbs maturity assessment — it's a 13-crate Rust workspace
with 7 existing CI workflows + 30+ release tags + existing federation
crate, NOT a 16h-old greenfield. The npm package is the launcher only.
- §3.2.4 — two-phase auth: 15-min token is handshake-only;
long-lived stream sessions persist past expiry until idle-close.
- §3.5.4 — new "Founder-bootstrap trust elevation" admin escape hatch
so #exec cross-pod synthesis works on Day 1 without 500-interaction wait.
- §4.4 — Ops pod gets aidefence_*, terminal_execute, agent_execute,
new http_fetch tool, cloud-provider MCP servers; concrete bench scenario.
- §5.1.8 — new MCP tool `http_fetch` (URL allowlist, timeout, size cap).
- §5.2 — survey-first upstream changes; many requirements may already
exist in crates/agentbbs-federation and crates/agentbbs-mcp.
- §7.3 + §9.5 — forward-reference to ADR-164.1 for race resolution.
- §9.1 — risk #1 rewritten: real risks are npm/Rust version drift, FSL
license implications, cargo first-run requirement, MCP server
compatibility.
ADR-164.1 (new, 724 lines):
- Atomic reserve-and-commit token bucket against AgentDB-style
SQLite store with BEGIN IMMEDIATE serialization.
- Schema: bbs_budget_reservations + bbs_budget_rooms tables.
- Three-op API: reserve / commit / release with discriminated returns.
- 5 concurrency tests (vitest-implementable) closing the race window.
- Migration plan: feature-flagged rollout behind
CLAUDE_FLOW_BBS_ATOMIC_BUDGET, default flip after 1 week zero incidents.
- p99 < 5ms target with ~1000 reserves/sec throughput ceiling honestly
documented (partition-per-pod as the scale-out path, not replacing
SQLite).
Both Draft status. Phase 1 implementation gated on these.
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* docs(adr): ADR-164.1 amendments — close the Expired Commit Leak
Peer review (2026-06-29) identified three issues:
1. CRITICAL — Expired Commit Leak (§8.1, §5.3, §4.1)
Original draft rejected commit() of an expired reservation, so the
actual API spend went unrecorded. A high-latency loop could silently
burn unbounded $ past the monthly cap. Fixed: commit() now ACCEPTS
the spend, transitions state to new 'committed_post_expiry' value,
records actual_usd, returns { ok: true, warned: 'COMMIT_AFTER_EXPIRY' },
and emits a reservation.committed_post_expiry audit envelope.
2. SQLite locking clarification (§3.2 _lock_bump field note)
BEGIN IMMEDIATE itself acquires the RESERVED lock; _lock_bump is now
documented as belt-and-suspenders + code-review visibility, not the
primary serialization primitive.
3. Per-pod reservationExpiryMs (§3.2 expires_at field note)
Default 60s is too short for local large-model pods. Pod templates
may now set reservationExpiryMs in [5_000, 300_000] ms; ceiling
defends against unbounded runaway.
Plus new Test 6 in §9: load-bearing proof that COMMIT_AFTER_EXPIRY
captures the real spend and the room's subsequent gate-check reflects it.
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* feat(mcp): Phase 1 — agentbbs integration scaffold (4 MCP tools)
Implements ADR-164 §3.2 + §5.1 with the same architectural pattern as
PR #2500 (agenticow): optional-dep + graceful-degraded fallback.
New MCP tools (4):
- federation_bbs_register register a BBS room as a federation peer
- federation_bbs_publish publish a typed envelope to a room
- federation_bbs_watch poll recent envelopes (streaming = Phase 4)
- federation_bbs_human_join single-use Ed25519 token + web/SSH handshake
Phase 1 scope (scaffolding the surface, not the wire):
- loadAgentbbs() checks importability; degrades to {degraded:true,
reason:'agentbbs-not-found'} when missing — never throws
- Validation runs BEFORE the optional-dep check so path-traversal /
label / msgType rejection is deterministic regardless of install state
- Backing store: local JSON-lines in <basePath>/room-<id>.jsonl +
rooms.json registry. The Rust agentbbs-federation crate will replace
this with signed wire envelopes in Phase 2.
- Ed25519 keypair is per-process ephemeral; real federation keypair
wiring is Phase 2 (documented inline at the call site).
Gates (all PASS):
- Build: clean (v3/@claude-flow/cli npm run build)
- Vitest: 8 pass + 4 skip-conditional (agentbbs binary not built locally)
- ADR-112 audit: 349/349 tools with Use-when guidance (was 345; +4 new)
- Bash smoke: 8/8 (end-to-end register→publish→watch cycle via dist handlers)
Plus:
- .github/workflows/no-agentbbs-smoke.yml — CI guard mirroring
no-metaharness-smoke.yml; asserts agentbbs stays in optionalDependencies
and runtime drill exits 0 with --ignore-optional install
- plugins/ruflo-bbs-federation/.claude-plugin/plugin.json — plugin metadata
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* docs(adr-164): replace §5.2 hypotheticals with concrete agentbbs survey findings
Phase 1 survey of ruvnet/agentbbs @ ca3c6e0 resolved each compatibility
check in §5.2 against the live upstream source. Six "VERIFY FIRST / if-
exists / if-missing" branches are replaced with definite answers:
- §5.2.1 FederationPayload — already covers ruflo's needs (4 variants,
Ed25519-sealed); map publish→ReplicateMessage, register→AnnounceBoard.
No upstream PR.
- §5.2.2 MCP tool registration — static 4-tool surface (list_boards,
read_board, post_message, search_memory). Re-scoped from "web UI
rendering" to the actual MCP shape concern. Gap #1 filed for missing
create_board tool. No upstream PR for Phase 1.
- §5.2.3 Subscription/streaming — genuinely missing (subscribe=false
hardcoded), but matches ruflo's Phase 1 polling design. Gap #2 filed
for Phase 4 streaming. No upstream PR for Phase 1.
- §5.2.4 Integration seam — surprise finding: agentbbs already drives
`npx ruflo federation` via RufloAdapter (other direction). Ruflo's
CLI now has a contract obligation to keep init/join/status alive.
- §5.2.5 Durable retention — postgres backend exists in CI but
`agentbbs mcp` defaults to MemoryStore; gap #3 filed for Phase 3.
- §5.2.6 CI regression coverage — no existing end-to-end agentbbs↔ruflo
test. Closed by ruvnet/AgentBBS#3 regression guard (PR opened upstream
in this same Phase 1 cycle).
The regression guard at ruvnet/AgentBBS#3 asserts the four MCP tool
names, four FederationPayload variants, and three RufloAdapter
subcommand names continue to exist on every agentbbs PR + nightly cron.
Cross-ref:
- Upstream PR: https://github.com/ruvnet/AgentBBS/pull/3
- Survey commit: ruvnet/AgentBBS@ca3c6e0
* feat(pods): Phase 2 — sales pod end-to-end (dry-run + validator + smoke)
Implements ADR-164 Phase 2: scaffold the first concrete business pod
(sales) end-to-end with a typed validator, a tick runner, and full smoke
coverage. Dry-run mode is the Phase 2 default; --live mode exits 3 with
a "Phase 3" message until Managed Agent + claude-p wiring lands.
New surface (~1,597 LOC):
v3/@claude-flow/cli/src/business-pods/pod-schema.ts — PodTemplate type
+ validatePodTemplate()
+ KNOWN_AGENT_TYPES mirror
v3/@claude-flow/cli/src/mcp-tools/business-pod-tools.ts — 1 new MCP tool
(business_pod_validate)
plugins/ruflo-business-pods/
.claude-plugin/plugin.json
templates/sales.json — Phase 2 sales pod template
(matches ADR-164 §4.1 +
§3.3 schema)
scripts/pod-tick.mjs — dry-run tick runner +
file-based budget ledger
(TODO(adr-164.1): swap to
atomic SQLite tracker)
scripts/pod-tick.test.mjs — 15 node:test tests
scripts/smoke.sh — 8-step smoke contract
skills/pod-sales/SKILL.md
.github/workflows/business-pods-smoke.yml — CI gate
Gates (all PASS):
- Build: clean
- vitest business-pod-tools: 19/19 PASS
- node:test pod-tick: 15/15 PASS
- ADR-112 audit: 350/350 with guidance (was 349; +1 new tool)
- business-pods smoke: 8/8 PASS
- agentbbs regression smoke: 8/8 PASS (no regression from Phase 1)
- agenticow regression smoke: 8/8 PASS (no regression from PR #2500)
Honest Phase 2 deviations:
- Schema validator duplicated TS / JS (single canonical TS in cli/src/,
JS copy in pod-tick.mjs so script runs without prebuilt CLI). Phase 3
consolidates via shared agents/registry.ts.
- Budget ledger is file-based JSON stub; ADR-164.1 atomic SQLite
tracker swap deferred to Phase 3.
- agentbbs subprocess wiring not invoked; envelopes go directly to
the Phase 1 JSONL backing store (matches ADR-164 §5.2.2 phase plan).
Phase 3 follow-ups inline-marked TODO(adr-164.1) / TODO(phase-3).
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* feat(pods): Phase 3 — remaining 6 pods + domain-affinity router policy
Implements ADR-164 Phase 3: templates for marketing/finance/ops/support/hr/exec
+ the @metaharness/router domain-affinity policy hook.
New templates (6) at plugins/ruflo-business-pods/templates/:
marketing.json SOC2, $40/mo, cloud-tolerant
finance.json GDPR, $80/mo, local-pinned, expiryMs=180_000 (3min)
ops.json SOC2, $50/mo, local-pinned, synthetic-HTTP bench scenario;
TODO(phase-3-http-fetch) for the unbuilt http_fetch tool
support.json SOC2, $40/mo, cloud-tolerant
hr.json GDPR, $30/mo, local-pinned (employee PII = finance-grade)
exec.json GDPR, $60/mo, local-pinned, references §3.5.4
founder-bootstrap trust elevation for share-context on Day 1
New code:
v3/@claude-flow/cli/src/business-pods/domain-affinity-policy.ts (86 LOC)
- selectAgentBackend(pod): {backend, reason}
- rules: preferLocalExecution=true → local-stdio
else if budget.monthlyUsd >= 50 → cloud-managed
else → remote-peer
v3/@claude-flow/cli/src/mcp-tools/business-pod-tools.ts (+107 LOC)
- new MCP tool: business_pod_route_backend
- shared loadTemplate(input: object | string) helper
Schema mirror in lockstep: added `base-template-generator` to KNOWN_AGENT_TYPES
in BOTH TS (pod-schema.ts) and JS (pod-tick.mjs) copies.
Gates (all PASS):
- Build: clean
- vitest business-pod-tools: 44/44 PASS (was 19; +18 Phase 3 cases)
- node:test pod-tick: 21/21 PASS (was 15; +6 happy-path tests)
- ADR-112 audit: 351/351 with guidance (was 350; +1 new tool)
- business-pods smoke: 11/11 PASS (was 8; +3 Phase 3 steps)
- agentbbs regression smoke: 8/8 PASS
- agenticow regression smoke: 8/8 PASS
Phase 4 follow-ups (inline TODOs):
- http_fetch MCP tool implementation (referenced by ops.json)
- @metaharness/router wire point in policy-engine.ts
- ruflo federation trust elevate ... --to TRUSTED CLI escape hatch
- Live-mode dispatch (Managed Agent + claude -p wiring)
- Atomic SQLite budget tracker swap (ADR-164.1)
Per ADR-164 §3.4, all rules codified verbatim; smoke step 11 + 4 vitest cases
assert what the rules produce per template. Live mode still exits 3 with
"Phase 4" message — Phase 3 is templates + validator + routing-policy only.
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* feat: Phase 4 — http_fetch + atomic budget tracker + federation trust elevate
Three Phase 4 deliverables landing per ADR-164:
A. http_fetch MCP tool (ADR-164 §5.1.8)
- 1 new tool (#352) for ops-pod's synthetic-endpoint bench
- Security-default-rejects: private IPs (RFC-1918, localhost), auth
headers (Authorization/Cookie/X-Auth-*) unless env vars opt-in
- URL allowlist + timeout + response-size cap (256 KB default, 1 MB max)
- 25/25 vitest pass (URL allowlist, timeout abort, truncation,
auth-header rejection, happy path against node:http mock)
B. Atomic SQLite budget tracker (ADR-164.1 §3-§5)
- bbs_budget_rooms + bbs_budget_reservations tables
- reserve/commit/release with BEGIN IMMEDIATE + _lock_bump
- committed_post_expiry state machine (Expired Commit Leak fix from
peer review 2026-06-29) implemented
- expires_at clamped to [5_000, 300_000] ms per-pod override
- Behind CLAUDE_FLOW_BBS_ATOMIC_BUDGET=1 — file-based stub remains
the default until next flip; pod-tick.mjs migration deferred to
Phase 5
- 15/15 vitest pass (Tests 1, 2, 3, 6 from ADR-164.1 §9, skipping
Test 5 clock-skew which would require system-clock manipulation)
- reservationId is randomUUID v4 (ADR-164.1 §3.2 notes v7 is purely
aesthetic — v7 generator would add a transitive dep we don't need)
C. ruflo federation trust elevate CLI (ADR-164 §3.5.4)
- New subcommand: bypasses 500-interaction TRUST_TRANSITION_THRESHOLDS
- Mandatory --reason + --audit flags (both required by spec)
- Refuses unknown peer node-ids
- Reuses existing trust_level_changed audit envelope with
metadata.tag='bootstrap_elevation' + metadata.operatorBypass=true
(cheapest path — keeps SEVERITY_BY_EVENT_TYPE / CATEGORY_BY_EVENT_TYPE
stable rather than introducing a new event-type that needs propagation
through downstream consumers)
Gates (all PASS):
- Build: clean (tsc)
- vitest http-fetch + bbs-budget-tracker: 40/40 PASS (25 + 15)
- vitest business-pod-tools regression: 44/44 PASS (Phase 3 still green)
- ADR-112 audit: 352/352 with guidance (was 351; +1 http_fetch)
- business-pods smoke: 11/11 PASS
- agentbbs smoke: 8/8 PASS
- agenticow smoke: 8/8 PASS
Phase 5 follow-ups (explicit deferrals):
- Live-mode dispatch (pod-tick --live still exits 3)
- Sweeper timer integration site (daemon worker, not pod-tick)
- Spend-reporter audit adapter (write to federation_spend namespace
BEFORE BEGIN IMMEDIATE per ADR-164.1 §6.1)
- pod-tick.mjs migration from file-based to atomic tracker
- ACL gate on `federation trust elevate` (currently consistent with
`federation evict` / `reactivate` — no founder-only crypto check yet)
- http_fetch wiring into pod-tick live-mode for ops bench
Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni
* chore(lock): regen v3/pnpm-lock.yaml with agentbbs entry (PR #2503 CI fix)
Same fix as we did on the agenticow PR #2500 push — pnpm install at root
regenerates pnpm-lock.yaml (the npm workspace), but the real workspace is
v3/pnpm-workspace.yaml and its sibling v3/pnpm-lock.yaml. CI uses
--frozen-lockfile so the v3 lockfile must be in sync with v3/@claude-flow/cli's
package.json (which declares agentbbs: ~0.1.0 as optional).
* fix(ci): re-export-tolerant agentbbs guard + skip business-pods smoke under --ignore-optional
PR #2503 CI surfaced 2 ADR-164 issues:
1. no-agentbbs-smoke Rule 2 false-positive on mcp-tools/index.ts.
The static-grep treated `export { agentbbsTools } from './agentbbs-tools.js';`
as an unguarded agentbbs reference. The agentbbsTools symbol itself
contains the loadAgentbbs() guard — the index.ts re-export is benign.
Fixed: strip re-export + spread + import-of-agentbbsTools patterns + all
comments before the unguarded-reference check.
2. ruflo-business-pods smoke 9/11 under no-metaharness-smoke's runtime
drill (which does `npm install --ignore-optional`). Without optional
deps, vitest may be absent AND the cli dist may not exist. Steps 4
(vitest) and 11 (call into dist) now SKIP cleanly when those are
missing instead of failing — the main test-suite jobs still gate
the full vitest + build runs.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): business-pods-smoke uses pnpm (root npm chokes on workspace:*)
The root package.json declares some workspace deps with the pnpm `workspace:*`
protocol that npm doesn't support. Symptom: `npm install` step exited with
EUNSUPPORTEDPROTOCOL.
The v3/ tree is a real pnpm workspace (v3/pnpm-workspace.yaml). Switch the
workflow to install + build from there using pnpm + frozen-lockfile, then
fall through to vitest / node:test / smoke contract.
Pattern matches the existing v3-ci.yml install steps.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): pnpm --filter '@claude-flow/cli...' to include workspace deps
The previous `pnpm --filter @claude-flow/cli build` didn't build workspace
dependencies first, so the cli's tsc step failed with TS2307 errors looking
for @claude-flow/memory, @claude-flow/neural, @claude-flow/cli-core types.
The `...` suffix tells pnpm to include all of the cli's workspace
dependencies in the build graph.
Applied to both business-pods-smoke.yml and no-agentbbs-smoke.yml's
runtime drill.
Co-Authored-By: RuFlo <ruv@ruv.net>
* fix(ci): pnpm -r build (whole workspace, dep-first) — pnpm filter can't
discover cross-package dist/ imports
Round 4 surfaced two pre-existing fragilities in the workspace's build wiring:
1. business-pods-smoke: @claude-flow/cli imports from @claude-flow/swarm/dist/
not via package.json deps but via direct file path. `--filter "@claude-flow/cli..."`
doesn't traverse those. Fixed: `pnpm -r --no-bail build` builds the whole
workspace dep-first, with a fallback to a direct cli build.
2. no-agentbbs-smoke runtime drill: `--no-optional` stripped agentdb, which
is a transitive consumer of @claude-flow/neural and breaks neural's tsc
even though neural has its own optional-degradation path internally.
Fixed: install everything, then SURGICALLY rm node_modules/agentbbs only,
so only the dep we're testing graceful-degradation for is missing.
Co-Authored-By: RuFlo <ruv@ruv.net>
ADR-150 sibling-package integration. `@metaharness/redblue` runs an
adversarial red-team → judge → blue-team patch → retest → report loop
against an LLM target you own. Covers OWASP LLM Top-10 / NIST AI RMF
families (prompt injection, tool misuse, data leakage, jailbreaks,
denial-of-wallet). Joins score/genome/mcp-scan/threat-model/oia-audit
as the run-time red/blue layer of the security plugin surface.
Why integrate here vs ruflo-aidefence or ruflo-security-audit:
- aidefence is detection (PII / prompt-injection scan); redblue is
*generation* — they complement, redblue doesn't replace it
- security-audit is dep CVEs / static scan; redblue is run-time LLM eval
- ruflo-metaharness already carries the @metaharness/* wrapper pattern
(`_darwin.mjs`, `_harness.mjs`), the locator, the MCP-tool registration
surface, and the smoke/CI gates — redblue slots in as one more sibling
Surface added:
- `npx ruflo metaharness redblue {init|run|patch|attack|report}` CLI
- `metaharness_redblue` MCP tool (subcommand + family + tests + patch +
mockJudge + alertOnFail + timeoutMs)
- Skill discoverability via CLAUDE.md (both CLI catalog + MCP tool catalog)
- 11 metaharness subcommands (was 10), 13 MCP tools (was 12)
Safety posture (inherited verbatim from upstream; wrapper does NOT relax):
- upstream `src/config/safety.ts` hard-enforces no real credentials, no
live external targets (loopback / *.test / *.internal only), no shell,
no arbitrary network, no eval at config-load time — a config that
enables any of these errors at load
- `--mock-judge` is the $0 marker-fixture path for CI / offline; the real
model judge requires `OPENROUTER_API_KEY` and is capped by
`max_cost_usd` / `max_runtime_minutes` / `max_tests`
- wrapper shells out with `shell: false` argv arrays; never string interp
- ADR-150 graceful-degradation rule #3 — on install/network failure the
wrapper returns `{degraded: true, reason: ...}` and exits 0 so ruflo
stays operational
Upstream bug workaround (track for revert):
`@metaharness/redblue@0.1.1`'s CLI bootstrap uses
`isMain = import.meta.url === \`file://\${process.argv[1]}\``. When npx
links `redblue` → `dist/cli/index.js`, argv[1] is the symlink path but
import.meta.url is the resolved real path, so isMain is false and the
binary silently exits 0 with no output, no file, no error. Darwin's CLI
calls `main()` unconditionally and is unaffected. Workaround: install the
package once into `~/.ruflo/redblue-cache` via `npm install --prefix` and
invoke `node <abs_path>/dist/cli/index.js` directly — argv[1] then equals
the real path and isMain becomes true. First install hits npm's cache so
the cold path is ~200ms; warm invocations are ~20ms.
Locator hardening (prevents recurrence of artifact-mirror staleness):
The publish artifact at `v3/@claude-flow/cli/plugins/ruflo-metaharness/`
is regenerated only at `prepublishOnly`. On a dev tree with a fresh
script in source but a stale mirror, the locator would pick the mirror
because `_harness.mjs` exists in both. Locators in `commands/metaharness.ts`
and `mcp-tools/metaharness-tools.ts` now accept an optional `requiredScript`
that narrows the match to dirs containing the dispatched script. The
artifact mirror is also synced with the two new redblue scripts so the
publish artifact stays usable until the next `prepublishOnly`.
Gates updated to lock new state:
- smoke.sh: 9 subcommands in dispatcher (was 8), 11 in description list
(was 10), 13 MCP tools (was 12), 13 mcp-script-count (was 12), 14
MCP_SUCCESS_SEMANTIC footnotes (was 13), 13 `success: r.success`
occurrences (was 12), tilde-pin check covers @metaharness/redblue
- test-mcp-tools.mjs: `tools.length === 13`, `metaharness_redblue`
enumerated, attack-preview Phase-3 input, 180s timeout (cold-cache npx
fetch class)
- CLAUDE.md: surfaced under both CLI catalog and MCP-tool catalog (gated
by smoke 17z56 + 17z57)
Verification:
- `bash plugins/ruflo-metaharness/scripts/smoke.sh` → 120 passed, 0 failed
- `node plugins/ruflo-metaharness/scripts/test-mcp-tools.mjs` → 153 passed, 0 failed
- `node v3/@claude-flow/cli/bin/cli.js metaharness redblue init --out <path>`
→ writes the safety-asserting sample config, exits 0
- attack preview, mock-judge run (3-test → real findings report), and
CLI dispatcher all exercised end-to-end before commit
Co-Authored-By: RuFlo <ruv@ruv.net>
This iter-4 edit was made by the headless agent but its commit step
didnt land in the branch (rate-limit at end of workflow). Cleanly
landing it now alongside the lockfile fix.