Skip to content

Latest commit

 

History

History
871 lines (665 loc) · 27.5 KB

File metadata and controls

871 lines (665 loc) · 27.5 KB

ADR-001: Direct Script vs Agent for Auto-Reindex Operations

⚠️ SUPERSEDED: 2025-12-15

Status: Superseded by fast-fail optimization (see commits 577a861, adf2c60, e0fd660)

What Changed:

  • PostToolUse hook removed (auto-reindex on Write/Edit removed)
  • Functions deleted: run_incremental_reindex_sync(), reindex_after_write(), should_reindex_after_write()
  • Hook file deleted: .claude/hooks/post-tool-use-track-research.py
  • Auto-reindex feature replaced by fast-fail optimization in incremental-reindex script

Why Superseded:

  • PostToolUse auto-reindex had limited value (fast-fail makes manual reindex fast enough)
  • Removed complexity and maintenance burden
  • Fast-fail optimization (14.4x speedup) makes on-demand reindex acceptable

Historical Context: This ADR is preserved for reference. The decision and rationale remain valid for understanding the architecture that existed from 2025-12-03 to 2025-12-15.


Original Status: ✅ Accepted (Updated 2025-12-11 for first-prompt architecture) Original Date: 2025-12-03 (Last Updated: 2025-12-11) Decision Makers: Architecture Review Impact: Core auto-reindex implementation (first-prompt trigger, post-modification hooks)


Context

The semantic search skill requires automatic reindexing in two scenarios:

  1. First Prompt: On first user prompt after session start, trigger background reindex to check for file changes and update index
  2. Post-Modification: After user creates or edits files (Write/Edit tools), update index to reflect changes

These operations must run in hooks with minimal user impact and execute frequently (potentially 10+ times per day).

The Question

Should automatic reindexing operations:

  • Option A: Run bash scripts directly (subprocess.run)
  • Option B: Invoke semantic-search-indexer agent (Task tool)

Decision

We chose Option A: Direct Script Execution for automatic reindexing.

# Current implementation in .claude/utils/reindex_manager.py
def run_incremental_reindex_sync(project_path: Path) -> Optional[bool]:
    script = project_root / '.claude' / 'skills' / 'semantic-search' / 'scripts' / 'incremental-reindex'
    result = subprocess.run(
        [str(script), str(project_path)],
        timeout=50,
        capture_output=True,
        text=True
    )
    # Process result...

Manual operations continue to use semantic-search-indexer agent for rich, intelligent user interaction.


Rationale

1. Performance Requirements

Auto-reindex runs in hooks with strict timing constraints:

Requirement: Must complete within hook timeout (60 seconds) Typical execution: 2-5 seconds (incremental reindex) Buffer needed: 8-10 seconds for safety

Direct Script Performance:

Prerequisites check:     0.1s
Config load:            0.1s
Incremental reindex:    2.5s
Total:                  2.7s ✓ (22x safety margin)

Agent Performance:

Prerequisites check:     0.1s
Agent spawn (Task):     8.0s  ← Overhead
Agent LLM processing:   3.0s  ← Thinking
Incremental reindex:    2.5s
Agent cleanup:          1.0s
Total:                 14.6s ❌ (4.1x safety margin, risky)

Analysis: Agent approach is 5.4x slower (14.6s vs 2.7s), consuming most of the timeout budget. If agent encounters issues or decides to retry, could easily exceed 60s limit.


2. Cost Analysis

Auto-reindex runs frequently as a background operation.

Assumptions:

  • 1 developer working full-time
  • 20 file edits per day (conservative estimate)
  • Each edit potentially triggers reindex
  • Cooldown prevents most (90%), but ~2 reindexes/day execute
  • Sonnet API: ~$0.02 per agent invocation

Direct Script Cost:

Per reindex:     $0.00
Daily:           $0.00
Monthly:         $0.00
Annual:          $0.00

Agent Cost:

Per reindex:     $0.02
Daily:           2 reindexes × $0.02 = $0.04
Monthly:         $1.20
Annual:          $14.40 per developer

Team of 10 developers: $144/year

