From b0f1698ee917b19850a32db8b5be95f3b7702d59 Mon Sep 17 00:00:00 2001 From: Paul Keen <125715+pftg@users.noreply.github.com> Date: Sat, 22 Aug 2026 12:39:36 +0200 Subject: [PATCH 1/2] Ruflo frictionless setup: bootstrap self-heal, shared worktree memory, OKF mirror rule Every new session now gets a working ruflo runtime with zero manual steps: - bin/agent-bootstrap (SessionStart hook) self-heals the two silent failure modes found 2026-08-22: regenerates gitignored .claude/helpers/ via `init upgrade` when the hook handler is missing (otherwise every settings.json hook no-ops behind `|| true`), and symlinks a fresh worktree's .swarm to the main checkout so all sessions share ONE memory DB instead of writing to a store that dies with the worktree. Skipped in CI. Verified end-to-end in this worktree: symlink created, plain `memory list -n okf` reads the shared DB's 30 backfilled entries with no env override. - .okf/workflows/ruflo-runtime.md (new concept) + index row: the runtime map, the okf-namespace mirror + sync rule, distill targets agentdb-memory.db (first run: 660 reasoning patterns, 650 causal edges, 44 promoted), and the v3.6.30 CLI bugs pinned so nobody re-fights them. - CLAUDE.md OKF section: one-line Ruflo-mirror sync rule (concept change => upsert its okf-* memory entry, same commit). - Dated .okf/log.md entry rides this commit (ENFORCED rule). Gates: OKF validator 0 ERRORS (123 warnings, known-red --strict state); bootstrap block exercised live (output in PR); docs+tooling-only diff. Co-Authored-By: Claude Fable 5 --- .okf/log.md | 14 +++++++ .okf/workflows/index.md | 1 + .okf/workflows/ruflo-runtime.md | 65 +++++++++++++++++++++++++++++++++ CLAUDE.md | 2 +- bin/agent-bootstrap | 18 +++++++++ 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 .okf/workflows/ruflo-runtime.md diff --git a/.okf/log.md b/.okf/log.md index 6b04a1009..445c4da41 100644 --- a/.okf/log.md +++ b/.okf/log.md @@ -111,6 +111,20 @@ Also corrected: the ~1e-6 noise figure in test-gates and in the code comment was macOS-local and read as universal. Same overclaim shape the #566 reviewer caught one layer down. +## 2026-08-22 - ruflo self-learning enabled, memory unified, OKF backfilled + +Two silent failure modes closed: fresh worktrees had dead learning hooks +(`.claude/helpers/` is gitignored; every settings.json hook no-opped behind +`|| true` - stats sat at zero for months) and a private `.swarm` memory DB +that died with the worktree. `bin/agent-bootstrap` now self-heals both at +SessionStart: `init upgrade` when the handler is missing, and a `.swarm` +symlink to the main checkout so every session shares ONE memory store. +The OKF bundle was backfilled into ruflo memory (namespace `okf`, one entry +per concept + pointer) with a sync rule, and the first distill run mined 660 +reasoning patterns / 650 causal edges (44 promoted) from the main agentdb. +Full runtime map incl. the v3.6.30 CLI bugs: +[ruflo-runtime](workflows/ruflo-runtime.md). + ## 2026-08-22 - STATUS.md round two: the surface broke its own rule on commit one A clean-context peer reviewer (second, independent 4-eyes pass after the diff --git a/.okf/workflows/index.md b/.okf/workflows/index.md index 97fbbdf6b..7616e3ade 100644 --- a/.okf/workflows/index.md +++ b/.okf/workflows/index.md @@ -12,3 +12,4 @@ * Test suites, rake tasks, and the visual-regression gate live in [test-gates](/build/test-gates.md) (`workflows/testing.md` was squashed into it 2026-08-20 - it duplicated the gate rules and still carried the superseded "run both suites per commit" instruction) * [Analytics Access](analytics-access.md) - live GA4 + Search Console MCP servers, correct property IDs, credential split, data-lag traps, and why GA4 sessions must be reconciled against GSC clicks before being quoted * [Outbound Sprint Machinery](outbound-sprint.md) - 2607 browser-agent send/monitor loop, pipeline ledger, board conventions, mail-routing gotchas +* [Ruflo runtime](ruflo-runtime.md) - agent-bootstrap self-heals the gitignored scaffolding, worktrees share the main .swarm memory via symlink, the okf memory namespace mirrors this bundle, and the v3.6.30 CLI bugs not to re-fight diff --git a/.okf/workflows/ruflo-runtime.md b/.okf/workflows/ruflo-runtime.md new file mode 100644 index 000000000..c6a620322 --- /dev/null +++ b/.okf/workflows/ruflo-runtime.md @@ -0,0 +1,65 @@ +--- +type: Playbook +title: Ruflo runtime - self-heal, shared memory, and the learning loop +description: How ruflo (claude-flow) runs in this repo - bin/agent-bootstrap self-heals the gitignored scaffolding, worktrees symlink .swarm to the main checkout so memory is shared, and the okf memory namespace mirrors the OKF bundle one entry per concept. +tags: [ruflo, claude-flow, memory, hooks, learning] +generated: + by: claude-fable/5 + at: 2026-08-22T00:00:00Z +timestamp: 2026-08-22T00:00:00Z +--- + +Ruflo = `@claude-flow/cli` (same codebase, two npm names). The repo commits NO +ruflo artifacts - `.claude/helpers/`, `.swarm/`, `.claude-flow/`, and +`claude-flow.config.json` are all gitignored scaffolding. That design created +two silent failure modes, both closed 2026-08-22 by a self-heal block in +`bin/agent-bootstrap` (the SessionStart hook): + +1. **Dead hooks**: every `.claude/settings.json` hook calls + `.claude/helpers/hook-handler.cjs` with `|| true`. In a fresh + worktree/checkout the helper does not exist, so the whole learning pipeline + no-ops silently (intelligence stats sat at zero for months). The bootstrap + now runs `npx @claude-flow/cli@latest init upgrade` whenever the handler is + missing - `init upgrade` regenerates helpers while preserving data and + never touches tracked files. +2. **Doomed worktree memory**: `.swarm/` is cwd-relative, so a worktree + session wrote to a private DB that died with the worktree. The bootstrap + now symlinks a worktree's `.swarm` to the main checkout's (only when + `.swarm` does not already exist), so every session - CLI and MCP tools - + reads and writes the ONE shared store. + +# The okf memory namespace mirrors this bundle + +Backfilled 2026-08-22: namespace `okf` holds one entry per OKF concept +(key `okf-
-`), each a distilled fact plus a pointer to its +`.okf/` file. Semantic recall routes a session to the right concept; the file +stays canon. **Sync rule: a commit that changes a concept's title/description +also upserts its `okf-*` entry** (`npx @claude-flow/cli@latest memory store +-n okf -k -v " Details: "`), or the namespace drifts from +the bundle. + +# The learning loop, and where each piece lives + +- `memory.db` - KV + vector store (memory_store/search; 384-dim ONNX + embeddings). `agentdb-memory.db` - the learning store (reasoning_patterns, + episodes, causal_edges, skills), fed by the in-session memory bridge. +- `memory distill run --db .swarm/agentdb-memory.db` mines agentdb entries + into reasoning patterns (first run 2026-08-22: 660 patterns, 650 causal + edges, 44 promoted). Plain `memory distill run` targets `memory.db`, which + by design has no pattern tables - the skip message "agentdb schema not + initialised" means you pointed it at the wrong DB, not that init is needed. +- 12 background workers exist (`hooks worker list`); the daemon runs them. + +# Version-pinned bugs (v3.6.30) - do not re-fight these + +- `config init` generates a config its own loader rejects ("reading 'map'" + warning on every call). Run on defaults; delete any generated config. +- `memory export` fails ("Exported to undefined"); `memory_import_claude` + finds 0 files even with `allProjects: true` (path-encoding). The auto-memory + corpus is deliberately NOT mirrored into ruflo - `MEMORY.md` already loads + every session. +- CLI `memory search --type semantic` returns empty in terminals (needs + @ruvector/core); single-term `--type keyword` works; real semantic search is + MCP-only. (Also in CLAUDE.md research protocol.) +- `CLAUDE_FLOW_DB_PATH` redirects store/list/search/retrieve but NOT + backup/init (cwd-resolved) - superseded by the symlink for normal use. diff --git a/CLAUDE.md b/CLAUDE.md index 89f9d10d3..307843ddf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,7 +40,7 @@ Operational knowledge lives in `.okf/` (`build/`, `content/`, `design/`, `workflows/` — one concept per file). Consume via progressive disclosure: `/okf:okf` (consume) at session start; never hand-read or hand-edit the bundle format — the skills carry the spec. Validate with `/okf:validate .okf --strict` before committing bundle changes. -**Maintain as you work (ENFORCED)**: a durable learning updates its concept + section index + a dated `.okf/log.md` entry, riding the SAME commit as the change — dispatch a background okf-maintainer in parallel, or inline for tiny fixes; a weekly maintain pass back-fills misses. A session that shipped durable knowledge without an OKF entry is not done. +**Maintain as you work (ENFORCED)**: a durable learning updates its concept + section index + a dated `.okf/log.md` entry, riding the SAME commit as the change — dispatch a background okf-maintainer in parallel, or inline for tiny fixes; a weekly maintain pass back-fills misses. A session that shipped durable knowledge without an OKF entry is not done. **Ruflo mirror**: a concept title/description change also upserts its `okf-
-` entry in ruflo memory namespace `okf` (backfilled 2026-08-22, one entry per concept; runtime map: `.okf/workflows/ruflo-runtime.md`). --- diff --git a/bin/agent-bootstrap b/bin/agent-bootstrap index 55aecb74d..5b7df0b54 100755 --- a/bin/agent-bootstrap +++ b/bin/agent-bootstrap @@ -21,6 +21,24 @@ bundle install --quiet || log "WARN bundle install failed - Ruby tests/validator log "bun install" bun install --frozen-lockfile >/dev/null 2>&1 || log "WARN bun install failed - PostCSS/lint unavailable" +# Ruflo (claude-flow) runtime self-heal. .claude/helpers/ and .swarm/ are +# gitignored scaffolding, so in a fresh worktree the settings.json hooks call a +# missing handler (silent no-op) and memory writes land in a DB that dies with +# the worktree. Skipped in CI: no MCP session there to feed. +if [ -z "${CI:-}" ]; then + log "ruflo runtime" + GIT_COMMON="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)" + MAIN_ROOT="${GIT_COMMON%/.git}" + if [ -n "$MAIN_ROOT" ] && [ "$MAIN_ROOT" != "$PWD" ] && [ -d "$MAIN_ROOT/.swarm" ] && [ ! -e .swarm ]; then + ln -s "$MAIN_ROOT/.swarm" .swarm && log " .swarm -> shared main-checkout memory DB" \ + || log "WARN .swarm symlink failed - ruflo memory will die with this worktree" + fi + if [ ! -f .claude/helpers/hook-handler.cjs ]; then + npx @claude-flow/cli@latest init upgrade >/dev/null 2>&1 && log " helpers regenerated (init upgrade)" \ + || log "WARN ruflo init upgrade failed - learning hooks will silently no-op" + fi +fi + # libvips runtime for screenshot diffs (Debian/Ubuntu containers) if ! ruby -e 'require "vips"' >/dev/null 2>&1 && type apt-get >/dev/null 2>&1; then log "installing libvips42" From 5ca1f6789a8273688824b4363e914be659f77f73 Mon Sep 17 00:00:00 2001 From: Paul Keen <125715+pftg@users.noreply.github.com> Date: Sat, 22 Aug 2026 12:46:31 +0200 Subject: [PATCH 2/2] Apply reviewer findings: full 39-concept mirror, honest versioning, sturdier guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - P1-1: backfilled the 10 concepts the first pass missed (architecture/ x7, content-strategy/ x3 — sections never enumerated); namespace now mirrors all 39 concepts; doc states the coverage, the key-prefix convention (okf-build/-content/-wf/-design/-arch/-cs/-log), and the fresh-MACHINE regeneration path (empty namespace on a new machine by design). - P1-2: bug list re-headed as dated observations on ruflo v3.38.16 — the bootstrap installs @latest, so no pin can hold; doc says re-measure. - P2-3: ln -s → ln -sfn, healing a dangling .swarm symlink (main checkout moved/renamed) instead of WARNing forever. - P2-4: init-upgrade success now measured by the handler file existing, not the npx exit code. - Reviewer's letter-vs-intent verdict adopted: STATUS.md update rule tightened to "ships a PR that changes a workstream's state" (STATUS.md + CLAUDE.md), so the rule can't be mechanically over-applied or quietly ignored. OKF validator: 0 ERRORS. bash -n clean. Co-Authored-By: Claude Fable 5 --- .okf/workflows/ruflo-runtime.md | 28 +++++++++++++++++++--------- CLAUDE.md | 2 +- STATUS.md | 3 ++- bin/agent-bootstrap | 12 +++++++++--- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/.okf/workflows/ruflo-runtime.md b/.okf/workflows/ruflo-runtime.md index c6a620322..4ca0d5584 100644 --- a/.okf/workflows/ruflo-runtime.md +++ b/.okf/workflows/ruflo-runtime.md @@ -30,13 +30,19 @@ two silent failure modes, both closed 2026-08-22 by a self-heal block in # The okf memory namespace mirrors this bundle -Backfilled 2026-08-22: namespace `okf` holds one entry per OKF concept -(key `okf-
-`), each a distilled fact plus a pointer to its -`.okf/` file. Semantic recall routes a session to the right concept; the file -stays canon. **Sync rule: a commit that changes a concept's title/description -also upserts its `okf-*` entry** (`npx @claude-flow/cli@latest memory store --n okf -k -v " Details: "`), or the namespace drifts from -the bundle. +Backfilled 2026-08-22: namespace `okf` holds one entry per OKF concept — all +39 concepts across all six sections, plus two log-derived lessons and the +backfill marker. Key prefixes abbreviate the section: `okf-build-`, +`okf-content-`, `okf-wf-` (workflows), `okf-design-`, `okf-arch-` +(architecture), `okf-cs-` (content-strategy), `okf-log-`. Each entry is a +distilled fact plus a pointer to its `.okf/` file; semantic recall routes a +session to the right concept, the file stays canon. **Sync rule: a commit +that changes a concept's title/description also upserts its `okf-*` entry** +(`npx @claude-flow/cli@latest memory store -n okf -k -v " +Details: "`), or the namespace drifts from the bundle. The mirror lives +in the gitignored `.swarm/` store, so a fresh MACHINE (not worktree) starts +with an empty namespace — regenerate by re-running the backfill: one store +per concept from its frontmatter title/description, exactly as above. # The learning loop, and where each piece lives @@ -50,9 +56,13 @@ the bundle. initialised" means you pointed it at the wrong DB, not that init is needed. - 12 background workers exist (`hooks worker list`); the daemon runs them. -# Version-pinned bugs (v3.6.30) - do not re-fight these +# CLI bugs observed 2026-08-22 (ruflo v3.38.16) - do not re-fight these -- `config init` generates a config its own loader rejects ("reading 'map'" +The bootstrap installs `@latest`, so no pin can hold - these are dated +observations, not version guarantees; re-measure before assuming one is fixed +or still present. + +- `config init` generates a config the loader rejects ("reading 'map'" warning on every call). Run on defaults; delete any generated config. - `memory export` fails ("Exported to undefined"); `memory_import_claude` finds 0 files even with `allProjects: true` (path-encoding). The auto-memory diff --git a/CLAUDE.md b/CLAUDE.md index 307843ddf..0b4be9d3e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,7 +84,7 @@ Operational knowledge lives in `.okf/` (`build/`, `content/`, `design/`, `workfl - **Feature/idea intake**: `/deliver ` (from the `jt-delivery` plugin) — triage → GOAL → author≠verifier orchestration per the `jt-delivery:contract` skill §1a; repo-specific bindings (gates, canon, reviewer routing): `docs/workflows/autonomous-delivery-prompt.md`. - **Manager triage (Paul 2026-08-01)**: Paul adds requests mid-flight; triage each against the active plan — now / sequenced / backlog / groom-first — and report the verdict in one line so he can override. Deferring is a decision; interrupting a gated pipeline for a non-critical request is the failure. **Autonomy grant**: handle sprints end-to-end; for big/critical calls AND any highly OPINIONATED question (design taste, naming, strategy trade-offs — anywhere reasonable people disagree) run a voting panel of subagents with DISTINCT PERSONAS/lenses and organize an explicit vote (Paul 2026-08-21); make the call (split + irreversible → hold for Paul). Record every autonomous call with its evidence. Paul's explicit words override any panel. - **Agent 4-eyes on EVERY stage, author ≠ verifier (Paul 2026-08-20, widened 2026-08-21)**: every change is written by one agent and verified by a different one; review lands BEFORE the artifact leaves the workshop (plan before Paul sees it, diff before commit, finding before reported, measurement before quoted). Brief reviewers with goal + artifact, never conclusions; ask for measurements, not verdicts. Internal sub-agents per stage — **model routing (Paul 2026-08-21): critical decisions, editing/outlining AND design critique on fable; coding, code review AND content writing on opus; mechanical/simple tasks on sonnet; spawns never inherit the session model implicitly — pass `model` on every Agent call**; `/codex:review` once at the merge gate for user-facing changes. Full protocol: `jt-delivery:contract` skill §5; repo routing: `docs/workflows/autonomous-delivery-prompt.md`. (Evidence: 2026-08-20/21 — reviewers caught a CSS-breaking defect, a fabricated quote, and 11 findings on the delivery prompt itself, all after author self-review.) -- **Async-first (MANDATORY)**: written, discoverable artifacts for every decision, finding, and handoff; sync is the exception, written back same-day. A task is not done until a cold session can read its state with zero questions. Canonical surfaces: `.agents/skills/async-first-communication/SKILL.md`; same SOP in `AGENTS.md`. **Cold-start surface: `STATUS.md` at repo root** — a session that changed what's in flight (started/finished/parked a workstream, shipped a PR, hit a blocker) without updating `STATUS.md` in the same commit/PR is not done. +- **Async-first (MANDATORY)**: written, discoverable artifacts for every decision, finding, and handoff; sync is the exception, written back same-day. A task is not done until a cold session can read its state with zero questions. Canonical surfaces: `.agents/skills/async-first-communication/SKILL.md`; same SOP in `AGENTS.md`. **Cold-start surface: `STATUS.md` at repo root** — a session that changed what's in flight (started/finished/parked a workstream, shipped a PR that changes a workstream's state, hit a blocker) without updating `STATUS.md` in the same commit/PR is not done. - **Company facts have a canon**: check `.okf/content/claims-canon.md` before publishing any number (founding 2008-09-01; tenure from `site.Params.foundingYear`; "4.8/5 on Clutch" linked, NO review count; founder 22+ vs company 18+). A number with no in-repo source is a defect. Correcting one means sweeping the instruction layer too — `PRODUCT.md`, `docs/business/`, outreach kits have re-introduced bad canon before (4 of 8 published figures were wrong on 2026-08-14). - **Text ratchets read RENDERED output, not source**: `marketing_copy_test` globs source and missed three rendered-only defects on 2026-08-14 (unglobbed partial, line-wrapped banned phrase, composed nested `
`). Queued: `docs/20-29-testing-qa/20.10` §3b P0-4. - **Zero**: generic AI language · unsupported claims · Hugo build breaks (`bin/hugo-build` validates) · ad hoc test scripts (header Test line commands only) · Python for analysis (use `rg`/`sed`/`awk`) · duplicate files (`*_new.*`, `*_backup.*`). diff --git a/STATUS.md b/STATUS.md index ca1205204..78fce6085 100644 --- a/STATUS.md +++ b/STATUS.md @@ -3,7 +3,8 @@ > Cold-start surface. One screen: goals, WIP, blockers. Links carry the detail — > this file never duplicates project state, it points at it. > **Update rule**: any session that changes what's in flight (starts/finishes/parks -> a workstream, ships a PR, hits a blocker) updates this file in the same commit/PR. +> a workstream, ships a PR that changes a workstream's state, hits a blocker) +> updates this file in the same commit/PR. > **When updating: verify against the artifact (the ledger, the file, the PR), never > a tracker line — trackers rot, and this file must not inherit their staleness.** diff --git a/bin/agent-bootstrap b/bin/agent-bootstrap index 5b7df0b54..0a489b14b 100755 --- a/bin/agent-bootstrap +++ b/bin/agent-bootstrap @@ -30,12 +30,18 @@ if [ -z "${CI:-}" ]; then GIT_COMMON="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)" MAIN_ROOT="${GIT_COMMON%/.git}" if [ -n "$MAIN_ROOT" ] && [ "$MAIN_ROOT" != "$PWD" ] && [ -d "$MAIN_ROOT/.swarm" ] && [ ! -e .swarm ]; then - ln -s "$MAIN_ROOT/.swarm" .swarm && log " .swarm -> shared main-checkout memory DB" \ + # -sfn also heals a DANGLING .swarm symlink (main checkout moved/renamed): + # -e follows links, so a dangling one enters this branch and gets replaced. + ln -sfn "$MAIN_ROOT/.swarm" .swarm && log " .swarm -> shared main-checkout memory DB" \ || log "WARN .swarm symlink failed - ruflo memory will die with this worktree" fi if [ ! -f .claude/helpers/hook-handler.cjs ]; then - npx @claude-flow/cli@latest init upgrade >/dev/null 2>&1 && log " helpers regenerated (init upgrade)" \ - || log "WARN ruflo init upgrade failed - learning hooks will silently no-op" + npx @claude-flow/cli@latest init upgrade >/dev/null 2>&1 + if [ -f .claude/helpers/hook-handler.cjs ]; then + log " helpers regenerated (init upgrade)" + else + log "WARN ruflo init upgrade did not produce hook-handler.cjs - learning hooks will silently no-op" + fi fi fi