Comprehensive Lessons Learned - Terraphim AI Development

Compiled: December 20, 2025 Source: Multiple development sessions (2025-10-07 to 2025-09-17) Status: Production Ready Patterns

Executive Summary

This document consolidates all major lessons learned from Terraphim AI development, covering security implementation, multi-agent systems, workflow orchestration, deployment patterns, and technical excellence. These patterns represent proven solutions for production-ready AI systems.


Security Implementation Patterns

Date: 2025-10-07 - Critical Security Vulnerability Fixes

Pattern 1: Defense in Depth for Input Validation

Context: LLM prompt injection and network interface name injection vulnerabilities.

What We Learned:

  • Separate sanitization from validation: Sanitization (making input safe) and validation (rejecting bad input) serve different purposes
  • Multiple layers of defense: Pattern detection, length limits, character whitelisting, and control character removal all work together
  • Log but don't fail: Sanitization should log warnings but allow operation to continue with safe version

Implementation:

// GOOD: Separate concerns
pub fn sanitize_system_prompt(prompt: &str) -> SanitizedPrompt { ... }
pub fn validate_system_prompt(prompt: &str) -> Result<(), String> { ... }

// GOOD: Multiple checks
- Regex pattern matching for suspicious strings
- Length enforcement (10,000 char limit)
- Control character removal
- Special token stripping

Anti-pattern to Avoid:

// BAD: Single validation that's too strict
if prompt.contains("ignore") {
    return Err("Invalid prompt");  // Might reject legitimate prompts
}

Pattern 2: Eliminate Subprocess Execution Where Possible

Context: Command injection vulnerability via curl subprocess.

What We Learned:

  • Native libraries >> subprocesses: Using hyper HTTP client eliminates entire class of injection attacks
  • Path canonicalization is critical: Always canonicalize file paths before use
  • Type safety helps: Using proper types (PathBuf, Uri) prevents string manipulation errors

Implementation:

// GOOD: Native HTTP client
use hyper::Client;
use hyperlocal::{UnixClientExt, Uri};

let socket_path = self.socket_path.canonicalize()?;  // Validate first
let client = Client::unix();
let response = client.request(request).await?;

// BAD: Shell subprocess
Command::new("curl")
    .args(["--unix-socket", &socket_str])  // Injection vector!
    .output()

When to Apply: HTTP/API clients, file operations, process management, database access

Pattern 3: Replace Unsafe Code with Safe Abstractions

Context: 12 occurrences of unsafe { ptr::read() } for DeviceStorage copying.

What We Learned:

  • Safe alternatives usually exist: DeviceStorage already had arc_memory_only() method
  • Unsafe blocks are technical debt: Even correct unsafe code is harder to maintain
  • Clone is often acceptable: Performance cost of cloning is usually worth safety

Implementation:

// GOOD: Safe Arc creation
let persistence = DeviceStorage::arc_memory_only().await?;

// BAD: Unsafe pointer copy
use std::ptr;
let storage_ref = DeviceStorage::instance().await?;
let storage_copy = unsafe { ptr::read(storage_ref) };  // Use-after-free risk!

TruthForge Workflow Orchestration Patterns

Date: 2025-10-07 - PassOneOrchestrator Parallel Execution

Pattern 4: Enum Wrapper for Heterogeneous Async Results

Context: PassOneOrchestrator needs to run 4 different agents in parallel, each returning different result types.

Problem: tokio::task::JoinSet requires all spawned tasks to return the same type.

Solution: Create enum wrapper to unify result types:

enum PassOneAgentResult {
    OmissionCatalog(OmissionCatalog),
    BiasAnalysis(BiasAnalysis),
    NarrativeMapping(NarrativeMapping),
    TaxonomyLinking(TaxonomyLinking),
}

// Spawn with explicit type annotation
join_set.spawn(async move {
    let catalog = detector.detect_omissions_mock(&text, &context).await?;
    Ok::<PassOneAgentResult, TruthForgeError>(PassOneAgentResult::OmissionCatalog(catalog))
});

When to Apply: Parallel execution of agents/services returning different data structures

Pattern 5: Critical vs Non-Critical Agent Execution

Context: PassOneOrchestrator runs 4 agents - some are critical (OmissionDetector), others provide enhancement.

Solution: Differentiate critical from non-critical agents with different error strategies:

// Critical agent: propagate error
let omission_catalog = omission_catalog.ok_or_else(||
    TruthForgeError::WorkflowExecutionFailed {
        phase: "Pass1_OmissionDetection".to_string(),
        reason: "Omission detection failed".to_string(),
    }
)?;

// Non-critical agent: provide fallback
let bias_analysis = bias_analysis.unwrap_or_else(|| BiasAnalysis {
    biases: vec![],
    overall_bias_score: 0.0,
    confidence: 0.0,
});

Benefits: Workflow robustness: continues even if enhancement agents fail


LLM Integration Patterns

Date: 2025-10-08 - Pass Two Debate Generator Implementation

Pattern 6: Temperature Tuning for Adversarial Debates

Context: Pass2 debate requires different creativity levels for defensive vs exploitation arguments.