Analysis: Agent approach adds significant cost ($144/year per 10 developers) for background operations that provide no additional value. The script is deterministic and doesn't need intelligence.


3. Reliability & Predictability

Auto-reindex must be rock-solid as it runs automatically without user oversight.

Direct Script Characteristics:

  • Deterministic: Same input → same output, always
  • Predictable timing: 2-5s every time
  • Simple failure modes: Disk space, permissions, corruption
  • Clear error messages: Direct stderr output
  • No surprises: Does exactly what you expect

Agent Characteristics:

  • ⚠️ Non-deterministic: Agent may try different strategies
  • ⚠️ Variable timing: 10-22s depending on agent decisions
  • ⚠️ Complex failure modes: Script + agent + LLM + API
  • ⚠️ Masked errors: Agent might "fix" issue differently than expected
  • ⚠️ Potential surprises: Agent might do full reindex (3 min → timeout!)

Analysis: Background automation requires predictability. Agent intelligence becomes a liability when user isn't watching to correct unexpected behavior.


4. Offline Development

Developers need reindexing to work even without internet connectivity.

Scenario: Developer on airplane

Developer edits 50 files while offline
Auto-reindex attempts:

Option A (Direct Script):
  ✅ Script runs locally
  ✅ Index updates successfully
  ✅ Search works with latest changes

Option B (Agent):
  ❌ Agent spawn requires Anthropic API
  ❌ API call fails (no internet)
  ❌ Index never updates
  ❌ Search results stale for entire flight

Analysis: Direct script works offline; agent approach breaks offline development workflows.


5. Hook Timeout Safety

Hooks have hard 60-second timeout. Exceeding timeout breaks the hook.

Risk Analysis for Auto-Reindex:

Direct Script:

  • Worst case: Script times out at 50s
  • Hook cleanup: <1s
  • Total: 51s
  • Buffer: 9 seconds ✓ Safe

Agent:

  • Best case: 14.6s (smooth execution)
  • Worst case: Agent retries or decides full reindex → 60s+
  • Risk: Agent intelligence could trigger timeout
  • Impact: Hook fails, no reindex, user sees error

Real-World Scenario with Agent:

# Agent detects many changes
agent_thinks: "Many files changed, should I do full reindex?"
agent_decides: "Yes, full reindex is better"
full_reindex_starts: Takes 3 minutes
hook_timeout: 60 seconds
result: HOOK FAILS

Analysis: Agent's adaptive behavior is a risk for time-constrained operations. Fixed script behavior is safer.


6. User Experience

