SLOPSHOPPER

cfn-mailbox-listener

Wakes an idle session when agent-mailbox mail arrives, without typing into the terminal

toaststatuspromptprocesstimer
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · cfn-mailbox-listener
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts ⚠ cfn-mailbox-listener: mail: listener did not start
README

Claude Flow Novice v2.18.1 Documentation

Version: 2.18.1 (RuVector Integration) Last Updated: 2025-12-05

Package Metrics:

  • Namespace-isolated installation (~0.01% collision risk)
  • Semantic codebase search via RuVector
  • Multi-provider routing (Z.ai, Kimi, OpenRouter, Anthropic)

Overview

AI agent orchestration with semantic codebase search, Redis coordination, and multi-loop consensus validation (CFN Loop).

CFN Loop Execution Modes

Task Mode (Debugging - Full Visibility)

  • Spawn Method: Main Chat spawns Task() agents directly
  • Cost: $0.150/iteration (Anthropic provider)
  • Visibility: Complete agent output in Main Chat
  • Use Case: Debugging, learning, short tasks (<5 minutes)
  • Memory: ANTI-023 protection prevents memory leaks
  • Audit: Automatic audit trail storage in SQLite and Redis

CLI Mode (Production - Cost Optimized)

  • Spawn Method: Coordinator spawns CLI agents via npx claude-flow-novice
  • Cost: $0.054/iteration (64% savings vs Task mode)
  • Visibility: Background execution with progress tracking
  • Use Case: Production, long tasks, cost-sensitive workflows
  • Memory: Redis-based coordination with recovery capabilities
  • Custom Routing: Optional 5x cost reduction with Z.ai provider
  • Redis Configuration: Requires CFN_REDIS_HOST=localhost for non-Docker environments (see CLI Mode Redis Configuration)

Mode Selection Guide

  • Use Task Mode when: Debugging issues, learning CFN Loop, short tasks requiring full visibility
  • Use CLI Mode when: Production work, cost optimization, long-running tasks, background execution
  • Custom Routing: /custom-routing-activate for 95-98% total cost savings when using CLI mode

Slash Commands

  • /cfn-loop-task: Task mode execution (Main Chat → Task() agents)
  • /cfn-loop-cli: CLI mode execution (Main Chat → coordinator → CLI agents)
  • Mode Parameters: --mode=mvp|standard|enterprise with different confidence thresholds

Cost Comparison

  • Task Mode: $0.150/iteration (full visibility, debugging)
  • CLI Mode: $0.054/iteration (64% savings, production)
  • With Custom Routing: $0.004-0.010/iteration (95-98% total savings)

Quick Start

Task Mode (Debugging - Full Visibility)

# Install and initialize
npm install claude-flow-novice
npx cfn-init

# Execute CFN Loop - Main Chat spawns Task() agents directly
/cfn-loop-task "Implement JWT authentication" --mode=standard

# Custom routing available for 5x cost reduction
/custom-routing-activate

CLI Mode (Production - Cost Optimized)

# Install and initialize
npm install claude-flow-novice
npx cfn-init

# Configure Redis for non-Docker environments
export CFN_REDIS_HOST=localhost
export CFN_REDIS_PORT=6379

# Execute CFN Loop - Coordinator spawns CLI agents in background
/cfn-loop-cli "Implement JWT authentication" --mode=standard

# Initialize swarm with skills
npx claude-flow-novice swarm "Task Description" \
  --skills=redis-coordination,agent-spawning \
  --strategy development

Documentation Index

Core Concepts

User Guides

Technical Reference

Workflows

Maintenance

Legacy

Key Features (v2.18.1)

RuVector Codebase Search (NEW)

  • Semantic Search: Natural language queries against codebase
  • OpenAI Embeddings: text-embedding-3-small (1536 dimensions)
  • Manifest System: .cfn-manifest.json tracks CFN vs custom files
  • Safe Distribution: Custom files preserved during CFN updates