What We Learned:

  • Defensive arguments benefit from control: Temperature 0.4 produces strategic, measured damage control
  • Exploitation arguments need creativity: Temperature 0.5 enables more aggressive, innovative attacks
  • Small differences matter: 0.1 temperature difference is sufficient for distinct behavioral changes

Implementation:

// GOOD: Different temperatures for different roles
let defensive_request = LlmRequest::new(messages)
    .with_temperature(0.4);  // Controlled, strategic

let exploitation_request = LlmRequest::new(messages)
    .with_temperature(0.5);  // Creative, aggressive

Pattern 7: Flexible JSON Field Parsing for LLM Responses

Context: Different system prompts produce different JSON field names for similar concepts.

What We Learned:

  • LLMs may vary field names: Even with structured prompts, field naming isn't guaranteed
  • Multiple fallbacks essential: Try 3-4 field name variations before failing
  • Role-specific fields: Defensive uses "opening_acknowledgment", Exploitation uses "opening_exploitation"

Implementation:

// GOOD: Multiple fallback field names
let main_argument = llm_response["opening_exploitation"]
    .as_str()
    .or_else(|| llm_response["opening_acknowledgment"].as_str())
    .or_else(|| llm_response["main_argument"].as_str())
    .unwrap_or("No main argument provided")
    .to_string();

Pattern 8: Model Selection Strategy (Sonnet vs Haiku)

Context: Different agents have different complexity needs and cost sensitivities.

Solution: Task-based model selection:

| Task Type | Model | Reasoning | Cost | |-----------|-------|-----------|------| | Deep analysis (OmissionDetector) | Sonnet | Complex reasoning, multi-category detection | High | | Critical analysis (BiasDetector) | Sonnet | Subtle bias patterns, logical fallacy detection | High | | Framework mapping (NarrativeMapper) | Sonnet | SCCT framework expertise required | High | | Taxonomy mapping (TaxonomyLinker) | Haiku | Simple categorization, speed matters | 5-12x cheaper |

Cost Impact: Pass One with Haiku for taxonomy achieved 33% cost reduction with minimal quality impact


Multi-Agent System Architecture

Date: 2025-09-16 - Multi-Agent System Implementation Success

Pattern 9: Role-as-Agent Principle

Critical Insight: Each Role configuration in Terraphim is already an agent specification.

What We Learned:

  • Roles ARE Agents: Each role has haystacks (data sources), LLM config, knowledge graph, capabilities
  • Enhance Don't Rebuild: Don't build parallel agent system - enhance the role system
  • Multi-Agent = Multi-Role Coordination: Not new agent infrastructure

Implementation:

// Each Role becomes an autonomous agent
let agent = TerraphimAgent::from_role_config(role_config)?;
let result = agent.execute_command(command, context).await?;

Pattern 10: Mock-First Development Strategy

Pattern: Implement full workflow orchestration with mock agents before adding LLM integration.

Benefits:

  1. Fast iteration on workflow logic (no network calls)
  2. Predictable test behavior (no LLM variability)
  3. Clear separation of orchestration vs agent implementation
  4. Easy to identify workflow bugs vs agent bugs

Testing Strategy:

#[tokio::test]
async fn test_orchestrator_without_llm() {
    let orchestrator = PassOneOrchestrator::new();  // No LLM
    let result = orchestrator.execute(&narrative).await.unwrap();
    assert_eq!(result.agents_completed, 4);
}

Dynamic Model Selection

Date: 2025-09-17 - Dynamic Model Selection Complete

Pattern 11: Configuration Hierarchy Design Pattern

Problem Solved: User requirement "model names should not be hardcoded - in user facing flow user shall be able to select it via UI or configuration wizard."

Solution: 4-level configuration hierarchy system with complete dynamic model selection.

fn resolve_llm_config(&self, request_config: Option<&LlmConfig>, role_name: &str) -> LlmConfig {
    let mut resolved = LlmConfig::default();

    // 1. Hardcoded safety net
    resolved.llm_model = Some("llama3.2:3b".to_string());

    // 2. Global defaults from config
    // 3. Role-specific overrides
    // 4. Request-level overrides (highest priority)
}

Key Design Principles:

  • 4-Level Priority System: Request → Role → Global → Hardcoded fallback
  • Graceful Degradation: Always have working defaults while allowing complete override
  • Type Safety: Optional fields with proper validation and error handling

Web Development and Deployment Patterns

Date: 2025-10-08 - TruthForge Phase 5: UI Development & Deployment Patterns

Pattern 12: Vanilla JavaScript over Framework for Simple UIs

Context: Need to create UI that matches agent-workflows pattern, avoid build complexity.

What We Learned:

  • No build step = instant deployment: Static HTML/JS/CSS files work immediately
  • Framework assumptions are wrong: Always check project patterns before choosing technology
  • WebSocket client reusability: Shared libraries contain reusable components

Benefits:

  • Zero build time
  • No dependency management
  • Easier debugging (no transpilation)
  • Smaller bundle size
  • Works offline

Pattern 13: Caddy Reverse Proxy for Static Files + API

Context: Need to serve static UI files and proxy API/WebSocket requests to backend.