User Expectations for Auto-Reindex:

  • ✅ Invisible (runs in background)
  • ✅ Fast (don't notice delay)
  • ✅ Reliable (always works)
  • ✅ Predictable (same behavior every time)

Direct Script Delivers:

  • 2.7s execution (barely noticeable)
  • Runs silently in background
  • Same behavior every session
  • Clear errors if something wrong

Agent Would Provide:

  • 14.6s execution (noticeable delay on session start)
  • Potentially verbose output (agent "thinking")
  • Variable behavior (agent makes decisions)
  • Complex error messages (agent context)

Analysis: User experience favors direct script. Agent features (intelligence, rich output) are unnecessary and potentially annoying for background operations.


Consequences

Positive

Fast: 5x faster execution (2.7s vs 14.6s) ✅ Free: $0 API costs vs $144/year per 10 developers ✅ Reliable: Simple, deterministic behavior ✅ Offline-ready: Works without internet ✅ Safe: Won't exceed hook timeout ✅ Predictable: Consistent behavior every time ✅ Simple to debug: Direct error messages ✅ No API dependency: Works if Anthropic API down

Negative

No intelligence: Can't adapt to complex scenarios ❌ Fixed strategy: Always incremental, can't decide to do full ❌ No retry logic: Fails once, done (no second attempt) ❌ No diagnosis: Can't investigate why it failed ❌ No user guidance: Minimal error context

Mitigation

The negative consequences are acceptable for auto-reindex because:

  1. Fixed strategy is desired: Always incremental is the correct choice for background operations
  2. Retry logic unneeded: Could cause timeout; better to fail fast and let user fix manually
  3. Diagnosis unnecessary: Background operation, user not watching anyway
  4. Minimal errors acceptable: Critical errors rare; user can manually reindex if needed

For scenarios requiring intelligence, users invoke semantic-search-indexer agent manually.


Alternatives Considered

Alternative 1: Agent for All Operations ❌

Pros:

  • Consistent execution path (everything through agent)
  • Intelligence available for all scenarios
  • Rich error handling everywhere

Cons:

  • 5x slower for common operations
  • $144/year cost per 10 developers
  • Risk of timeout in hooks
  • Breaks offline development

Why Rejected: Cost, performance, and reliability issues outweigh benefits. Background operations don't need intelligence.


Alternative 2: Smart Script with Limited Intelligence ⚠️

Approach: Enhance bash script with decision logic:

if index_corrupted; then
    echo "⚠️ Index corrupted, manual full reindex recommended"
    exit 1
fi

if too_many_changes; then
    echo "ℹ️ Many changes detected, consider manual full reindex"
    # But still run auto-reindex (IndexFlatIP auto-fallback)
fi

Pros:

  • Still fast (bash logic is instant)
  • Still free (no API calls)
  • Some adaptive behavior

Cons:

  • Limited to bash scripting (no LLM intelligence)
  • Can't ask user questions
  • Can't learn from patterns

Why Partially Adopted: This is a good middle ground. Current implementation has basic error detection. Can enhance script intelligence without agent overhead. Potential future improvement.


Alternative 3: Hybrid with Fallback ⚠️

Approach: Try direct script, fall back to agent on error

result = run_script_direct()
if result.failed and time_allows:
    result = run_agent_troubleshoot()

Pros:

  • Fast path for normal cases
  • Intelligence for error cases
  • Best of both worlds?

Cons:

  • Complex error handling logic
  • Still risks timeout (agent fallback could exceed 60s)
  • Adds code complexity
  • Error in automatic context (user not watching)

Why Rejected: Complexity not justified. If script fails, better to fail fast with clear error. User can manually investigate with agent if needed.


Implementation Details

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                    SEMANTIC SEARCH SKILL                     │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  AUTOMATIC OPERATIONS (Background)                          │
│  ┌────────────────────────────────────────────────────┐    │
│  │ First-Prompt Hook (UserPromptSubmit)               │    │
│  │ └─> reindex_manager.spawn_background_reindex()    │    │
│  │     └─> subprocess.Popen (DETACHED)               │    │
│  │         └─> BACKGROUND SCRIPT ✓                    │    │
│  │             └─ scripts/incremental_reindex.py      │    │
│  │                 └─ Full reindex (3-10 min)         │    │
│  └────────────────────────────────────────────────────┘    │
│                                                              │
│  ┌────────────────────────────────────────────────────┐    │
│  │ Post-Write Hook (ToolUse)                          │    │
│  │ └─> reindex_manager.reindex_after_write()          │    │
│  │     └─> run_incremental_reindex_sync()            │    │
│  │         └─> DIRECT SCRIPT ✓ (synchronous)         │    │
│  │             └─ scripts/incremental-reindex         │    │
│  └────────────────────────────────────────────────────┘    │
│                                                              │
│  Characteristics:                                           │
│  - First-Prompt: <100ms hook, background completes async   │
│  - Post-Write: 2.7 seconds (synchronous, kill-and-restart) │
│  - Cost: $0.00                                             │
│  - Reliability: High (deterministic)                       │
│  - Works offline: Yes                                      │
│                                                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  MANUAL OPERATIONS (User-invoked)                          │
│  ┌────────────────────────────────────────────────────┐    │
│  │ User Command                                       │    │
│  │ └─> "index /path/to/project --full"               │    │
│  │     └─> AGENT: semantic-search-indexer ✓          │    │
│  │         └─ Task tool invocation                    │    │
│  │            └─ scripts/incremental-reindex          │    │
│  └────────────────────────────────────────────────────┘    │
│                                                              │
│  Characteristics:                                           │
│  - Execution: 10-20 seconds                                │
│  - Cost: $0.02 per invocation                             │
│  - Intelligence: High (adaptive, interactive)              │
│  - Rich output: Progress, stats, guidance                 │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Code Organization

Direct Script Path:

.claude/utils/reindex_manager.py
  ├─ spawn_background_reindex()         ← Background Popen (first-prompt)
  ├─ run_incremental_reindex_sync()     ← Direct subprocess.run() (post-write)
  ├─ reindex_after_write()              ← Called by post-write hook
  ├─ initialize_session_state()         ← Called by session-start hook
  └─ auto_reindex_on_session_start()    ← ⚠️ DEPRECATED (not used)

.claude/hooks/
  ├─ first-prompt-reindex.py            ← Spawns background reindex
  ├─ session-start.py                   ← Initializes session state only
  └─ post-tool-use-track-research.py    ← Invokes reindex_manager

.claude/skills/semantic-search/scripts/
  ├─ incremental_reindex.py             ← Python script (background + sync)
  └─ incremental-reindex                ← Bash wrapper (legacy, still works)

Agent Path:

.claude/agents/semantic-search-indexer.md  ← Agent definition
  └─ User invokes → Task tool → Agent spawns
      └─ Agent runs scripts/incremental-reindex
          └─ Agent interprets results
              └─ Returns rich, formatted output

Performance Benchmarks

Measured Execution Times

Test Environment:

  • MacBook Pro M1
  • Project: 342 files, 2,348 chunks
  • Changes: 7 files modified, 3 files added

Direct Script (Auto-Reindex):

Attempt 1:  2.74s
Attempt 2:  2.68s
Attempt 3:  2.71s
Average:    2.71s ✓
Variance:   ±0.03s (very consistent)

Agent Approach (Estimated):

Agent spawn:         8.0s   (Task tool overhead)
Agent processing:    3.0s   (LLM inference)
Script execution:    2.7s   (actual work)
Agent response:      1.0s   (formatting output)
Total:              14.7s ❌
Variance:           ±2.0s (variable based on agent)

Performance Ratio: 5.4x slower with agent


Cost Projections

Annual Cost Analysis

Single Developer:

Scenario Daily Reindexes Daily Cost Annual Cost
Direct Script 2-5 $0.00 $0.00
Agent 2-5 $0.04-$0.10 $14.60-$36.50

Team of 10 Developers:

Scenario Daily Reindexes Annual Cost
Direct Script 20-50 $0.00
Agent 20-50 $146-$365

Enterprise (100 Developers):

Scenario Annual Cost
Direct Script $0
Agent $1,460-$3,650

Analysis: For background operations running 10+ times/day per developer, API costs accumulate significantly. Direct script approach saves $1,460-$3,650 annually per 100 developers.


When to Use Each Approach

Use Direct Script ✓

Scenarios:

  • ✅ First-prompt reindex (automatic, background)
  • ✅ Post-file-write reindex (automatic)
  • ✅ Any hook-based operation (timeout constraints)
  • ✅ Background maintenance (user not watching)
  • ✅ High-frequency operations (>5 times/day)
  • ✅ Offline development workflows
  • ✅ Cost-sensitive deployments

Requirements:

  • Speed is critical (< 5s desired)
  • User not waiting/watching
  • No interaction needed
  • Predictable behavior required
  • Works offline needed
  • Zero API cost desired

Use Agent ✓

Scenarios:

  • ✅ User explicitly requests reindex
  • ✅ First-time project setup
  • ✅ Troubleshooting index issues
  • ✅ Manual full reindex operations
  • ✅ Index health diagnostics
  • ✅ Recovery from corruption

Requirements:

  • User is waiting (can take 10-20s)
  • Complex decisions needed
  • User interaction possible
  • Rich output valuable
  • Adaptive behavior helpful
  • Intelligence adds value

Examples

Example 1: First Prompt (Background Auto-Reindex)

User Action: Opens Claude Code, then sends first prompt

Implementation:

# .claude/hooks/first-prompt-reindex.py
def main():
    input_data = json.loads(sys.stdin.read())

    # Check if this is first prompt
    if not reindex_manager.should_show_first_prompt_status():
        sys.exit(0)

    # Spawn background reindex (non-blocking)
    reindex_manager.spawn_background_reindex(project_root)

    # Mark as processed
    reindex_manager.mark_first_prompt_shown()

    print("🔄 Checking for index updates in background...")

    # NOT using agent ❌
    # task_tool_spawn('semantic-search-indexer', ...)

Execution:

[Session starts in 0.5s]
User sends first prompt
🔄 Checking for index updates in background...
[Hook exits in <100ms, background process continues 3-10 min]

Why Background Script:

  • User wants to start working immediately (0.5s session start)
  • Hook overhead imperceptible (<100ms)
  • Full reindex completes in background (3-10 minutes)
  • Background operation, no interaction needed
  • Happens multiple times per day (cost would accumulate if using agent)

Example 2: User Manual Full Reindex

User Action: Types "reindex my project with full rebuild"

Implementation:

# User prompt triggers skill/agent
# semantic-search-indexer agent spawned
def execute_reindex(operation='index', full=True):
    # Agent provides rich, interactive experience
    result = run_bash_script('index', project_path, full=True)
    return format_rich_output(result)

Execution:

✅ Successfully indexed the project!

Indexing Summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Project: my-web-app
Files Processed: 342 files
Chunks Created: 2,348 semantic content chunks
Time taken: 156.3 seconds (~2.6 minutes)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

The semantic index is ready! You can now:
1. Search for code by describing what it does
2. Find similar implementations
...

Why Agent:

  • User explicitly requested operation (waiting for it)
  • Rich output valuable (progress, stats, guidance)
  • Can take 2-3 minutes (user understands)
  • One-time operation (cost acceptable)
  • Intelligence helpful (error diagnosis, recommendations)

Example 3: Post-Modification Auto-Reindex

User Action: Creates or edits files (Write/Edit tools)

Implementation:

# .claude/hooks/post-tool-use-track-research.py
if tool_name in ['Write', 'Edit']:
    file_path = tool_input.get('file_path')

    # Direct script approach ✓
    reindex_manager.reindex_after_write(file_path)

    # NOT using agent ❌

Execution:

[User saves file]
🔄 Updating semantic search index (file modified: main.py)...
[2.7s execution via direct script]
✅ Semantic search index updated
[User continues working]

Why Direct Script:

  • Happens every time user saves (high frequency)
  • User wants to continue working immediately
  • No interaction needed (background)
  • Cooldown prevents spam (but still frequent)
  • Cost would accumulate ($0.04 × 20 saves/day = $0.80/day)

Testing & Validation

Performance Validation

Test 1: First-Prompt Background Reindex

# Test hook spawn (should exit in <100ms)
time echo '{}' | .claude/hooks/first-prompt-reindex.py

# Monitor background process
ps aux | grep incremental_reindex.py

Result: Hook exits in <100ms ✓
Background process: Completes in 3-10 minutes ✓
Expected: Hook < 1 second, no session blocking ✓
Status: PASS

Test 2: Post-Write Reindex

# Simulate file write event
time .claude/hooks/post-tool-use-track-research.py < write_event.json

Result: 2.68 seconds ✓
Expected: < 5 seconds ✓
Status: PASS

Test 3: Hook Timeout Safety

# Simulate worst-case: reindex timeout
# Script has 50s timeout, hook has 60s timeout
# Buffer should be 10s

Measured:
- Script timeout: 50.0s ✓
- Hook cleanup: 0.5s
- Total: 50.5s
- Buffer: 9.5s ✓
Status: PASS (safe)

Cost Validation

Test 4: Daily Cost Tracking

# Simulate full work day
day_events = [
    'first_prompt',       # 1 background reindex
    'edit_file_1',        # Cooldown active, skip
    'edit_file_2',        # Cooldown active, skip
    # ... 15 more edits (cooldown)
    'edit_file_18',       # Cooldown expired, reindex
    'edit_file_19',       # Cooldown active, skip
    'edit_file_20',       # Cooldown active, skip
]

Results:
- Total edits: 20
- Reindexes executed: 2 (90% skipped by cooldown)
- Cost with direct script: $0.00- Cost with agent: $0.04
Status: PASS (cost savings confirmed)

Reliability Validation

Test 5: Offline Operation

# Disable network
sudo ifconfig en0 down

# Run reindex
.claude/utils/reindex_manager.py

Result: SUCCESS ✓
Index updated successfully
No network required
Status: PASS

Test 6: Deterministic Behavior

# Run reindex 10 times, verify identical behavior
for i in {1..10}; do
    ./run_reindex.sh
    echo "Run $i: $(check_result)"
done

Results:
- All runs: 2.7s ± 0.05s ✓
- All runs: Same output ✓
- All runs: Same index state ✓
Status: PASS (fully deterministic)

Future Considerations

Potential Enhancements

1. Smart Script Intelligence (Low Overhead)

Enhance bash script with lightweight checks:

# scripts/incremental-reindex (enhanced)
if [ -f "$STORAGE_DIR/.index_corrupted" ]; then
    echo "⚠️ Index corruption detected"
    echo "   Run manual full reindex: index $PROJECT_PATH --full"
    exit 1
fi

if [ "$CHANGED_FILES_COUNT" -gt 100 ]; then
    echo "ℹ️ Many files changed ($CHANGED_FILES_COUNT)"
    echo "   Consider manual full reindex if search results seem stale"
fi

Benefit: Add helpful guidance without agent overhead Cost: $0 (bash logic is instant) Risk: Low (deterministic checks)


2. Adaptive Cooldown

Dynamically adjust cooldown based on project activity:

def calculate_adaptive_cooldown():
    recent_activity = get_edit_frequency_last_hour()
    if recent_activity > 20:  # High activity
        return 600  # 10 minutes (reduce reindex frequency)
    else:
        return 300  # 5 minutes (normal)

Benefit: Reduce reindex spam during heavy editing Cost: $0 (simple calculation) Risk: Low (still uses direct script)


3. Agent-Assisted Recovery

For script failures, offer agent troubleshooting:

if script_failed and not in_hook:
    suggestion = "Reindex failed. Would you like me to investigate? [Y/n]"
    if user_confirms:
        spawn_agent('semantic-search-indexer', operation='diagnose')

Benefit: Intelligence only when needed Cost: $0.02 per troubleshooting session (rare) Risk: Low (user-initiated only)


Non-Goals

What we will NOT do:

Use agent for automatic operations

  • Reason: Performance, cost, reliability issues
  • Alternative: Keep direct script, enhance with smart checks

Add retry logic to auto-reindex

  • Reason: Could cause timeout
  • Alternative: Fail fast, user manually investigates

Make auto-reindex interactive

  • Reason: Background operation, user not watching
  • Alternative: Use agent for manual operations

References

Related Documentation

  • Implementation: .claude/utils/reindex_manager.py
  • Hooks: .claude/hooks/first-prompt-reindex.py (background), .claude/hooks/session-start.py (state init), post-tool-use-track-research.py (post-write)
  • Agent: .claude/agents/semantic-search-indexer.md
  • Scripts: .claude/skills/semantic-search/scripts/incremental_reindex.py, incremental-reindex (bash wrapper)
  • Testing: docs/guides/incremental-reindex-validation.md
  • Architecture: docs/implementation/comprehensive-architecture-audit-20251201.md

External References

  • Claude Code Bug #1481: Background process blocking (why synchronous execution)
  • FAISS Documentation: IndexIDMap2 for proper vector removal
  • Merkle Tree: Change detection in incremental reindex

Decision Log

Date Event Outcome
2025-11-28 Initial implementation Used direct script instinctively
2025-12-02 Architecture review Questioned script vs agent choice
2025-12-03 Deep analysis Confirmed direct script is optimal
2025-12-03 This ADR Documented decision rationale

Approval

Reviewed by: Architecture Team Approved by: Lead Architect Status: ✅ Accepted Next Review: 2026-06-01 (6 months) or on major architecture changes


Summary: Direct script execution for automatic reindex operations is the correct architectural choice based on performance (5x faster), cost ($0 vs $144/year per 10 developers), reliability (deterministic), and user experience (invisible background operation). Agent approach reserved for manual operations where intelligence and rich output add value.