Commit Graph
386 Commits
Author SHA1 Message Date
ruv 8f4b47af16 fix(security): migration-safe hive-mind gating by caller transport (ADR-476, #3338)
Gate hive-mind init/join/leave/spawn/propose/vote/broadcast/shutdown/
memory set+delete/optimize-memory for remote (HTTP/WebSocket) callers only;
local stdio, ruflo mcp exec, the CLI and in-process callers keep working
with no extra step. hive-mind_init never returns hiveToken. Operator secret
from RUFLO_HIVE_BOOTSTRAP_SECRET or a 0600 bootstrap.secret created by the
first local init. state.json is written 0600 atomically (dir 0700).
Constant-time compare. RUFLO_HIVE_REQUIRE_AUTH=1 for bridged stdio.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 10:18:44 -04:00
ruv f6fda0e569 Merge origin/main into dream/2026-09-16-security (drop LEDGER.md hunk)
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 10:02:03 -04:00
rUv d4dc8054a0 Merge pull request #3871 from ruvnet/fix/agentdb-3691-3693
fix(memory): honest pattern-store failures; share AgentDB's SQLite copy in graph writer
2026-10-06 21:58:47 -07:00
ruv 67261ac049 fix(memory): honest agentdb_pattern-store failures; share AgentDB's better-sqlite3 for graph writer (#3691, #3693)
- bridgeStorePattern no longer turns a bridgeStoreEntry {success:false} into a success receipt
- agentdb_pattern-store checks storeEntry's result in the registry-null fallback and refuses failed writes
- hooks pattern-store falls back to the direct store when the bridge write was refused
- graph writer, native recovery/repair and attestation open SQLite via the better-sqlite3 copy AgentDB resolves, so the idle close cannot strip a live AgentDB handle's WAL/SHM sidecars

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-07 00:28:39 -04:00
Rudy Celekli bc6d654d22 fix(session): round-trip compressed JSON backups
Signed-off-by: Rudy Celekli <rudy@gradiahq.com>
2026-10-06 13:18:04 -04:00
ruv 39d73ea1eb fix(mcp): absent URL assertions use the configured base; loopback HTTP in operator config
Review follow-ups on the destination pinning:
- null and "" now mean "no assertion" (MCP clients commonly send null for
  optional fields) instead of throwing; the destination still comes only
  from server configuration, so this cannot widen anything.
- Operator configuration may name a plain-HTTP loopback service
  (localhost, 127.0.0.1, [::1]) for a local or self-hosted gateway/LLM.
  Public http:// and lookalike hosts (localhost.attacker.example,
  127.0.0.1.nip.io, 10.0.0.1) stay rejected. An argument must still equal
  the configured base exactly, so it can never select a loopback port the
  operator did not.
- Note: this supersedes ADR-125's "tool argument beats env var" precedence
  for RUFLO_X_GATEWAY_URL and SERAPHINA_METALLM_URL; arguments are now
  assertions only.

Tests: mcp-service-url-security 37/37 (new: absent overrides, loopback
config and port mismatch, lookalike hosts; 0/false/{} still rejected),
x-federation-tools passes; CLI build clean; env-var precedence audit ok.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-02 11:08:53 -04:00
Dragan Spiridonov 68283ba7fc fix(mcp): pin service destinations to server configuration
Validate configured HTTPS bases and matching compatibility arguments before I/O, reject redirects, and retain operator-only destination selection for federation and Seraphina tools.

Prepared by Codex in Dragan’s authorized session.
2026-10-02 09:44:58 +02:00
ruv 48ec166d9b fix(missions): ADR-112 guidance in mission MCP tool descriptions
Each mission_* description now states when to use it and why the nearest
alternative (task_create, memory_store, task_status, polling mission_get,
task_cancel) is wrong. scripts/audit-tool-descriptions.mjs: 392/392 with
guidance, all gates pass.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-01 22:58:17 -04:00
ruv 0483ac5517 feat(missions): ADR-406 M1 mission observation via CLI and MCP, e2e gate
`ruflo mission create|plan|get|events|action` and the mission_create,
mission_plan, mission_get, mission_events and mission_request_action MCP
tools are thin transports over the one MissionService and its zod schemas;
MCP calls are still authorized by the existing policy runtime in
mcp-client.ts. A bounded, sanitized .claude-flow/missions/observation.json
(contract ruflo.mission-observation/1, source-time observedAt) is rewritten
atomically after each committed event for the workbench to read.

