diff --git a/claude/aqe-reference.md b/claude/aqe-reference.md new file mode 100644 index 00000000..58199068 --- /dev/null +++ b/claude/aqe-reference.md @@ -0,0 +1,45 @@ + + + +## Agentic-QE — operating guidance + +> Applies when the standalone **agentic-qe** fleet is installed (`aqe` on PATH). This is the +> reusable subset of what `aqe init` would otherwise append to each project's `CLAUDE.md`; +> per-project specifics (enabled domains, worker config, the generation timestamp, local +> `.agentic-qe/` paths) are intentionally **not** here — `aqe init` writes those into the repo. + +### Critical policies (apply whenever agentic-qe is in use) +- **Integrity (absolute):** no shortcuts, fake data, or false success claims; verify before + claiming done; use real DB queries in integration tests; run actual tests, don't assume. +- **Test execution:** never run `npm test` without `--run` (watch-mode hang risk) — use + `npm test -- --run`, or `npm run test:unit` / `test:integration` when available. +- **Data protection:** never `rm -f` `.agentic-qe/` or `*.db` without confirmation; back up + before destructive database operations. +- **Git:** never auto-commit/push without an explicit user request. + +### Driving the AQE MCP +Tools are prefixed `mcp__agentic-qe__` (discover via `ToolSearch`). **`fleet_init` MUST be +called first**, e.g. `fleet_init({ topology:"hierarchical", maxAgents:15, memoryBackend:"hybrid" })`. + +| Tool | Purpose | +|------|---------| +| `fleet_init` | Initialize the QE fleet (call first) · `fleet_status` for health | +| `test_generate_enhanced` | AI-powered test generation (`framework`, `strategy`) | +| `test_execute_parallel` | Parallel execution with retry | +| `coverage_analyze_sublinear` | O(log n) coverage analysis (`paths`, `threshold`) | +| `quality_assess` | Quality-gate evaluation | +| `task_orchestrate` | Multi-agent QE tasks across domains (`parallel:true`) | +| `memory_store` / `memory_query` | Patterns with `namespace` + `persist:true` (learning) | +| `security_scan_comprehensive` | SAST/DAST scanning | + +### QE agents via the native Task tool +QE agents live under `.claude/agents/v3/` once `aqe init` has run in the repo: +```javascript +Task({ prompt: "Generate tests", subagent_type: "qe-test-architect", run_in_background: true }) +Task({ prompt: "Find coverage gaps", subagent_type: "qe-coverage-specialist", run_in_background: true }) +Task({ prompt: "Security audit", subagent_type: "qe-security-scanner", run_in_background: true }) +``` + + diff --git a/claude/ruflo-reference.md b/claude/ruflo-reference.md index a21ac6c0..71320fae 100644 --- a/claude/ruflo-reference.md +++ b/claude/ruflo-reference.md @@ -314,6 +314,12 @@ ruflo-setup-aqe --force # force reinitialize (aqe init --auto --upgrade Opt-in only — `ruflo-setup-project` does NOT run it. +When agentic-qe **is** installed, the kit also merges a conditional **`ruflo-aqe-reference`** +block (AQE operating guidance — policies + MCP tool usage + QE-agent patterns) into this same +`~/.claude/CLAUDE.md`, just below this `ruflo-reference` block. It is added when `aqe` is on +PATH and **stripped automatically when agentic-qe is absent**. Source: `claude/aqe-reference.md`; +applied by `install.sh` and re-asserted by `ruflo-reference-refresh` / `ruflo-resync`. + ### Security surface (verify + activate) ```bash diff --git a/install.sh b/install.sh index c8fe4a97..ada4fa99 100755 --- a/install.sh +++ b/install.sh @@ -187,11 +187,12 @@ case ":$PATH:" in esac echo "" -# CLAUDE.md reference template +# CLAUDE.md reference template (+ the conditional agentic-qe sub-block template) echo "## CLAUDE.md reference template -> $CFG_DIR/claude-md-template.md" run "mkdir -p '$CFG_DIR'" run "cp '$HERE/claude/ruflo-reference.md' '$CFG_DIR/claude-md-template.md'" -ok "template installed" +run "cp '$HERE/claude/aqe-reference.md' '$CFG_DIR/aqe-md-template.md'" +ok "templates installed (ruflo-reference + conditional aqe-reference)" echo "" # Shared helper lib — deployed to a stable absolute path so the standalone bin @@ -224,6 +225,26 @@ else fi echo "" +# Conditional agentic-qe operating block: present in ~/.claude/CLAUDE.md ONLY when agentic-qe +# is installed; stripped otherwise (self-healing on uninstall). Idempotent. +echo "## ruflo-aqe-reference block (conditional on agentic-qe) -> $CLAUDE_MD" +AQE_BEGIN=''; AQE_END='' +if [ "$DRY" -eq 1 ]; then + if have aqe; then printf '%s[dry-run]%s upsert ruflo-aqe-reference block (aqe present)\n' "$C_DIM" "$C_RESET" + else printf '%s[dry-run]%s strip ruflo-aqe-reference block (aqe absent)\n' "$C_DIM" "$C_RESET"; fi +elif have aqe; then + _ruflo_block_upsert "$CLAUDE_MD" "$AQE_BEGIN" "$AQE_END" "$HERE/claude/aqe-reference.md" \ + && ok "agentic-qe present — merged ruflo-aqe-reference block" \ + || warn "could not merge ruflo-aqe-reference block (aqe-reference.md unreadable)" +else + if [ -f "$CLAUDE_MD" ] && grep -qF "$AQE_BEGIN" "$CLAUDE_MD"; then + _ruflo_block_strip "$CLAUDE_MD" "$AQE_BEGIN" "$AQE_END"; ok "agentic-qe absent — stripped stale ruflo-aqe-reference block" + else + dim "agentic-qe absent — no ruflo-aqe-reference block to manage" + fi +fi +echo "" + # Shell rc source line if [ "$EDIT_RC" -eq 1 ]; then echo "## shell functions" diff --git a/shell/ruflo-functions.sh b/shell/ruflo-functions.sh index e16ce0e0..0d3f542b 100644 --- a/shell/ruflo-functions.sh +++ b/shell/ruflo-functions.sh @@ -651,6 +651,25 @@ ruflo-neural-train() { # # ruflo-resync # re-apply learning + statusline (recommended after upgrade) # ruflo-resync --aqe # also refresh agentic-qe skills in this repo +# Sync the conditional agentic-qe sub-block in ~/.claude/CLAUDE.md: present iff `aqe` is +# installed (upsert from the staged template), stripped otherwise (self-healing on uninstall). +# Quiet unless the block's presence actually changes. Needs ruflo-lib.sh (_ruflo_block_*). +_ruflo_sync_aqe_block() { + local ref="$HOME/.claude/CLAUDE.md" + local tmpl="$HOME/.config/ruflo/aqe-md-template.md" + local b='' e='' + command -v _ruflo_block_upsert >/dev/null 2>&1 || return 0 + [ -f "$ref" ] || return 0 + if command -v aqe >/dev/null 2>&1; then + [ -f "$tmpl" ] || return 0 + grep -qF "$b" "$ref" || echo " + agentic-qe present → adding ruflo-aqe-reference block to $ref" + _ruflo_block_upsert "$ref" "$b" "$e" "$tmpl" + elif grep -qF "$b" "$ref" 2>/dev/null; then + echo " - agentic-qe absent → stripping stale ruflo-aqe-reference block from $ref" + _ruflo_block_strip "$ref" "$b" "$e" + fi +} + ruflo-resync() { local do_aqe=0 [ "${1:-}" = "--aqe" ] && do_aqe=1 @@ -668,6 +687,9 @@ ruflo-resync() { echo ""; echo "## 3/4 statusline (version + activation footer) for this project" ruflo-fix-statusline-version + echo ""; echo "## machine-wide ~/.claude/CLAUDE.md: conditional agentic-qe reference block" + _ruflo_sync_aqe_block && echo "✓ ruflo-aqe-reference block in sync with agentic-qe install state" + if [ "$do_aqe" -eq 1 ]; then echo ""; echo "## 4/4 refresh agentic-qe skills (--aqe)" if [ -f .agentic-qe/memory.db ]; then @@ -697,22 +719,31 @@ ruflo-reference-refresh() { case "$1" in --diff) mode="diff" ;; --regenerate) mode="regenerate" ;; + --sync-aqe) mode="sync-aqe" ;; -y|--yes) yes=1 ;; - -h|--help) echo "Usage: ruflo-reference-refresh [--diff|--regenerate [-y]]"; return 0 ;; + -h|--help) echo "Usage: ruflo-reference-refresh [--diff|--regenerate [-y]|--sync-aqe]"; return 0 ;; *) echo "Unknown flag: $1"; return 2 ;; esac shift done + # --sync-aqe only touches the conditional agentic-qe block; no ruflo template needed. + if [ "$mode" = "sync-aqe" ]; then _ruflo_sync_aqe_block; return 0; fi if [ ! -f "$template" ]; then echo "No template at $template (run install.sh, or extract from $ref)." return 1 fi + local aqe_begin='' case "$mode" in status) echo "ruflo: $(ruflo --version 2>/dev/null || echo 'not installed')" echo "installed sentinel: $(grep -E 'ruflo-version' "$ref" 2>/dev/null || echo 'none')" echo "template sentinel: $(grep -E 'ruflo-version' "$template" 2>/dev/null || echo 'none')" - echo "Use --diff to compare, --regenerate to rebuild." + if command -v aqe >/dev/null 2>&1; then + grep -qF "$aqe_begin" "$ref" 2>/dev/null && echo "agentic-qe: installed — aqe block present" || echo "agentic-qe: installed — aqe block MISSING (run --sync-aqe)" + else + grep -qF "$aqe_begin" "$ref" 2>/dev/null && echo "agentic-qe: absent — aqe block STALE (run --sync-aqe to strip)" || echo "agentic-qe: absent — aqe block correctly absent" + fi + echo "Use --diff to compare, --regenerate to rebuild, --sync-aqe to fix the agentic-qe block." ;; diff) local blk; blk=$(mktemp) @@ -721,13 +752,13 @@ ruflo-reference-refresh() { rm -f "$blk" ;; regenerate) - if [ ! -f "$ref" ]; then cp "$template" "$ref"; echo "✓ Installed reference at $ref"; return 0; fi + if [ ! -f "$ref" ]; then cp "$template" "$ref"; echo "✓ Installed reference at $ref"; _ruflo_sync_aqe_block; return 0; fi local pre post new pre=$(mktemp); post=$(mktemp); new=$(mktemp) awk '//{exit} {print}' "$ref" > "$pre" awk 'f; //{f=1}' "$ref" > "$post" cat "$pre" "$template" "$post" > "$new" - if diff -q "$ref" "$new" >/dev/null 2>&1; then echo "✓ Already up-to-date."; rm -f "$pre" "$post" "$new"; return 0; fi + if diff -q "$ref" "$new" >/dev/null 2>&1; then echo "✓ Already up-to-date."; rm -f "$pre" "$post" "$new"; _ruflo_sync_aqe_block; return 0; fi diff -u "$ref" "$new" | head -80 if [ "$yes" -eq 0 ]; then printf "Apply this regeneration? [y/N] "; local r; read -r r @@ -736,6 +767,7 @@ ruflo-reference-refresh() { cp "$ref" "$ref.bak.$(date +%Y%m%d-%H%M%S)" mv "$new" "$ref"; rm -f "$pre" "$post" echo "✓ Regenerated $ref (backup saved)" + _ruflo_sync_aqe_block ;; esac } diff --git a/shell/ruflo-lib.sh b/shell/ruflo-lib.sh index 53b56f26..e81f462f 100644 --- a/shell/ruflo-lib.sh +++ b/shell/ruflo-lib.sh @@ -99,4 +99,44 @@ _ruflo_bsq3_install() { ( cd "$1" && npm install "better-sqlite3@${2:-^12}" --no-save --no-audit --no-fund >/dev/null 2>&1 ) } +# --- sentinel-delimited block management (CLAUDE.md sub-blocks) ------------- +# Manage a ``…`` block in a file. Used for the +# conditional ruflo-aqe-reference block in ~/.claude/CLAUDE.md (present only when +# agentic-qe is installed). Idempotent; preserves everything outside the markers. +# Markers are matched as fixed substrings (awk index()). + +# _ruflo_block_upsert FILE BEGIN END SRC — replace the BEGIN..END block in FILE with +# the contents of SRC (which must itself contain the markers); append if the block is +# absent; create FILE from SRC if FILE is missing. Returns 1 if SRC is unreadable. +_ruflo_block_upsert() { + local file="$1" begin="$2" end="$3" src="$4" + [ -f "$src" ] || return 1 + mkdir -p "$(dirname "$file")" 2>/dev/null + if [ ! -f "$file" ]; then cat "$src" > "$file"; return 0; fi + if grep -qF "$begin" "$file"; then + local pre post new; pre=$(mktemp); post=$(mktemp); new=$(mktemp) + awk -v b="$begin" 'index($0,b){exit} {print}' "$file" > "$pre" + awk -v e="$end" 'f; index($0,e){f=1}' "$file" > "$post" + cat "$pre" "$src" "$post" > "$new" + cat "$new" > "$file"; rm -f "$pre" "$post" "$new" + else + { printf '\n'; cat "$src"; } >> "$file" + fi +} + +# _ruflo_block_strip FILE BEGIN END — remove the BEGIN..END block (inclusive) from +# FILE. No-op if FILE or the block is absent. +_ruflo_block_strip() { + local file="$1" begin="$2" end="$3" + [ -f "$file" ] || return 0 + grep -qF "$begin" "$file" || return 0 + local new; new=$(mktemp) + awk -v b="$begin" -v e="$end" ' + index($0,b){skip=1} + !skip{print} + index($0,e){skip=0} + ' "$file" > "$new" + cat "$new" > "$file"; rm -f "$new" +} + _RUFLO_LIB=1 # sentinel: consumers check this to confirm the lib loaded diff --git a/uninstall.sh b/uninstall.sh index 7402ed7e..d60f1063 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -4,9 +4,9 @@ # # By default removes ONLY the kit's own footprint: # - every helper this repo ships in bin/ from ~/.local/bin/ (derived from bin/) -# - ~/.config/ruflo/claude-md-template.md -# - the BEGIN/END ruflo-reference block from ~/.claude/CLAUDE.md (content -# outside the sentinels is preserved) +# - ~/.config/ruflo/{claude-md-template,aqe-md-template}.md +# - the BEGIN/END ruflo-reference AND ruflo-aqe-reference blocks from +# ~/.claude/CLAUDE.md (content outside the sentinels is preserved) # - the source line from ~/.zshrc / ~/.bashrc # # Leaves your ruflo install, memory DBs, and project files untouched. Per-project @@ -86,23 +86,24 @@ for src in "$HERE"/bin/*; do [ -f "$f" ] && { run "rm -f '$f'"; ok "removed $f"; } done -# 2. template +# 2. templates (ruflo-reference + conditional agentic-qe block) [ -f "$HOME/.config/ruflo/claude-md-template.md" ] && { run "rm -f '$HOME/.config/ruflo/claude-md-template.md'"; ok "removed template"; } +[ -f "$HOME/.config/ruflo/aqe-md-template.md" ] && { run "rm -f '$HOME/.config/ruflo/aqe-md-template.md'"; ok "removed agentic-qe template"; } # 2b. shared helper lib (already sourced at the top, so removing it here is safe) [ -f "$HOME/.config/ruflo/ruflo-lib.sh" ] && { run "rm -f '$HOME/.config/ruflo/ruflo-lib.sh'"; ok "removed helper lib"; } -# 3. CLAUDE.md managed block +# 3. CLAUDE.md managed blocks (ruflo-reference + the conditional ruflo-aqe-reference) CLAUDE_MD="$HOME/.claude/CLAUDE.md" -if [ -f "$CLAUDE_MD" ] && grep -q '' "$CLAUDE_MD"; then +if [ -f "$CLAUDE_MD" ] && grep -qE '' "$CLAUDE_MD"; then if [ "$DRY" -eq 1 ]; then - printf '%s[dry-run]%s strip ruflo-reference block from %s\n' "$C_DIM" "$C_RESET" "$CLAUDE_MD" + printf '%s[dry-run]%s strip ruflo-reference + ruflo-aqe-reference blocks from %s\n' "$C_DIM" "$C_RESET" "$CLAUDE_MD" else cp "$CLAUDE_MD" "$CLAUDE_MD.bak.$(date +%Y%m%d-%H%M%S)" new=$(mktemp) - awk '//{skip=1} //{skip=0; next} !skip' "$CLAUDE_MD" > "$new" + awk '//{skip=1} //{skip=1} //{skip=0; next} //{skip=0; next} !skip' "$CLAUDE_MD" > "$new" mv "$new" "$CLAUDE_MD" - ok "stripped ruflo-reference block (backup saved; rest of file preserved)" + ok "stripped ruflo-reference + ruflo-aqe-reference blocks (backup saved; rest of file preserved)" fi fi