What We Learned:

  • Caddy handles multiple concerns: Static file serving, reverse proxy, HTTPS, auth in one config
  • Selective proxying: Use handle /api/* to proxy only specific paths
  • WebSocket requires special handling: @ws matcher for Connection upgrade headers

Implementation:

alpha.truthforge.terraphim.cloud {
    import tls_config              # Automatic HTTPS
    authorize with mypolicy        # Authentication
    root * /path/to/truthforge-ui
    file_server                    # Static files

    handle /api/* {
        reverse_proxy 127.0.0.1:8090  # API backend
    }

    @ws {
        path /ws
        header Connection *Upgrade*
        header Upgrade websocket
    }
    handle @ws {
        reverse_proxy 127.0.0.1:8090  # WebSocket backend
    }
}

Pattern 14: 5-Phase Deployment Script Pattern

Context: Complex deployment with multiple steps needs to be reproducible and debuggable.

Solution: Phase-based organization:

#!/bin/bash
set -e  # Exit on first error

phase1_copy_files() {
    log_info "Phase 1: Copy files"
    rsync -avz src/ server:/dest/
    log_info "Phase 1 complete"
}

phase2_configure() {
    log_info "Phase 2: Configure server"
    ssh server bash << 'ENDSSH'
        # All commands run on server
        sudo tee -a /etc/config << 'EOF'
        config content here
        EOF
        sudo systemctl reload service
ENDSSH
    log_info "Phase 2 complete"
}

main() {
    phase1_copy_files
    phase2_configure
    phase3_verify
}

Benefits:

  • Easy to debug (run individual phases)
  • Clear failure points (phase that failed is obvious)
  • Reproducible (same steps every time)

Code Quality and Testing Infrastructure

Date: 2025-09-15 - Pre-commit Hook Integration

Pattern 15: Pre-commit Hook Integration is Essential

What We Learned:

  • Pre-commit checks catch errors: Before they block team development
  • Investment in hook setup saves massive time: In CI/CD debugging
  • False positive handling: API key detection needs careful configuration
  • Format-on-commit ensures consistency: Across team code style

Pattern 16: Systematic Error Resolution Process

Group similar errors and fix in batches:

  • Group similar errors (E0063, E0782) and fix in batches
  • Use TodoWrite tool to track progress on multi-step fixes
  • Prioritize compilation errors over warnings for productivity
  • cargo fmt should be run after all fixes to ensure consistency

Agent System Configuration Integration

Date: 2025-09-17 - Agent System Configuration Integration Fix

Pattern 17: Configuration Propagation Pattern

Critical Discovery: 4 out of 5 workflow files calling MultiAgentWorkflowExecutor::new() instead of new_with_config()

Problem: Workflows had no access to role configurations, LLM settings, or base URLs

Solution: Ensure consistent configuration state propagation:

// WRONG: No configuration access
let executor = MultiAgentWorkflowExecutor::new().await;

// RIGHT: Pass configuration state
let executor = MultiAgentWorkflowExecutor::new_with_config(state.config_state.clone()).await;

Lesson: Configuration state must be explicitly passed through all layers of workflow execution.


Best Practices Summary

Architecture Principles

  1. Role-as-Agent Principle - Transform existing role systems into agents, don't rebuild
  2. Mock-First Development - Build with mocks, swap to real services for production
  3. Defense in Depth - Multiple security layers, not single controls
  4. Configuration Hierarchy - Always provide 4-level override system

Security Principles

  1. Input Validation Pipeline - Multiple validation layers with sanitization
  2. Native over Subprocess - Use native libraries instead of shell commands
  3. Safe over Unsafe - Always prefer safe Rust abstractions
  4. Log Security Events - Observability is critical for production

Performance Principles

  1. Model Selection Strategy - Use different models for different task types
  2. Temperature Tuning - Adjust creativity per task requirements
  3. Parallel Processing - Use JoinSet for heterogeneous async tasks
  4. Resource Pooling - Implement proper resource lifecycle management

Deployment Principles

  1. Vanilla JS for Simple UI - Avoid unnecessary framework complexity
  2. Caddy for Web Services - Single config for static files + API + HTTPS
  3. Phase-Based Deployment - Break complex deployments into testable phases
  4. Protocol Awareness - Detect file:// vs HTTP for local development

Development Workflow Principles

  1. Pre-commit Integration - Catch issues before they block team
  2. Systematic Error Resolution - Group and fix errors in batches
  3. Component-by-Component Development - Build modules independently, integrate incrementally
  4. Configuration Consistency - Ensure configuration flows through all layers

Future Application

These patterns provide a comprehensive foundation for:

  1. New AI Agent Systems - Multi-agent architectures with workflow orchestration
  2. Security-Critical Applications - Input validation and secure execution patterns
  3. Web-Based AI Interfaces - Deployment and frontend development strategies
  4. Production AI Systems - Configuration management and testing infrastructure

Each pattern has been validated in production environments and represents proven solutions to common challenges in AI system development.


Document Compiled: December 20, 2025 Status: Production Ready Patterns Application: All Future Terraphim AI Development