scripts/e2e-adr-406.mjs runs the built CLI in throwaway HOME,
CLAUDE_CONFIG_DIR and project dirs: catalog current and verified, legacy
command files byte-unchanged, CLI create + MCP plan reading identical
records and events, revision conflict, honest admit refusal, SIGKILL of a
writer then restart, and the §18 fixture replay with mods off vs on
(permissions, policy mode and outcomes unchanged; uninstall restores).
RUFLO_E2E_LIVE=1 adds engine version and plugin validate (no model calls).

Mod hooks the engine confirms are recorded against their declaring source
file, so the catalog is identical with or without an engine. mission_*
tools are classified in the capability brain's tasks/workflows domain.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-10-01 22:34:58 -04:00
rUv 77befe1d90 Merge pull request #3582 from ruvnet/fix/3566-sibling-disclosure
fix(memory): disclose the sibling AgentDB store on partial hits too (#3566)
2026-09-30 19:19:09 -04:00
rUv 747d074833 Merge pull request #3571 from drakeo338/claude/3570-fix
fix(memory): validate namespace on memory store and memory import
2026-09-30 19:16:50 -04:00
rUv 63c041f766 Merge pull request #3581 from ruvnet/fix/3567-route-abstain
fix(hooks): route no longer reports its highest confidence when nothing matched (#3567)
2026-09-30 19:09:34 -04:00
ruvanddrakeo338 b1811363ec fix(memory): one validator for namespaces and keys across store, import, export and purge (#3570 follow-up)
Follow-up to drakeo338's fix, closing the remaining gaps found in review:

- Keys: MCP memory_store rejected `../` in keys, but CLI `memory store`
  and `memory_import` accepted it. The MCP rule (DANGEROUS_KEY_PATTERN)
  is now exported through `memoryKeyError()` and used by all three;
  import checks every key up front, so a bad file writes nothing. Keys
  with a plain `/` (`probe/x`) stay legal.
- Purge: `purgeNamespace` used its own NAMESPACE_PATTERN, which rejected
  `:`, so `team:alice` could be stored and exported but never purged. It
  now uses `validateIdentifier`, like the other three operations.
- MCP memory_store: namespaces only faced the key blacklist, so
  `proj/sub` was accepted there but rejected by export and purge. It now
  uses `validateIdentifier` too.

Tests added to memory-store-import-namespace-3570.test.ts: each gap fails
on the prior head and passes here, plus a round-trip table asserting that
CLI store, MCP store and purge accept exactly the namespaces export
accepts.

Co-Authored-By: drakeo338 <drakeo338@users.noreply.github.com>
Co-Authored-By: RuFlo <ruv@ruv.net>
2026-09-30 18:07:28 -04:00
ruv 18d6a7b70c fix(session): import round-trips and save actually includes memory (#3573, #3575)
#3575: `session import` passed a parsed `data` object to session_import,
which required `inputPath`, so it returned { error }; the CLI then printed
"Session imported" and crashed reading result.stats. The CLI now passes
the path, session_import also accepts an inline `data` record, and every
session subcommand checks the tool's { error } before printing success.
`session export` with no id now refuses (like delete) unless --latest is
given, and import/export help names the required positional argument.

#3573: session_save read only the pre-SQLite .claude-flow/memory/store.json,
which current installs never write, so --include-memory (default true)
saved nothing and reported "Memory Entries: 0". It now snapshots the live
memory DB plus rows found only in the sibling AgentDB store (deduped by
namespace+key), restore writes them back and reports the count actually
written, and the table says "not included" instead of an invented 0.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-09-30 18:02:04 -04:00
ruv 45a3b2ddd2 fix(hooks): route no longer reports its highest confidence when nothing matched (#3567)
suggestAgentsForTask() ended with a hard-coded { confidence: 0.7 } reached
only when no keyword or learned pattern matched. Blank, punctuation-only and
non-English tasks therefore routed to `coder` at 70%, above a correctly
routed "deploy the release to production" (62%).

The no-match path now returns NO_MATCH_CONFIDENCE (0.3, below every real
signal: keyword hits >= 0.8, learned >= 0.7, eligible semantic > 0.4, and the
same value the helper router already uses) with matched: false,
reason: 'no-match-default' and a note saying why (no words, or the keyword
matchers are English-only). Tasks with no letters or digits skip semantic
scoring. hooks_route, hooks_explain and hooks_pre-task surface the marker;
the CLI labels the box "Default Suggestion (nothing matched)", reports
success probability as unknown, and refuses a whitespace-only --task like an
empty one.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-09-30 17:58:57 -04:00
ruv 91ea1b524e fix(memory): disclose the sibling AgentDB store on partial hits too (#3566)
`memory search` and `memory retrieve` disclosed the sibling AgentDB store
(.swarm/agentdb-memory.db, written by the MCP path) only in their
empty-result branches, so a partial hit ("Found 1 results") read as
complete while the other store's rows went unread. The disclosure now
runs on every search path (semantic, hybrid, keyword-only, text and
JSON) and on a found retrieve, worded as "Partial result: N matches
came from the store read here". Warnings go to stderr, so --format json
and --value-only stdout stay parseable.

Also: `memory import` reported "Vectors: 0" while every value was
re-embedded. The memory_import tool now counts the vectors storeEntry
actually wrote.

Fixes #3566

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-09-30 17:56:03 -04:00
drakeo338 34b5c0ff51 fix(memory): validate namespace on memory store and memory import (#3570)
The CLI store path and memory_import wrote a namespace containing ../,
which memory export and purge reject, leaving entries they cannot read or
clean up. Validate with validateIdentifier before any write; import checks
every entry first so a bad file persists nothing.
2026-09-30 20:17:43 +00:00
ruv e69bc340cf feat(federation): add guarded public registration and release 3.47.0 2026-09-28 17:16:02 -04:00
rUv fa61df2ef2 fix(hive-mind): dispatch submitted tasks to workers and record results (#3524)
Three defects kept a hive task pending with its worker idle forever:

1. Nothing consumed the queue. `hive-mind task` only wrote a pending row;
   workers are records, not processes. New `hive-mind work` claims the
   oldest pending hive task, assigns it to an idle hive worker, runs it
   through `claude -p --output-format json`, and records the outcome via
   task_complete (or task_update status=failed).

2. task_assign/task_complete/task_cancel synced only
   `.claude-flow/agents/store.json`, but hive workers live in
   `.claude-flow/agents.json` (#1916). Assignment never marked a hive
   worker busy and completion never counted it. They now update
   whichever store holds the agent. task_update gains `result` and
   frees workers on `failed`.

3. `spawn --claude` fell back to passing `~/.claude.json` as
   --mcp-config. Where that file has no top-level `mcpServers` (a fresh
   desktop), Claude exits with "Invalid MCP configuration: mcpServers:
   Invalid input". The worker config is now always generated: servers
   are extracted from the source config, a `ruflo` server pinned to the
   running CLI is guaranteed, and CLAUDE_FLOW_CWD points it at the
   dispatcher's stores.

Also fixes the "Track with: hive-mind task-status" hint, which named a
subcommand that does not exist.
2026-09-28 11:38:57 -04:00
ruv 850bd7991e Revert "perf(hooks): restore the in-memory fast path for trajectory lookups"
This reverts commit 5a45b76c8. The fast-path broke trajectory-recovery-3199's
own regression test ("reloads a clean cache after another process adds a
step"): with vi.resetModules() simulating separate processes, a first
process's clean-but-now-stale in-memory copy would win over the freshly
persisted cross-process step, since the fast path never re-read disk when
the local cache was merely clean rather than empty. That's the exact
scenario #3467 was written to fix — the "cost" the fast path removed was
the correctness guarantee, not just overhead. Local runs of the
unmodified #3467 code average 20-46ms on graph-trajectory-hooks-smoke's
200ms budget; the one observed 1171ms CI failure is far more likely
explained by that round's runner queue (this same PR's other jobs sat
queued 40+ minutes on ordinary infra load) than a real regression.
2026-09-27 15:24:21 -04:00
ruv 5a45b76c80 perf(hooks): restore the in-memory fast path for trajectory lookups
#3467 made loadPendingTrajectory() always do two DB reads (completed +
pending) before returning, even when the trajectory is already tracked
cleanly in-process — turning every trajectory-step/post-task call into
a synchronous round-trip instead of a Map lookup. CI's
graph-trajectory-hooks-smoke (ADR-130 P3, <200ms budget) failed once on
a loaded runner at 1171ms; local runs stayed at 20-46ms, so this was
likely a transient load spike, but the always-hit-disk path was real
overhead regardless. Skip both reads when the id is already a clean
(non-dirty) in-memory hit — the case #3467 didn't change (same-process,
not-yet-restarted). The disk-recovery path #3467 added still runs
exactly when it's needed: on a cache miss (e.g. after an MCP restart).
2026-09-27 15:07:49 -04:00
ruv 1d79068c56 fix(ci): repair CI regressions surfaced by the integrated community fixes
- plugins/ruflo-adr smoke step 20: #3432 correctly split the memory-db
  cwd into a more precise DB_ROOT (nearest .git/.swarm ancestor of ROOT),
  but the smoke check still only recognized the literal `cwd: ROOT`
  string. Accept `cwd: DB_ROOT` too.
- plugins/ruflo-core smoke step 6: #3428 replaced the old "pinned to
  v3.6" CLI compatibility line with an accurate description of the new
  resolve-installed-before-npx-fallback contract. Updated the smoke
  check to verify that contract's env vars are documented instead of a
  version pin that no longer exists.
- session-tools.ts: CodeQL flagged Math.random()-derived session IDs as
  insecure randomness in a security context, newly reachable through
  #3486's activate path. Switched both session ID generators to
  randomUUID(), matching the convention already used in mcp-server.ts
  and autopilot-state.ts.
2026-09-27 13:30:29 -04:00
ruv 2d8bab762f Merge PR #3486: fix(session): restore imported state before reporting activation 2026-09-27 13:15:52 -04:00
ruv b9f60a948c Merge PR #3483: fix(tasks): preserve current agent ownership during task retirement 2026-09-27 13:15:51 -04:00
ruv e62e96cc43 Merge PR #3482: fix(session): honor memory exclusion when exporting snapshots 2026-09-27 13:15:51 -04:00
ruv b757009733 Merge PR #3479: fix(session): honor component selectors before restoring stores 2026-09-27 13:15:50 -04:00
ruv a83aa4307a Merge PR #3472: fix(mcp): isolate and bound governance audit logs 2026-09-27 13:15:49 -04:00
ruv b5105bda5e Merge PR #3471: fix(graph): query retained SQL relationships for k-hop 2026-09-27 13:15:48 -04:00
ruv 7f9b880c03 Merge PR #3469: fix(learning): preserve zero quality and reject invalid scores 2026-09-27 13:15:48 -04:00
ruv 3e6a2d5377 Merge PR #3467: fix(learning): recover pending trajectories after MCP restart 2026-09-27 13:15:47 -04:00
ruv 2ea6a97c44 Merge PR #3463: fix(memory): honor the selected database in memory stats 2026-09-27 13:15:45 -04:00
ruv 580980a0fe Merge PR #3462: fix(learning): create skills from validated task patterns 2026-09-27 13:15:36 -04:00
ruv 57088a8f1b Merge PR #3456: fix(hooks): expire command history and preserve failed outcomes 2026-09-27 13:14:14 -04:00
ruv aa6cb07191 Merge PR #3453: fix(mcp): report unsupported memory consolidation honestly 2026-09-27 13:14:01 -04:00
ruv 9a9c488543 Merge PR #3425: fix(memory): import into the CLI-selected database 2026-09-27 13:12:33 -04:00
Rudy Celekli 3fb168e686 fix(session): restore imported state before reporting activation 2026-09-27 10:36:26 -04:00
Rudy Celekli e22b3c9414 fix(tasks): preserve current agent ownership during task retirement 2026-09-27 10:31:41 -04:00
Rudy Celekli 058d85f5d5 fix(session): honor memory exclusion when exporting snapshots 2026-09-27 10:29:54 -04:00
Rudy Celekli 55be3a7efa fix(session): honor component selectors before restoring stores 2026-09-27 10:25:16 -04:00
Rudy Celekli 3d87b4e7d3 fix(mcp): allow explicit audit destination before environment 2026-09-26 21:24:37 -04:00
Rudy Celekli d47ed5eb34 fix(graph): retain graph query selection guidance 2026-09-26 21:18:05 -04:00
Rudy Celekli 2bd489d3b2 fix(mcp): retain consolidation tool selection guidance 2026-09-26 21:18:03 -04:00
Rudy Celekli a1013a7988 fix(mcp): isolate and bound governance audit logs 2026-09-26 20:01:03 -04:00
Rudy Celekli 6413557bc3 fix(learning): retain uncheckpointed steps and serialize updates 2026-09-26 19:56:14 -04:00
Rudy Celekli 71e5844245 fix(memory): normalize numeric timestamps in store statistics 2026-09-26 19:55:47 -04:00
Rudy Celekli e88ce4702f fix(graph): query retained SQL relationships for k-hop 2026-09-26 19:55:09 -04:00
Rudy Celekli c2a8ad58e2 fix(learning): preserve zero quality and reject invalid scores 2026-09-26 19:38:29 -04:00
Rudy Celekli 13723ca65a fix(mcp): keep consolidation schema within shared interface 2026-09-26 19:35:57 -04:00
Rudy Celekli c195cad66c fix(learning): recover pending trajectories after MCP restart 2026-09-26 19:34:40 -04:00
Rudy Celekli 42df589065 fix(memory): report statistics for the selected database 2026-09-26 19:32:10 -04:00