# Index codebase
./.claude/skills/cfn-ruvector-codebase-index/index.sh --full

# Search
./.claude/skills/cfn-ruvector-codebase-index/search.sh "authentication" --top 5

# Incremental reindex
/cfn-ruvector:codebase-reindex

Skills-First Architecture

  • Modular Skills: Independently maintainable, testable capabilities
  • Explicit Dependencies: Redis pub/sub coordination, no implicit coupling
  • Thin Orchestration: Main chat delegates to skills, minimal coordination logic
  • Namespace-Isolated Installation: ~0.01% collision risk
  • Preserves User Custom Agents/Skills/Hooks

Zero-Token Coordination

  • Redis BLPOP: Agents wait without API calls (0 tokens while idle)
  • Instant Wake-Up: <100ms latency for agent activation
  • Scalable: 23 agents in cfn-dev-team

CFN Loop (Consensus Framework)

  • Loop 3: Implementation agents (coders, researchers)
  • Loop 2: Validation agents (reviewers, testers)
  • Loop 1: Product owner (strategic oversight)
  • Adaptive Modes: MVP (fast), Standard (balanced), Enterprise (rigorous)

Cost Optimization

  • CLI Mode: 64% savings vs Task mode ($0.054 vs $0.150/iteration)
  • Custom Routing: Optional 5x reduction with Z.ai provider (95-98% total savings)
  • Mode-Aware Architecture: Task Mode agents use clean exit, CLI Mode uses Redis coordination
  • Memory Safety: ANTI-023 protection prevents memory leaks in Task Mode

Architecture Principles

  1. Skills-Based Coordination: All agent communication via explicit Redis dependencies
  2. Multi-Layer Enforcement: Coordination primitives at technical, skill, agent, and system layers
  3. Centralized Orchestration: Keep orchestration in dedicated skills, not distributed across components
  4. Mode-Aware Architecture: Task Mode (direct Task() spawning) vs CLI Mode (coordinator-driven)
  5. Post-Edit Validation: All Edit/Write operations trigger validation hooks
  6. Parallel Agent Spawning: All Task-based coordinators require parallel spawning (single message, multiple Task calls)

Mode-Agent Profile Specialization

  • Task Mode Agents: Clean exit protocol, direct Main Chat communication, audit trail storage
  • CLI Mode Agents: Redis coordination, completion signaling, background execution
  • Coordinators: Enhanced monitoring with recovery capabilities, progress tracking

Migration Notes

v1 → v2 Changes:

  • Deprecated: Implicit agent coordination, distributed orchestration logic
  • Added: Skills system, Redis coordination, zero-token waiting, orchestrate-cfn-loop.sh
  • Breaking: CFN Loop now requires orchestrator (no manual Task spawning)

v2.14 Changes:

  • Dual-Mode Architecture: Task Mode (Main Chat Task() spawning) vs CLI Mode (coordinator-driven)
  • Custom Routing: Z.ai integration for 5x cost reduction in CLI mode
  • Memory Safety: ANTI-023 protection prevents memory leaks in Task Mode
  • Enhanced Coordinators: Progress tracking, recovery capabilities, multi-layer enforcement

v2.16.0 Changes (Integration Standardization - PR #16):

  • Skill Lifecycle Management: Automated deployment, versioning, promotion workflows
  • Cross-Database Integration: Transaction coordinator for PostgreSQL/SQLite/Redis
  • File System Standardization: Unified backup, logging, state persistence patterns
  • Edge Case Feedback Loop: Auto-generates patches from test failures
  • Data Format Harmonization: JSON schema validation across 43+ skills
  • 27/30 Tasks Complete: 90% integration standardization implementation

See CHANGELOG.md and CFN Loop Task Mode Guide for migration details.

Testing

Mode Verification (All 3 Modes Working)

  • Task Mode: ✅ Verified (6 hello world files test)
  • CLI Mode: ✅ Verified (6 hello world files test with CFN_REDIS_HOST=localhost)
  • Docker Mode: ✅ Verified (Bug #6 validation test)

Test Details: See docs/ALL_3_MODES_VERIFIED_WORKING.md

Test Suites (All Passing)

  • TDD Compliance: 100% (24/24 tests)
  • CLI Mode Coordinator: 100% (23/23 tests)
  • CLI Mode Orchestrator: 91% (21/23 tests, 2 flexible)
  • CLI Mode Threshold: 100% (6/6 tests)
  • CLI Mode Redis: 100% (7/7 tests)

Running Tests

# TDD compliance tests
bash tests/tdd-compliance/test-*.sh

# CLI mode tests
bash tests/cli-mode/test-*.sh

# Bug #6 Redis validation
bash tests/docker/validation/validate-bug6-redis-vars.sh

RuVector - Semantic Codebase Search

Centralized Index: ~/.local/share/ruvector/index_v2.db

RuVector provides dual-mode code intelligence with a centralized index shared across all projects:

Dual Storage Architecture

SchemaPurposeQuery TypeUse Case
V1 (embeddings, files)Semantic similarityVector distance"Find code similar to X"
V2 (entities, refs, modules)Structured relationshipsSQL joins"Who calls this function?"

V1 - Semantic Search:

  • Stores text chunks with OpenAI embeddings (text-embedding-3-small, 1536 dims)
  • Queries: Fuzzy semantic similarity via cosine distance
  • Returns: Code that's semantically related regardless of exact syntax

V2 - Code Intelligence:

  • Stores AST entities (functions, classes, interfaces) with relationships
  • Queries: Precise SQL on structured code graph
  • Returns: Exact references, callers, type usage, module dependencies

Usage

# Build RuVector
cd .claude/skills/cfn-local-ruvector-accelerator
cargo build --release

# Initialize centralized index
./target/release/local-ruvector init

# Index current project (all file types)
./target/release/local-ruvector index --path . --types rs,ts,js,json,md,sh

# Semantic search across all indexed projects
./target/release/local-ruvector query --pattern "authentication middleware"

# SQL queries on code structure
sqlite3 ~/.local/share/ruvector/index_v2.db "
  SELECT * FROM refs WHERE target_name = 'MyFunction';
"

Supported Files:

  • AST extraction: Rust (.rs), TypeScript/JavaScript (.ts, .tsx, .js, .jsx)
  • Text indexing: JSON, YAML, Markdown (.md), Shell scripts (.sh)
  • Auto-excluded: .artifacts/ (logs/reports)

Benefits:

  • Cross-project semantic search
  • Shared learnings across codebases
  • Dual query modes (semantic + structural)
  • Full paths preserve project context

Support

License

See LICENSE file in repository root.

Source 1 files
hooks/register.ts 124 lines
1import type { EngineInterface, Register } from 'claude-code'
2
3// Agent mailbox listener. Runs `mailbox.sh listen` for the session's life; each line it prints is
4// one new message (metadata only, never the body). Mail that should wake the session starts a turn
5// of its own with $.prompt.submit once the session is idle: nothing is typed into the terminal, so
6// a half-typed draft in the prompt box is never touched, and it works in tmux, a plain terminal
7// tab, VS Code and on the server alike. The mail hook (cfn-mailbox-hook.sh) then shows the mail
8// on that prompt. Other mail only shows a toast and waits for the next prompt.
9// Needs mailbox.sh listen/unread (mailbox stage 6 listener work).
10
11// Must equal NUDGE_TEXT in mailbox.sh: the hook keeps the outside-mail guard up for this exact
12// prompt, since no person typed it. tests/test-cfn-mailbox-listener-mod.sh checks they match.
13export const NUDGE_TEXT = 'You have mail: run /mail read'
14const COOLDOWN_MS = 60_000
15const SCRIPT = '$HOME/.claude/skills/cfn-mailbox/mailbox.sh'
16
17export type MailLine =
18  | { event: 'ready'; session: string }
19  | { event: 'mail'; from: string; kind: string; wake: boolean; addr_kind?: string }
20  | { event: 'down'; reason?: string }
21  | { event: 'up' }
22
23// Module state: restarts with the module (a reload re-runs session.start, which restarts the child).
24const st = { isBusy: false, isPending: false, lastWake: 0, session: '' }
25
26export function parseLines(buffer: string): { lines: MailLine[]; rest: string } {
27  const parts = buffer.split('\n')
28  const rest = parts.pop() ?? ''
29  const lines: MailLine[] = []
30  for (const p of parts) {
31    const s = p.trim()
32    if (!s.startsWith('{')) continue
33    try {
34      const v = JSON.parse(s)
35      if (v && typeof v.event === 'string') lines.push(v as MailLine)
36    } catch {
37      // a partial or foreign line: ignore it
38    }
39  }
40  return { lines, rest }
41}
42
43function mailboxArgv(sub: string, sid: string, cwd: string): string[] {
44  return ['sh', '-c', `exec bash "${SCRIPT}" ${sub} --sid "$1" --cwd "$2"`, 'sh', sid, cwd]
45}
46
47async function wake($: EngineInterface): Promise<void> {
48  if (st.isBusy) {
49    st.isPending = true
50    return
51  }
52  const now = await $.clock.now()
53  const wait = st.lastWake + COOLDOWN_MS - now
54  if (wait > 0) {
55    st.isPending = true
56    $.clock.after(wait, () => void flush($))
57    return
58  }
59  st.isPending = false
60  st.lastWake = now
61  // The hook may already have shown it (a tool call ran in between): wake only if mail waits.
62  const sid = await $.session.id()
63  const cwd = await $.session.cwd()
64  const ran = await $.process.run(mailboxArgv('unread', sid, cwd), { timeoutMs: 15_000 })
65  if (ran.exitCode === 0 && Number.parseInt(ran.stdout.trim(), 10) === 0) return
66  void $.prompt.submit({ text: NUDGE_TEXT })
67}
68
69async function flush($: EngineInterface): Promise<void> {
70  if (st.isPending && !st.isBusy) await wake($)
71}
72
73async function handleLine($: EngineInterface, line: MailLine): Promise<void> {
74  if (line.event === 'ready') {
75    st.session = line.session
76    $.ui.status(undefined)
77  } else if (line.event === 'down') {
78    $.ui.status('mail: offline')
79  } else if (line.event === 'up') {
80    $.ui.status(undefined)
81  } else if (line.wake) {
82    await wake($)
83  } else {
84    $.ui.toast(`Mail from ${line.from} (${line.kind}); shown at your next prompt`)
85  }
86}
87
88async function listen($: EngineInterface, sid: string, cwd: string): Promise<void> {
89  const child = $.process.spawn({ argv: mailboxArgv('listen', sid, cwd) })
90  let buffer = ''
91  for await (const piece of child) {
92    if (piece.stream !== 'stdout') continue
93    const parsed = parseLines(buffer + piece.text)
94    buffer = parsed.rest
95    for (const line of parsed.lines) await handleLine($, line)
96  }
97  $.ui.status(st.session ? 'mail: listener stopped' : 'mail: listener did not start')
98}
99
100export const register: Register = on => {
101  on('session.start', async ($, e, next) => {
102    const started = await next(e)
103    if (!e.isInteractive) return started
104    const sid = await $.session.id()
105    void listen($, sid, e.cwd)
106    return started
107  })
108
109  // Bookkeeping only: a failure here must never block a prompt.
110  on('prompt.submit', ($, e, next) => {
111    st.isBusy = true
112    return next(e)
113  }).catch(($, e, next) => next(e))
114
115  on('turn.complete', async ($, e, next) => {
116    const done = await next(e)
117    if (e.agentId === undefined) {
118      st.isBusy = false
119      await flush($)
120    }
121    return done
122  })
123}
124