// === m1nd-mcp/src/personality.rs ===
//
// v0.4.0: _m1nd metadata builder, suggest_next mapping, personality templates,
// ANSI formatting, visual identity glyphs.

use serde_json::{json, Value};

// ---------------------------------------------------------------------------
// Visual Identity — glyphs and ANSI colors
// ---------------------------------------------------------------------------

/// m1nd logo glyphs with their semantic meanings.
pub const GLYPH_SIGNAL: &str = "\u{234C}"; // ⍌ — spreading activation signal
pub const GLYPH_PATH: &str = "\u{2350}"; // ⍐ — paths through the graph
pub const GLYPH_STRUCTURE: &str = "\u{2342}"; // ⍂ — structural analysis
pub const GLYPH_DIMENSION: &str = "\u{1D53B}"; // 𝔻 — 4D dimensional scoring
pub const GLYPH_CONNECTION: &str = "\u{27C1}"; // ⟁ — graph connections, edges

/// ANSI escape codes for m1nd's color palette.
pub const ANSI_CYAN: &str = "\x1b[38;2;0;212;255m";
pub const ANSI_GOLD: &str = "\x1b[38;2;255;215;0m";
pub const ANSI_MAGENTA: &str = "\x1b[38;2;255;0;255m";
pub const ANSI_BLUE: &str = "\x1b[38;2;65;105;225m";
pub const ANSI_GREEN: &str = "\x1b[38;2;0;255;136m";
pub const ANSI_RED: &str = "\x1b[38;2;255;71;87m";
pub const ANSI_DIM: &str = "\x1b[38;2;90;101;119m";
pub const ANSI_RESET: &str = "\x1b[0m";
pub const ANSI_BOLD: &str = "\x1b[1m";

// ---------------------------------------------------------------------------
// Gradient border builder
// ---------------------------------------------------------------------------

/// Build a gradient top border (cyan -> magenta -> blue -> green).
pub fn gradient_top_border(width: usize) -> String {
    let colors = [ANSI_CYAN, ANSI_MAGENTA, ANSI_BLUE, ANSI_GREEN];
    let segment = width / colors.len();
    let mut border = String::new();
    for (i, color) in colors.iter().enumerate() {
        let len = if i == colors.len() - 1 {
            width - segment * i
        } else {
            segment
        };
        border.push_str(color);
        for _ in 0..len {
            border.push('\u{2550}'); // ═
        }
    }
    border.push_str(ANSI_RESET);
    border
}

/// Build a gradient bottom border.
pub fn gradient_bottom_border(width: usize) -> String {
    let colors = [ANSI_GREEN, ANSI_BLUE, ANSI_MAGENTA, ANSI_CYAN];
    let segment = width / colors.len();
    let mut border = String::new();
    for (i, color) in colors.iter().enumerate() {
        let len = if i == colors.len() - 1 {
            width - segment * i
        } else {
            segment
        };
        border.push_str(color);
        for _ in 0..len {
            border.push('\u{2550}'); // ═
        }
    }
    border.push_str(ANSI_RESET);
    border
}

// ---------------------------------------------------------------------------
// suggest_next mapping (D5 from synthesis)
// ---------------------------------------------------------------------------

/// Returns suggested next tool calls based on the tool just executed.
pub fn suggest_next(tool_name: &str) -> Vec<String> {
    match tool_name {
        "activate" | "seek" | "search" => vec![
            "impact(top_result) to check blast radius".into(),
            "learn(feedback) to strengthen edges".into(),
            "hypothesize(claim) to test a theory".into(),
        ],
        "impact" => vec![
            "view(next_suggested_target) to inspect the strongest downstream seam".into(),
            "validate_plan(files) before touching a high-blast seam".into(),
            "counterfactual(node) to simulate removal".into(),
        ],
        "hypothesize" => vec![
            "view(next_suggested_target) to inspect the strongest proof target".into(),
            "timeline(next_suggested_target) when historical proof is missing".into(),
            "validate_plan(files) when the claim is strong enough to shape an edit".into(),
        ],
        "surgical_context" | "surgical_context_v2" => vec![
            "validate_plan(files) to ground the coupled edit surface".into(),
            "edit_preview(file, content) to preview changes before writing".into(),
            "apply_batch(edits) for multiple files after proof".into(),
        ],
        "edit_preview" => {
            vec!["edit_commit(preview_id, confirm=true) to apply the previewed change".into()]
        }
        "edit_commit" => vec![
            "predict(changed_node) for ripple effects".into(),
            "learn(feedback) to update graph".into(),
        ],
        "apply" | "apply_batch" => vec![
            "predict(changed_node) for ripple effects".into(),
            "learn(feedback) to update graph".into(),
        ],
        "batch_view" => vec![
            "coverage_session to see what remains unread".into(),
            "search(query) when the next move depends on exact text inside the returned files"
                .into(),
        ],
        "scan_all" => vec![
            "batch_view(file_paths) on the strongest findings".into(),
            "validate_plan when grouped findings imply a connected edit surface".into(),
        ],
        "cross_verify" => vec![
            "audit(path) when you need recommendations and topology around the drift".into(),
            "batch_view(file_paths) on the mismatched files".into(),
        ],
        "coverage_session" => vec![
            "batch_view(unvisited_files) for compact catch-up".into(),
            "seek(query) or search(query) to close the highest-value unread gap".into(),
        ],
        "external_references" => vec![
            "federate_auto when you want m1nd to discover sibling repos from explicit paths or manifest/workspace hints and suggest namespaces for you".into(),
            "audit(path, external_refs=true) to fold the signal into a larger report".into(),
        ],
        "federate_auto" => vec![
            "federate when you already know the exact repo list and want direct execution".into(),
            "audit(path, external_refs=true) when you want discovery wrapped in a broader structural report".into(),
        ],
        "audit" => vec![
            "batch_view(files) on the strongest evidence files".into(),
            "cross_verify(scope) for a narrower graph-vs-disk pass after the top-level report"
                .into(),
        ],
        "ghost_edges" => vec![
            "timeline(file) to compare historical coupling evidence".into(),
            "impact(node) when a ghost edge suggests a hidden blast seam".into(),
        ],
        "taint_trace" => vec![
            "validate_plan before touching a suspected trust boundary".into(),
            "flow_simulate when the taint path implies runtime coordination risk".into(),
        ],
        "twins" => vec![
            "refactor_plan to turn duplication into extraction candidates".into(),
            "impact(node) to compare blast radius before consolidating twins".into(),
        ],
        "refactor_plan" => vec![
            "validate_plan to ground the proposed extraction before editing".into(),
            "apply_batch after the split surface is fully proved".into(),
        ],
        "runtime_overlay" => vec![
            "trace when runtime heat and failure text need to converge on one file".into(),
            "panoramic to compare runtime heat with structural risk concentration".into(),
        ],
        "missing" => vec![
            "activate(topic) to explore the gap".into(),
            "hypothesize(claim) about the missing piece".into(),
        ],
        "predict" => vec![
            "impact(predicted_node) to verify".into(),
            "learn(feedback) to calibrate".into(),
        ],
        "panoramic" => vec![
            "impact(critical_module) for deep dive".into(),
            "antibody_scan to check for patterns".into(),
        ],
        "ingest" => vec![
            "activate(topic) to explore ingested code".into(),
            "layers to detect architecture".into(),
            "panoramic for full health scan".into(),
        ],
        "layers" => vec![
            "layer_inspect(layer_name) for details".into(),
            "panoramic for risk analysis".into(),
        ],
        "trust" => vec![
            "tremor(node) to check volatility".into(),
            "panoramic for combined view".into(),
        ],
        _ => vec![
            "activate(query) for exploration".into(),
            "help for tool reference".into(),
        ],
    }
}

// ---------------------------------------------------------------------------
// Personality templates (D2 from synthesis)
// ---------------------------------------------------------------------------

/// Generate a personality one-liner based on tool and result.
pub fn personality_line(tool_name: &str, result: &Value) -> String {
    match tool_name {
        "activate" => {
            let count = result
                .get("results")
                .and_then(|v| v.as_array())
                .map_or(0, |a| a.len());
            let query = result.get("query").and_then(|v| v.as_str()).unwrap_or("?");
            if count == 0 {
                format!("no results for '{}'. try ingest first, or rephrase.", query)
            } else {
                let top = result
                    .get("results")
                    .and_then(|v| v.as_array())
                    .and_then(|a| a.first())
                    .and_then(|v| v.get("label"))
                    .and_then(|v| v.as_str())
                    .unwrap_or("?");
                format!("found {} results for '{}'. top hit: {}.", count, query, top)
            }
        }
        "impact" => {
            let total = result
                .get("blast_radius")
                .and_then(|v| v.as_array())
                .map_or(0, |a| a.len());
            let proof_state = result
                .get("proof_state")
                .and_then(|v| v.as_str())
                .unwrap_or("triaging");
            format!(
                "{} nodes in blast radius. proof_state={}. follow the downstream seam next.",
                total, proof_state
            )
        }
        "search" => {
            let count = result
                .get("total_matches")
                .and_then(|v| v.as_u64())
                .unwrap_or(0);
            let query = result.get("query").and_then(|v| v.as_str()).unwrap_or("?");
            let mode = result
                .get("mode")
                .and_then(|v| v.as_str())
                .unwrap_or("literal");
            format!("{} matches for '{}' ({})", count, query, mode)
        }
        "panoramic" => {
            let total = result
                .get("total_modules")
                .and_then(|v| v.as_u64())
                .unwrap_or(0);
            let alerts = result
                .get("critical_alerts")
                .and_then(|v| v.as_array())
                .map_or(0, |a| a.len());
            format!("{} modules scanned. {} critical alerts.", total, alerts)
        }
        "hypothesize" => {
            let verdict = result
                .get("verdict")
                .and_then(|v| v.as_str())
                .unwrap_or("unknown");
            let confidence = result
                .get("confidence")
                .and_then(|v| v.as_f64())
                .unwrap_or(0.0);
            format!(
                "verdict: {} ({:.0}% confidence).",
                verdict,
                confidence * 100.0
            )
        }
        "ingest" => {
            let nodes = result
                .get("node_count")
                .and_then(|v| v.as_u64())
                .unwrap_or(0);
            let edges = result
                .get("edge_count")
                .and_then(|v| v.as_u64())
                .unwrap_or(0);
            format!("ingested: {} nodes, {} edges. graph ready.", nodes, edges)
        }
        _ => String::new(),
    }
}

// ---------------------------------------------------------------------------
// _m1nd metadata builder
// ---------------------------------------------------------------------------

/// Build the `_m1nd` metadata envelope to wrap every tool response.
pub fn build_m1nd_meta(
    tool_name: &str,
    result: &Value,
    session_tokens_saved: u64,
    global_tokens_saved: u64,
) -> Value {
    let suggestions = suggest_next(tool_name);
    let personality = personality_line(tool_name, result);

    let mut meta = json!({
        "suggest_next": suggestions,
        "savings": {
            "query_tokens_saved": estimate_query_savings(tool_name),
            "session_total": session_tokens_saved,
        },
        "gaia": {
            "global_tokens_never_burned": global_tokens_saved,
        },
    });

    if !personality.is_empty() {
        meta["personality"] = Value::String(personality);
    }

    meta
}

/// Estimate tokens saved for a single query.
fn estimate_query_savings(tool_name: &str) -> u64 {
    match tool_name {
        "activate" | "seek" | "search" => 750,
        "impact" | "predict" | "counterfactual" => 1000,
        "surgical_context" => 3200,
        "surgical_context_v2" => 4800,
        "hypothesize" | "missing" => 1000,
        "apply" | "apply_batch" => 900,
        "scan" => 1000,
        _ => 500,
    }
}

// ---------------------------------------------------------------------------
// Help tool content
// ---------------------------------------------------------------------------

/// Tool documentation entry for the help system.
pub struct ToolDoc {
    pub name: &'static str,
    pub category: &'static str,
    pub glyph: &'static str,
    pub one_liner: &'static str,
    pub params: &'static [(&'static str, &'static str, bool)], // (name, description, required)
    pub returns: &'static str,
    pub example: &'static str,
    pub next: &'static [&'static str],
}

pub(crate) fn when_to_use(tool_name: &str) -> &'static [&'static str] {
    match tool_name {
        "search" => &[
            "Use when you already know the text, regex, or exact identifier you want.",
            "Best for precise string matching, scoped grep, and quick confirmation.",
        ],
        "seek" => &[
            "Use when you know the intent but not the exact symbol or filename.",
            "Best for natural-language retrieval before opening a likely file.",
        ],
        "glob" => &[
            "Use when the question is mainly about filenames or path patterns.",
            "Best for narrowing a file set before search, view, or surgical tools.",
        ],
        "trace" => &[
            "Use when you have an error or stacktrace and need the most likely file to inspect next.",
            "Best for turning failure text into a guided triage path.",
        ],
        "hypothesize" => &[
            "Use when you want to test a structural claim instead of manually proving it with grep.",
            "Best for yes-or-no dependency/path questions before editing.",
        ],
        "validate_plan" => &[
            "Use before a connected or risky edit when you want gaps, hotspots, and the next proof step.",
            "Best for deciding whether an edit plan is still proving or ready to execute.",
        ],
        "surgical_context_v2" => &[
            "Use when you need the target file plus connected proof files in one edit-prep surface.",
            "Best for compact multi-file grounding before validate_plan or apply_batch.",
        ],
        "trail_resume" => &[
            "Use when you are resuming an earlier investigation and want the next likely move, not just raw history.",
            "Best for continuity across long-running agent work.",
        ],
        "timeline" => &[
            "Use when the question is historical: what changed, when, and with what nearby churn.",
            "Best for commit history and co-change proof on a file.",
        ],
        "apply_batch" => &[
            "Use when you already know the multi-file edit set and want one write, one re-ingest, and one verdict.",
            "Best for execution after plan/proof, not for discovery.",
        ],
        "batch_view" => &[
            "Use when you need to read several files at once without paying one tool call per file.",
            "Best for audit sweeps, proof packets, and compact repo reading after glob/search/audit.",
        ],
        "scan_all" => &[
            "Use when you want grouped structural findings without manually calling scan eight times.",
            "Best at the start of an audit or before prioritizing a hardening pass.",
        ],
        "cross_verify" => &[
            "Use when you need filesystem truth, not just graph truth.",
            "Best for checking whether the graph, docs, and disk still agree before trusting an audit claim.",
        ],
        "coverage_session" => &[
            "Use when you are asking yourself what you have not inspected yet.",
            "Best during long sessions where rediscovery and duplicate reading become a risk.",
        ],
        "external_references" => &[
            "Use when the repo likely points outside its own root and you want those paths surfaced quickly.",
            "Best in coordination or planning repos that describe other systems.",
        ],
        "federate_auto" => &[
            "Use when external path evidence or local manifest/workspace hints are real and you want m1nd to turn them into repo candidates instead of assembling the federate input by hand.",
            "Best after external_references or audit, or when the current repo uses path/workspace manifests to point at sibling repos.",
        ],
        "audit" => &[
            "Use when you want one top-level structural pass instead of manually chaining health, panoramic, layers, scans, verification, and git context.",
            "Best as a session opener on unfamiliar or changing repos.",
        ],
        "ghost_edges" => &[
            "Use when you suspect historical hidden coupling that static imports or calls do not explain.",
        ],
        "taint_trace" => &[
            "Use when the question is about trust boundaries, validation, sanitization, or auth paths.",
        ],
        "twins" => &[
            "Use when you want to find structural duplication or near-equivalence before refactoring.",
        ],
        "refactor_plan" => &[
            "Use when you want graph-native extraction candidates instead of ad-hoc refactor instincts.",
        ],
        "runtime_overlay" => &[
            "Use when you have span data and want runtime heat painted onto the structural graph.",
        ],
        _ => &[
            "Use when this tool is the shortest path to the answer you need right now.",
        ],
    }
}

pub(crate) fn avoid_when(tool_name: &str) -> &'static [&'static str] {
    match tool_name {
        "search" => &[
            "Avoid when the problem is structural and you do not know the right text yet.",
        ],
        "seek" => &[
            "Avoid when you already have an exact string, regex, or filename.",
        ],
        "glob" => &[
            "Avoid when you need semantic or structural ranking instead of filename matching.",
        ],
        "trace" => &[
            "Avoid when you do not have failure text or when simple compiler output already points to one file.",
        ],
        "hypothesize" => &[
            "Avoid when a direct literal search or file read already settles the question cheaply.",
        ],
        "validate_plan" => &[
            "Avoid as the first move when you still do not know the edit surface.",
        ],
        "surgical_context_v2" => &[
            "Avoid for one-file questions where view or surgical_context is enough.",
        ],
        "trail_resume" => &[
            "Avoid when you are not resuming prior work or when the trail is clearly irrelevant.",
        ],
        "timeline" => &[
            "Avoid when you need runtime truth or current code shape rather than git history.",
        ],
        "apply_batch" => &[
            "Avoid while you are still discovering the plan or proving the target files.",
        ],
        "batch_view" => &["Avoid for one-file questions where view is enough."],
        "scan_all" => &["Avoid when you only need one specific pattern; plain scan is cheaper."],
        "cross_verify" => &[
            "Avoid when the question is purely structural and does not depend on current disk truth.",
        ],
        "coverage_session" => &[
            "Avoid at the very start of a session before any meaningful exploration has happened.",
        ],
        "external_references" => &[
            "Avoid when you already know the repo is self-contained and there are no outside path references to chase.",
        ],
        "audit" => &[
            "Avoid for tiny one-file questions where view, search, or impact already gives the answer directly.",
        ],
        "ghost_edges" => &[
            "Avoid when the repo has no meaningful git history or the question is only about current static structure.",
        ],
        "taint_trace" => &[
            "Avoid when the question is ordinary impact or duplication rather than trust-boundary flow.",
        ],
        "twins" => &[
            "Avoid when you need exact clone detection by text alone rather than structural similarity.",
        ],
        "refactor_plan" => &[
            "Avoid before you know the target region; use audit, scan_all, or twins first.",
        ],
        "runtime_overlay" => &["Avoid when you do not have runtime span data to overlay."],
        _ => &["Avoid when a simpler tool answers the question more directly."],
    }
}

fn agent_notes(tool_name: &str) -> &'static [&'static str] {
    match tool_name {
        "trace" => &[
            "Read proof_state before editing: triaging means inspect next, not patch yet.",
            "Prefer next_suggested_tool and next_suggested_target over manual follow-up guesses.",
        ],
        "hypothesize" => &[
            "Use proof_state to separate a strong structural handoff from an inconclusive one.",
        ],
        "validate_plan" => &[
            "Read proof_hint and next_step_hint before calling more tools.",
            "A proving state means keep gathering evidence; ready_to_edit means the plan is grounded enough to proceed.",
        ],
        "surgical_context_v2" => &[
            "proof_focused=true is for compact edit proof, not wide exploration.",
            "Use proof_state plus next_suggested_tool to decide whether to keep proving or move into execution.",
        ],
        "trail_resume" => &[
            "Treat this as continuity assist on the current graph, not perfect replay of old agent state.",
            "Prefer the returned next_focus_node_id and next_suggested_tool over a fresh search loop.",
        ],
        "timeline" => &[
            "Timeline is historical proof on files; it does not replace runtime or compiler truth.",
        ],
        "impact" => &[
            "Read proof_state before editing: triaging means inspect the seam first, not patch yet.",
            "Use next_suggested_target as the downstream seam to inspect before widening the edit.",
        ],
        "apply_batch" => &[
            "Use status_message and phases to drive shell/UI progress.",
            "Use active_phase, completed_phase_count, phase_count, remaining_phase_count, progress_pct, and next_phase for coarse progress without reconstructing the phase timeline yourself.",
            "Each phase can carry phase_index, current_file, progress_pct, and next_phase for better progress rendering.",
            "progress_events mirrors the same lifecycle in a streaming-friendly event shape for future MCP emission.",
            "Read proof_state plus next_suggested_tool after the batch finishes; apply_batch now hands off the next verification or inspection step instead of only returning a verdict.",
        ],
        "batch_view" => &[
            "Use this to keep the read loop compact during audits instead of opening files one by one.",
            "Pair with coverage_session when you want to know what is still unread after a broad sweep.",
        ],
        "scan_all" => &[
            "Treat grouped findings as a prioritization surface, not as proof to edit immediately.",
        ],
        "cross_verify" => &[
            "This is the graph-vs-disk truth check; prefer it before shell wc/ls/test fallbacks.",
        ],
        "coverage_session" => &[
            "Use it as attention control for the session: it answers what you still have not touched.",
        ],
        "external_references" => &[
            "Use this when you want raw path evidence first; use federate_auto when you want m1nd to bridge into repo discovery.",
        ],
        "federate_auto" => &[
            "This is the bridge from external path evidence and manifest/workspace hints into an actionable federation plan.",
        ],
        "audit" => &[
            "Use audit as the top-level orienter, then drop to narrower tools for proof and execution.",
            "Profiles change the emphasis, not just the labeling.",
        ],
        "ghost_edges" => &[
            "Ghost edges are historical evidence, not proof of a current static dependency.",
        ],
        "taint_trace" => &[
            "Read taint output as trust-boundary guidance, not as CodeQL-class formal proof.",
        ],
        "twins" => &[
            "Twins are candidates for consolidation; always check blast radius before acting on them.",
        ],
        "refactor_plan" => &[
            "Use this to turn structural duplication into a plan, then validate the plan before writing.",
        ],
        "runtime_overlay" => &[
            "This is strongest when you can compare runtime heat with structural risk or failure traces.",
        ],
        _ => &[],
    }
}

pub(crate) fn error_recovery_notes(tool_name: &str) -> &'static [&'static str] {
    match tool_name {
        "search" => &[
            "If search says scope/path is wrong, retry with a graph-relative scope or let auto-ingest resolve the path first.",
            "If search returns mostly fixture noise, tighten scope before reformulating the query.",
        ],
        "seek" => &[
            "If seek drifts, switch to search when you already know an exact string, or activate when you need neighborhood rather than ranking.",
            "Treat a weak semantic hit as a hint to inspect, not as proof to edit.",
        ],
        "trace" => &[
            "If trace says the failure text is too weak, pass the full error output instead of only the exception headline.",
            "If trace cannot ground the path, fall back to view on the top suspect or timeline for historical proof.",
        ],
        "impact" => &[
            "If impact cannot ground the seam, inspect the suggested downstream file before widening the edit plan.",
            "If the blast set feels too broad, move into validate_plan instead of opening more files blindly.",
        ],
        "validate_plan" => &[
            "If validate_plan says the edit surface is unresolved, gather proof with surgical_context_v2 or seek before retrying.",
            "If the plan is still proving, treat the returned next_step_hint as the shortest path to a stronger retry.",
        ],
        "surgical_context_v2" => &[
            "If the payload is too wide, retry with proof_focused=true or narrow to a symbol before opening more files.",
            "If connected tests are missing, use validate_plan to ask for test impact rather than guessing test files manually.",
        ],
        "trail_resume" => &[
            "If the trail is stale or thin, use the resume hints as a compact restart plan instead of rebuilding the whole investigation from scratch.",
            "If there is no next focus, resume into search or activate rather than reopening every prior file.",
        ],
        "batch_view" => &[
            "If the response is too wide, lower max_lines_per_file or use max_output_chars to keep the sweep compact.",
        ],
        "scan_all" => &[
            "If findings are too noisy, narrow the scope or limit patterns instead of reading every result at once.",
        ],
        "cross_verify" => &[
            "If drift looks surprising, narrow scope to one subtree before assuming the whole graph is stale.",
        ],
        "coverage_session" => &[
            "If coverage is low, follow with batch_view on the top unread files instead of reopening files you already saw.",
        ],
        "external_references" => &[
            "If the outside paths matter, hand off into federate or a broader audit instead of switching immediately to raw shell find.",
        ],
        "audit" => &[
            "If audit feels too broad, rerun it with a narrower profile or scope and then drop to a proof-focused tool.",
        ],
        "ghost_edges" => &[
            "If history is too thin, use timeline or current structural tools instead of over-reading ghost edges.",
        ],
        "taint_trace" => &[
            "If the entry points are wrong, tighten the starting nodes before trusting the propagation output.",
        ],
        "twins" => &[
            "If similarity is too loose, raise the threshold before turning a pair into refactor work.",
        ],
        "refactor_plan" => &[
            "If the communities are too broad, narrow scope before treating the plan as actionable.",
        ],
        "runtime_overlay" => &[
            "If runtime mapping is weak, improve span-node mapping before drawing structural conclusions from the overlay.",
        ],
        _ => &[
            "When a tool fails, look for the hint, example, and next-step guidance before reformulating from scratch.",
            "If the current tool is a bad fit, switch tools instead of forcing a second weak retry.",
        ],
    }
}

fn benchmark_notes(tool_name: &str) -> &'static [&'static str] {
    match tool_name {
        "trace" => &[
            "Usually strong for warm-graph triage and fast first-good-answer on failure text.",
            "Not a replacement for compiler/runtime truth; use it to narrow the next file fast.",
        ],
        "trail_resume" => &[
            "Usually one of the strongest continuity wins in the benchmark corpus.",
            "Best when avoiding rediscovery matters more than replaying every old thought exactly.",
        ],
        "validate_plan" => &[
            "Usually strong for compact proof handoff before risky edits.",
            "Best read as planning/proof guidance, not as a universal speed win on tiny edits.",
        ],
        "surgical_context_v2" => &[
            "Usually strong for compact connected edit prep, especially with proof_focused=true.",
            "Benchmark wins here are mostly about payload quality and clarity, not always zero search steps.",
        ],
        "seek" => &[
            "Usually strong when intent is known but exact text is not.",
            "Use search instead when exact text or regex is already obvious.",
        ],
        "impact" => &[
            "Usually useful for guided blast-radius follow-up and downstream seam selection.",
            "The main win is better follow-up targeting, not proving every dependency alone.",
        ],
        "hypothesize" => &[
            "Usually strong for structural yes-or-no questions and proof-target handoff.",
            "Best when grep would require several manual path checks to settle the claim.",
        ],
        "apply_batch" => &[
            "Benchmark value here is mostly safety, verification, and better progress UX.",
            "Use after discovery and proof; this is execution, not exploration.",
            "The newer wins here are about observability and handoff quality, not only token savings.",
        ],
        "batch_view" => &[
            "Benchmark value is mostly round-trip reduction during long read sweeps.",
        ],
        "scan_all" => &[
            "The win is orchestration compression: one grouped scan pass instead of eight tool calls.",
        ],
        "cross_verify" => &[
            "The value is trust calibration between graph state and filesystem truth, not token savings alone.",
        ],
        "coverage_session" => &[
            "The win is attention control in long sessions, not raw retrieval precision.",
        ],
        "external_references" => &[
            "The value is discovering outside-path evidence quickly; it is not yet automatic federation.",
        ],
        "audit" => &["The main gain is replacing long manual tool chains with one profile-aware entrypoint."],
        "ghost_edges" => &[
            "Best when git history is rich enough to expose hidden co-change coupling.",
        ],
        "taint_trace" => &[
            "Strongest on trust-boundary investigations, not as a universal flow tool.",
        ],
        "twins" => &[
            "Best as a fast structural duplication lens before refactor planning.",
        ],
        "refactor_plan" => &[
            "The win is graph-native extraction guidance, not automatic refactoring by itself.",
        ],
        "runtime_overlay" => &[
            "Strongest when paired with traces, hotspots, or structural risk views.",
        ],
        "timeline" => &[
            "Usually strongest when historical proof is the missing piece after localization.",
            "Less useful when the question is current code shape rather than git history.",
        ],
        "search" => &[
            "Usually best for exact text and cheap confirmation, not as a headline m1nd differentiator.",
        ],
        "glob" => &[
            "Usually best as a cheap narrowing step before more semantic or structural tools.",
        ],
        _ => &[],
    }
}

fn workflow_patterns(tool_name: &str) -> &'static [&'static str] {
    match tool_name {
        "trace" => &[
            "trace -> view -> surgical_context_v2",
            "trace -> timeline when the missing piece is historical proof",
        ],
        "trail_resume" => &[
            "trail_resume -> next_suggested_tool",
            "trail_resume -> timeline for temporal follow-up",
        ],
        "validate_plan" => &[
            "validate_plan -> heuristics_surface -> apply_batch",
            "validate_plan -> surgical_context_v2 when the edit surface is still too implicit",
        ],
        "surgical_context_v2" => &[
            "surgical_context_v2 -> validate_plan -> apply_batch",
            "surgical_context_v2(proof_focused=true) -> validate_plan for compact edit proof",
        ],
        "seek" => &[
            "seek -> view on the winning file",
            "seek -> surgical_context_v2 when the retrieved seam looks coupled",
        ],
        "impact" => &[
            "impact -> view on the strongest downstream target",
            "impact -> validate_plan before touching a high-blast seam",
        ],
        "hypothesize" => &[
            "hypothesize -> view or timeline on the strongest proof target",
            "hypothesize -> validate_plan when the claim is strong enough to shape an edit",
        ],
        "apply_batch" => &[
            "validate_plan -> heuristics_surface -> apply_batch(verify=true)",
            "apply_batch -> next_suggested_tool when verification says the batch still needs review",
        ],
        "audit" => &[
            "audit -> batch_view on the strongest evidence files",
            "audit -> cross_verify when the top-level report suggests graph/disk drift",
        ],
        "scan_all" => &[
            "audit -> scan_all -> batch_view on the strongest findings",
            "scan_all -> validate_plan when grouped findings imply a connected edit surface",
        ],
        "cross_verify" => &["audit -> cross_verify -> batch_view on the mismatched files"],
        "batch_view" => &[
            "audit or glob -> batch_view -> coverage_session",
            "batch_view -> search when the next move depends on exact text inside the returned files",
        ],
        "coverage_session" => &[
            "batch_view/search/seek -> coverage_session -> batch_view on the top unread files",
        ],
        "external_references" => &["audit(external_refs=true) -> external_references -> federate"],
        "federate_auto" => &["audit(external_refs=true) -> federate_auto -> federate or direct execute=true"],
        "ghost_edges" => &["ghost_edges -> timeline -> impact"],
        "taint_trace" => &["taint_trace -> validate_plan -> flow_simulate"],
        "twins" => &["twins -> refactor_plan -> validate_plan"],
        "refactor_plan" => &["twins -> refactor_plan -> validate_plan -> apply_batch"],
        "runtime_overlay" => &["runtime_overlay -> trace -> impact"],
        "timeline" => &["trace or trail_resume -> timeline -> view"],
        _ => &[],
    }
}

fn state_handoffs(tool_name: &str) -> &'static [&'static str] {
    match tool_name {
        "trace" => &[
            "triaging: inspect the suggested file next; do not patch yet.",
            "ready_to_edit: rare here; only trust it when the causal path is already strong.",
        ],
        "hypothesize" => &[
            "proving: gather the strongest proof target before turning the claim into an edit plan.",
            "ready_to_edit: the structural claim is grounded enough to shape a concrete change.",
        ],
        "validate_plan" => &[
            "proving: keep collecting proof on the risky seam before writing.",
            "ready_to_edit: the plan is grounded enough to execute.",
        ],
        "surgical_context_v2" => &[
            "triaging: you have context, but not enough proof to commit to a coupled edit yet.",
            "proving: the connected edit surface is grounded; validate or verify before writing.",
            "ready_to_edit: the edit surface is compact and sufficiently settled for execution.",
        ],
        "seek" => &[
            "triaging: the semantic hit is promising, but you still need to inspect the winning file.",
            "proving: the winning target is strong enough to move into file-level proof next.",
            "ready_to_edit: rare here; only trust it when retrieval lands on one dominant file-level target.",
        ],
        "impact" => &[
            "triaging: inspect the strongest downstream seam before turning blast radius into a plan.",
            "proving: the blast pattern is strong enough to validate the change against the impacted target next.",
            "ready_to_edit: rare here; only trust it when the causal chain is strong and specific enough to ground the seam.",
        ],
        "apply_batch" => &[
            "blocked: inspect the failed or broken target before retrying or promoting the batch.",
            "triaging: the batch wrote cleanly, but it still needs a verification pass before you trust it.",
            "proving: the batch finished, but the verification verdict is still risky and needs hotspot review.",
            "ready_to_edit: the batch verification is strong enough that follow-up work can continue safely.",
        ],
        "audit" => &[
            "triaging: the audit is a broad orienter; follow the strongest files or drift seams before editing.",
            "ready_to_edit: rare here; use it as a signal that the repo surface is already narrowed enough for plan/execution tools.",
        ],
        "scan_all" => &[
            "triaging: grouped findings tell you where to inspect next, not what to edit immediately.",
        ],
        "cross_verify" => &[
            "triaging: inspect mismatches before trusting a graph or documentation claim.",
        ],
        _ => &[],
    }
}

/// Get all tool documentation entries.
pub fn tool_docs() -> Vec<ToolDoc> {
    vec![
        ToolDoc {
            name: "activate",
            category: "Foundation",
            glyph: GLYPH_SIGNAL,
            one_liner: "Spreading activation query -- fire signal into the graph",
            params: &[
                ("query", "Search query for spreading activation", true),
                ("agent_id", "Calling agent identifier", true),
                ("top_k", "Number of top results (default: 20)", false),
                (
                    "dimensions",
                    "Activation dimensions (structural, semantic, temporal, causal)",
                    false,
                ),
                (
                    "xlr",
                    "Enable XLR noise cancellation (default: true)",
                    false,
                ),
            ],
            returns: "Ranked list of activated nodes with scores, dimensions, ghost edges",
            example: r#"{"query": "rate limiting", "agent_id": "jimi", "top_k": 10}"#,
            next: &["impact", "learn", "hypothesize"],
        },
        ToolDoc {
            name: "impact",
            category: "Foundation",
            glyph: GLYPH_SIGNAL,
            one_liner: "Blast radius analysis -- who gets hit when this changes",
            params: &[
                ("node_id", "Target node identifier", true),
                ("agent_id", "Calling agent identifier", true),
                (
                    "direction",
                    "forward | reverse | both (default: forward)",
                    false,
                ),
            ],
            returns: "Blast radius, causal chains, proof_state, and guided next-step target",
            example: r#"{"node_id": "file::backend/chat_handler.py", "agent_id": "jimi"}"#,
            next: &["view", "validate_plan", "counterfactual"],
        },
        ToolDoc {
            name: "missing",
            category: "Foundation",
            glyph: GLYPH_SIGNAL,
            one_liner: "Find structural holes -- what connections SHOULD exist but don't",
            params: &[
                ("query", "Topic to find structural holes around", true),
                ("agent_id", "Calling agent identifier", true),
            ],
            returns: "Missing edges, ghost edges, structural holes",
            example: r#"{"query": "authentication", "agent_id": "jimi"}"#,
            next: &["activate", "hypothesize"],
        },
        ToolDoc {
            name: "why",
            category: "Foundation",
            glyph: GLYPH_PATH,
            one_liner: "Path explanation -- how are two nodes connected?",
            params: &[
                ("source", "Source node", true),
                ("target", "Target node", true),
                ("agent_id", "Calling agent identifier", true),
                ("max_hops", "Maximum hops (default: 6)", false),
            ],
            returns: "Shortest path with edge weights and relation types",
            example: r#"{"source": "file::auth.py", "target": "file::db.py", "agent_id": "jimi"}"#,
            next: &["trace", "impact"],
        },
        ToolDoc {
            name: "warmup",
            category: "Foundation",
            glyph: GLYPH_SIGNAL,
            one_liner: "Task-based priming -- prepare the graph for focused work",
            params: &[
                ("task_description", "Description of the task", true),
                ("agent_id", "Calling agent identifier", true),
            ],
            returns: "Primed node count, boost summary",
            example: r#"{"task_description": "fix rate limiting in smart_router", "agent_id": "jimi"}"#,
            next: &["activate", "impact"],
        },
        ToolDoc {
            name: "counterfactual",
            category: "Foundation",
            glyph: GLYPH_STRUCTURE,
            one_liner: "What-if simulation -- what breaks if we remove these nodes?",
            params: &[
                ("node_ids", "Nodes to simulate removal of", true),
                ("agent_id", "Calling agent identifier", true),
            ],
            returns: "Orphaned nodes, broken paths, cascade impact",
            example: r#"{"node_ids": ["file::legacy.py"], "agent_id": "jimi"}"#,
            next: &["impact", "predict"],
        },
        ToolDoc {
            name: "predict",
            category: "Foundation",
            glyph: GLYPH_DIMENSION,
            one_liner: "Co-change prediction -- what else needs to change?",
            params: &[
                ("changed_node", "Node that was changed", true),
                ("agent_id", "Calling agent identifier", true),
                ("top_k", "Number of predictions (default: 10)", false),
            ],
            returns: "Predicted co-change nodes with probability scores",
            example: r#"{"changed_node": "file::session.py", "agent_id": "jimi"}"#,
            next: &["impact", "learn"],
        },
        ToolDoc {
            name: "fingerprint",
            category: "Foundation",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Activation fingerprint -- find duplicate/equivalent code",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("target_node", "Node to find equivalents for", false),
                (
                    "similarity_threshold",
                    "Cosine similarity threshold (default: 0.85)",
                    false,
                ),
            ],
            returns: "Equivalent node pairs with similarity scores",
            example: r#"{"target_node": "file::utils.py", "agent_id": "jimi"}"#,
            next: &["counterfactual", "differential"],
        },
        ToolDoc {
            name: "drift",
            category: "Foundation",
            glyph: GLYPH_DIMENSION,
            one_liner: "Weight drift since last session -- what changed in the graph?",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                (
                    "since",
                    "Baseline: last_session (default) or ISO date",
                    false,
                ),
            ],
            returns: "Edge weight changes, node additions/removals",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["activate", "ingest"],
        },
        ToolDoc {
            name: "learn",
            category: "Foundation",
            glyph: GLYPH_CONNECTION,
            one_liner: "Hebbian feedback -- correct/wrong/partial strengthens edges",
            params: &[
                ("query", "Original query", true),
                ("agent_id", "Calling agent identifier", true),
                ("feedback", "correct | wrong | partial", true),
                ("node_ids", "Nodes to apply feedback to", true),
            ],
            returns: "Updated edge weights, plasticity state",
            example: r#"{"query": "auth flow", "feedback": "correct", "node_ids": ["file::auth.py"], "agent_id": "jimi"}"#,
            next: &["activate", "predict"],
        },
        ToolDoc {
            name: "ingest",
            category: "Foundation",
            glyph: GLYPH_CONNECTION,
            one_liner: "Load codebase into the graph -- the foundation of everything",
            params: &[
                ("path", "Filesystem path to source root", true),
                ("agent_id", "Calling agent identifier", true),
                (
                    "adapter",
                    "code | json | memory | light (default: code)",
                    false,
                ),
                ("mode", "replace | merge (default: replace)", false),
            ],
            returns: "Node/edge counts, ingest stats",
            example: r#"{"path": "/project/backend", "agent_id": "jimi"}"#,
            next: &["activate", "layers", "panoramic"],
        },
        ToolDoc {
            name: "resonate",
            category: "Foundation",
            glyph: GLYPH_SIGNAL,
            one_liner: "Standing wave harmonics -- find resonant patterns in the graph",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("query", "Seed query", false),
                ("node_id", "Specific seed node", false),
            ],
            returns: "Harmonics, sympathetic pairs, resonant frequencies",
            example: r#"{"query": "error handling", "agent_id": "jimi"}"#,
            next: &["activate", "fingerprint"],
        },
        ToolDoc {
            name: "health",
            category: "Foundation",
            glyph: GLYPH_DIMENSION,
            one_liner: "Server health -- graph size, uptime, sessions, host-binding contract",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Status, node/edge counts, uptime, active sessions, binding fingerprint, and tool-surface contract",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["trust_selftest", "session_handshake", "doctor"],
        },
        ToolDoc {
            name: "trust_selftest",
            category: "Foundation",
            glyph: GLYPH_DIMENSION,
            one_liner: "Trust selftest -- one-call verdict for m1nd binding and recovery readiness",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("observed_tool_count", "Optional host tools/list count", false),
                ("available_tools", "Optional host-exposed tool names", false),
                ("observed_tool", "Tool that produced a suspicious result", false),
                ("observed_proof_state", "Observed proof_state, such as blocked", false),
                ("observed_candidates", "Observed retrieval candidate count", false),
                ("scope", "Optional repo/scope path for Context Guard binding checks", false),
            ],
            returns: "Verdict, checks, binding fingerprint, graph state, context_guard, session handshake, and optional recovery playbook",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["session_handshake", "recovery_playbook", "ingest"],
        },
        ToolDoc {
            name: "session_handshake",
            category: "Foundation",
            glyph: GLYPH_DIMENSION,
            one_liner: "Session handshake -- classify whether this m1nd binding is trustworthy",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("observed_tool_count", "Optional host tools/list count", false),
                ("available_tools", "Optional host-exposed tool names", false),
                ("missing_tools", "Optional missing recovery tool names", false),
                ("scope", "Optional repo/scope path for Context Guard binding checks", false),
            ],
            returns: "Trust mode, capability flags, graph state, tool-surface status, context_guard, and doctor recovery payload",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["recovery_playbook", "ingest", "doctor"],
        },
        ToolDoc {
            name: "recovery_playbook",
            category: "Foundation",
            glyph: GLYPH_DIMENSION,
            one_liner: "Recovery playbook -- deterministic next steps for degraded or stale sessions",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("trust_mode", "Optional prior handshake trust mode", false),
                ("observed_tool", "Tool that produced a suspicious result", false),
                ("observed_proof_state", "Observed proof_state, such as blocked", false),
                ("observed_candidates", "Observed retrieval candidate count", false),
                ("scope", "Optional repo/scope path for Context Guard binding checks", false),
            ],
            returns: "Status, trust mode, context_guard, binding fingerprint, graph/tool summaries, and ordered recovery steps",
            example: r#"{"agent_id": "jimi", "observed_tool": "seek", "observed_proof_state": "blocked", "observed_candidates": 0}"#,
            next: &["doctor", "session_handshake", "ingest"],
        },
        ToolDoc {
            name: "doctor",
            category: "Foundation",
            glyph: GLYPH_DIMENSION,
            one_liner: "Runtime doctor -- diagnose graph/session/binding continuity",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("observed_tool", "Tool that returned a suspicious result", false),
                ("observed_proof_state", "Observed proof_state, such as blocked", false),
                ("observed_candidates", "Observed retrieval candidate count", false),
                ("scope", "Optional repo/scope path for Context Guard binding checks", false),
            ],
            returns: "Graph/runtime/session state, context_guard, warnings, probable causes, next actions",
            example: r#"{"agent_id": "jimi", "observed_tool": "seek", "observed_proof_state": "blocked", "observed_candidates": 0}"#,
            next: &["ingest", "seek", "help"],
        },
        // --- Superpowers ---
        ToolDoc {
            name: "seek",
            category: "Superpowers",
            glyph: GLYPH_PATH,
            one_liner: "Intent-aware semantic search -- find code by PURPOSE",
            params: &[
                ("query", "Natural language query", true),
                ("agent_id", "Calling agent identifier", true),
                ("top_k", "Max results (default: 20)", false),
                ("scope", "File path prefix filter", false),
            ],
            returns: "Ranked results with trigram + PageRank scoring",
            example: r#"{"query": "rate limit retry logic", "agent_id": "jimi"}"#,
            next: &["impact", "learn"],
        },
        ToolDoc {
            name: "scan",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Pattern-based structural analysis with graph validation",
            params: &[
                (
                    "pattern",
                    "Pattern ID (error_handling, concurrency, auth_boundary, etc.)",
                    true,
                ),
                ("agent_id", "Calling agent identifier", true),
                ("scope", "File path prefix", false),
            ],
            returns: "Findings with severity, graph-validated",
            example: r#"{"pattern": "error_handling", "agent_id": "jimi"}"#,
            next: &["hypothesize", "impact"],
        },
        ToolDoc {
            name: "search",
            category: "Superpowers",
            glyph: GLYPH_PATH,
            one_liner: "Literal/regex/semantic code search with graph context",
            params: &[
                ("query", "Search term or regex pattern", true),
                ("agent_id", "Calling agent identifier", true),
                (
                    "mode",
                    "literal | regex | semantic (default: literal)",
                    false,
                ),
                ("scope", "File path prefix filter", false),
                ("top_k", "Max results (default: 50, max: 500)", false),
                (
                    "context_lines",
                    "Lines of context (default: 2, max: 10)",
                    false,
                ),
                (
                    "case_sensitive",
                    "Case-sensitive matching (default: false)",
                    false,
                ),
            ],
            returns: "File matches with context lines and graph node cross-references",
            example: r#"{"query": "ANTHROPIC_API_KEY", "agent_id": "jimi", "mode": "literal"}"#,
            next: &["impact", "learn"],
        },
        ToolDoc {
            name: "scan_all",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Run all structural scan patterns in one grouped pass",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("scope", "File path prefix to limit scope", false),
                ("severity_min", "Minimum severity threshold", false),
                ("graph_validate", "Validate findings against graph edges", false),
                ("limit_per_pattern", "Maximum findings per pattern", false),
                ("patterns", "Optional subset of patterns", false),
            ],
            returns: "Grouped findings by pattern with per-pattern counts",
            example: r#"{"agent_id": "jimi", "scope": "src", "severity_min": 0.3}"#,
            next: &["batch_view", "validate_plan"],
        },
        // --- Extended ---
        ToolDoc {
            name: "hypothesize",
            category: "Extended",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Test a structural claim and surface the strongest next proof target",
            params: &[
                ("claim", "Natural language claim", true),
                ("agent_id", "Calling agent identifier", true),
            ],
            returns: "Verdict, confidence, evidence, proof_state, and guided follow-up target",
            example: r#"{"claim": "chat_handler validates session tokens", "agent_id": "jimi"}"#,
            next: &["view", "timeline", "validate_plan"],
        },
        ToolDoc {
            name: "trace",
            category: "Extended",
            glyph: GLYPH_PATH,
            one_liner: "Failure triage -- map error text to the best next file and proof stage",
            params: &[
                ("query", "Start node or query", true),
                ("agent_id", "Calling agent identifier", true),
            ],
            returns: "Suspects, causal chain, proof_state, and guided next-step file",
            example: r#"{"query": "file::auth.py", "agent_id": "jimi"}"#,
            next: &["view", "timeline", "surgical_context_v2"],
        },
        ToolDoc {
            name: "differential",
            category: "Extended",
            glyph: GLYPH_DIMENSION,
            one_liner: "Compare two subgraphs -- structural diff",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("group_a", "First set of nodes", true),
                ("group_b", "Second set of nodes", true),
            ],
            returns: "Shared/unique nodes, edge deltas, structural similarity",
            example: r#"{"group_a": ["file::v1.py"], "group_b": ["file::v2.py"], "agent_id": "jimi"}"#,
            next: &["fingerprint", "counterfactual"],
        },
        ToolDoc {
            name: "validate_plan",
            category: "Extended",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Validate a multi-step code change plan against the graph",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("plan", "Array of file changes", true),
            ],
            returns: "Validation result, proof_state, proof_hint, and guided next-step target",
            example: r#"{"plan": [{"file": "auth.py", "action": "modify"}], "agent_id": "jimi"}"#,
            next: &["heuristics_surface", "apply_batch", "surgical_context_v2"],
        },
        ToolDoc {
            name: "federate",
            category: "Extended",
            glyph: GLYPH_CONNECTION,
            one_liner: "Query across graph namespaces",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("query", "Search query", true),
            ],
            returns: "Results from all namespaces with provenance",
            example: r#"{"query": "authentication", "agent_id": "jimi"}"#,
            next: &["activate", "why"],
        },
        ToolDoc {
            name: "cross_verify",
            category: "Extended",
            glyph: GLYPH_DIMENSION,
            one_liner: "Compare graph state against disk truth: files, LOC drift, and hashes",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("scope", "File path prefix to limit scope", false),
                ("check", "Checks: existence, loc, hash", false),
                ("include_dotfiles", "Include selected dotfiles", false),
                ("dotfile_patterns", "Allowed dotfile patterns", false),
            ],
            returns: "Graph-vs-disk mismatches with stale confidence",
            example: r#"{"agent_id": "jimi", "scope": "src", "check": ["existence", "loc", "hash"]}"#,
            next: &["batch_view", "audit"],
        },
        ToolDoc {
            name: "coverage_session",
            category: "Extended",
            glyph: GLYPH_DIMENSION,
            one_liner: "Show what this agent session has and has not inspected yet",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Visited files, unvisited files, coverage percentage, tools used",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["batch_view", "seek", "search"],
        },
        ToolDoc {
            name: "external_references",
            category: "Extended",
            glyph: GLYPH_CONNECTION,
            one_liner: "Find explicit file path references that point outside current ingest roots",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("scope", "File path prefix to limit scope", false),
            ],
            returns: "External paths with existence checks and suggested follow-up action",
            example: r#"{"agent_id": "jimi", "scope": "docs"}"#,
            next: &["federate_auto", "audit"],
        },
        ToolDoc {
            name: "federate_auto",
            category: "Extended",
            glyph: GLYPH_CONNECTION,
            one_liner: "Turn external path or manifest/workspace evidence into repo candidates and optional one-shot federation",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("scope", "File path prefix to limit discovery sources", false),
                ("current_repo_name", "Optional namespace override for the current workspace", false),
                ("max_repos", "Maximum discovered repos to include", false),
                ("detect_cross_repo_edges", "Whether execute=true should auto-detect cross-repo edges", false),
                ("execute", "Immediately run federate with current + discovered repos", false),
            ],
            returns: "Suggested namespaces, repo roots, skipped paths, and optional federate result",
            example: r#"{"agent_id": "jimi", "scope": "docs", "execute": false}"#,
            next: &["federate", "audit"],
        },
        // --- Superpowers: Immunology, Seismology, etc. ---
        ToolDoc {
            name: "antibody_scan",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Immune system -- scan for known bug patterns",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Antibody matches with severity and affected nodes",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["antibody_create", "panoramic"],
        },
        ToolDoc {
            name: "antibody_list",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "List all stored antibody patterns",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "All antibodies with patterns and match counts",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["antibody_create", "antibody_scan"],
        },
        ToolDoc {
            name: "antibody_create",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Create a new antibody bug pattern",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("pattern", "Bug pattern to detect", true),
                ("description", "Human-readable description", true),
            ],
            returns: "Created antibody with ID",
            example: r#"{"pattern": "unwrap().unwrap()", "description": "double unwrap", "agent_id": "jimi"}"#,
            next: &["antibody_scan"],
        },
        ToolDoc {
            name: "flow_simulate",
            category: "Superpowers",
            glyph: GLYPH_PATH,
            one_liner: "Fluid dynamics -- simulate data flow and detect bottlenecks",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Flow paths, bottlenecks, race condition candidates",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["epidemic", "panoramic"],
        },
        ToolDoc {
            name: "epidemic",
            category: "Superpowers",
            glyph: GLYPH_CONNECTION,
            one_liner: "SIR model -- predict how bugs spread through the codebase",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Infection spread prediction, SIR curves",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["antibody_scan", "panoramic"],
        },
        ToolDoc {
            name: "tremor",
            category: "Superpowers",
            glyph: GLYPH_DIMENSION,
            one_liner: "Seismology -- detect change acceleration and volatility",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Tremor magnitude, frequency, affected regions",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["trust", "panoramic"],
        },
        ToolDoc {
            name: "trust",
            category: "Superpowers",
            glyph: GLYPH_DIMENSION,
            one_liner: "Actuarial trust scoring -- per-node defect risk assessment",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Trust scores per node with defect history",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["tremor", "panoramic"],
        },
        ToolDoc {
            name: "layers",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Detect architectural layers and violations",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Detected layers, layer assignments, violations",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["layer_inspect", "panoramic"],
        },
        ToolDoc {
            name: "layer_inspect",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Inspect a specific architectural layer",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("layer", "Layer name to inspect", true),
            ],
            returns: "Layer members, statistics, violations",
            example: r#"{"layer": "api", "agent_id": "jimi"}"#,
            next: &["layers", "impact"],
        },
        ToolDoc {
            name: "ghost_edges",
            category: "Superpowers",
            glyph: GLYPH_CONNECTION,
            one_liner: "Surface historical co-change edges with no explicit static dependency",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("depth", "Git history window: 7d, 30d, 90d, all", false),
                ("scope", "File path prefix to limit scope", false),
                ("top_k", "Maximum ghost edges to return", false),
            ],
            returns: "Ghost edges ranked by temporal coupling strength",
            example: r#"{"agent_id": "jimi", "depth": "30d", "scope": "src"}"#,
            next: &["timeline", "impact"],
        },
        ToolDoc {
            name: "taint_trace",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Trace taint propagation from entry nodes through trust boundaries",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("entry_nodes", "Entry point node IDs to inject taint", true),
                ("taint_type", "user_input, sensitive_data, or custom", false),
                ("boundary_patterns", "Custom boundary patterns", false),
                ("max_depth", "Maximum propagation depth", false),
            ],
            returns: "Propagation graph, suspicious sinks, and boundary misses",
            example: r#"{"agent_id": "jimi", "entry_nodes": ["file::src/api.rs"]}"#,
            next: &["validate_plan", "flow_simulate"],
        },
        ToolDoc {
            name: "twins",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Find structurally equivalent or near-equivalent nodes",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("similarity_threshold", "Minimum cosine similarity threshold", false),
                ("top_k", "Maximum twin pairs to return", false),
                ("scope", "File path prefix to limit scope", false),
            ],
            returns: "Twin pairs with structural similarity scores",
            example: r#"{"agent_id": "jimi", "similarity_threshold": 0.8}"#,
            next: &["refactor_plan", "impact"],
        },
        ToolDoc {
            name: "refactor_plan",
            category: "Superpowers",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Suggest graph-native extraction communities for refactoring",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("scope", "File path prefix to limit scope", false),
                ("max_communities", "Maximum communities to consider", false),
                ("min_community_size", "Minimum nodes per candidate", false),
            ],
            returns: "Proposed extraction communities and refactor candidates",
            example: r#"{"agent_id": "jimi", "scope": "src/payment"}"#,
            next: &["validate_plan", "apply_batch"],
        },
        ToolDoc {
            name: "runtime_overlay",
            category: "Superpowers",
            glyph: GLYPH_DIMENSION,
            one_liner: "Overlay runtime span heat, latency, and error signals onto the graph",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("spans", "OpenTelemetry spans to ingest", true),
                ("service_name", "Optional service name scope", false),
                ("mapping_strategy", "label_match, code_attribute, exact_id", false),
            ],
            returns: "Runtime heat overlay attached to graph nodes",
            example: r#"{"agent_id": "jimi", "spans": [{\"name\": \"auth.request\", \"duration_us\": 1200, \"parent\": null}]}"#,
            next: &["trace", "panoramic"],
        },
        // --- Surgical ---
        ToolDoc {
            name: "surgical_context",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Targeted code context extraction -- read only what matters",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("query", "What you need context for", true),
            ],
            returns: "Relevant code snippets with provenance",
            example: r#"{"query": "session pool initialization", "agent_id": "jimi"}"#,
            next: &["apply", "apply_batch"],
        },
        ToolDoc {
            name: "surgical_context_v2",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Connected edit prep -- compact proof-focused context before risky writes",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("query", "What you need context for", true),
            ],
            returns: "Connected code context, proof_state, and guided next-step handoff",
            example: r#"{"query": "chat handler message routing", "agent_id": "jimi"}"#,
            next: &["validate_plan", "apply_batch", "edit_preview"],
        },
        ToolDoc {
            name: "apply",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Apply a code change and update the graph",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("file", "Target file path", true),
                ("content", "New content", true),
            ],
            returns: "Apply result with graph update status",
            example: r#"{"file": "backend/auth.py", "content": "...", "agent_id": "jimi"}"#,
            next: &["predict", "learn"],
        },
        ToolDoc {
            name: "apply_batch",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Apply multiple code changes atomically",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("edits", "Array of file edits", true),
            ],
            returns: "Batch result with per-file status",
            example: r#"{"edits": [{"file": "a.py", "content": "..."}], "agent_id": "jimi"}"#,
            next: &["predict", "learn"],
        },
        ToolDoc {
            name: "edit_preview",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Preview a code change without writing to disk",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("file_path", "Target file path", true),
                ("new_content", "Proposed new content", true),
                ("description", "Human-readable description", false),
            ],
            returns: "Preview handle, source snapshot, unified diff, validation report",
            example: r#"{"file_path": "src/auth.py", "new_content": "...", "agent_id": "jimi"}"#,
            next: &["edit_commit"],
        },
        ToolDoc {
            name: "edit_commit",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Commit a previewed change to disk (requires confirm=true)",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("preview_id", "Handle from edit_preview", true),
                ("confirm", "Must be true to proceed", true),
                (
                    "reingest",
                    "Re-ingest file into graph (default true)",
                    false,
                ),
            ],
            returns: "Commit result with bytes written, graph updates",
            example: r#"{"preview_id": "preview_jimi_17...", "confirm": true, "agent_id": "jimi"}"#,
            next: &["predict", "learn"],
        },
        // --- Perspective ---
        ToolDoc {
            name: "perspective_start",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Enter a perspective -- create a navigable route surface from a query",
            params: &[
                ("query", "Seed query for route synthesis", true),
                ("agent_id", "Calling agent identifier", true),
                (
                    "anchor_node",
                    "Anchor to a specific node (activates anchored mode)",
                    false,
                ),
                ("lens", "Starting lens configuration", false),
            ],
            returns: "Perspective ID, initial route set, focus node",
            example: r#"{"query": "authentication flow", "agent_id": "jimi"}"#,
            next: &[
                "perspective_routes",
                "perspective_follow",
                "perspective_suggest",
            ],
        },
        ToolDoc {
            name: "perspective_routes",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Browse the current route set with pagination",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
                ("page", "Page number, 1-based (default: 1)", false),
                (
                    "page_size",
                    "Routes per page, clamped 1-10 (default: 6)",
                    false,
                ),
                (
                    "route_set_version",
                    "Version from previous response for staleness check",
                    false,
                ),
            ],
            returns: "Paginated routes with labels, scores, and route IDs",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123"}"#,
            next: &[
                "perspective_inspect",
                "perspective_follow",
                "perspective_peek",
            ],
        },
        ToolDoc {
            name: "perspective_inspect",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Expand a route with full path, metrics, provenance, and affinity",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
                ("route_set_version", "Version for staleness check", true),
                ("route_id", "Stable content-addressed route ID", false),
                ("route_index", "1-based page-local position", false),
            ],
            returns: "Full route path with edge weights, provenance, affinity scores",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123", "route_id": "r-def456", "route_set_version": 1}"#,
            next: &[
                "perspective_follow",
                "perspective_peek",
                "perspective_affinity",
            ],
        },
        ToolDoc {
            name: "perspective_peek",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Extract a small relevant code/doc slice from a route target",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
                ("route_set_version", "Version for staleness check", true),
                ("route_id", "Stable route ID", false),
                ("route_index", "1-based page-local position", false),
            ],
            returns: "Code snippet from target node with line numbers",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123", "route_id": "r-def456", "route_set_version": 1}"#,
            next: &["perspective_follow", "perspective_inspect"],
        },
        ToolDoc {
            name: "perspective_follow",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Follow a route -- move focus to target, synthesize new routes",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
                ("route_set_version", "Version for staleness check", true),
                ("route_id", "Stable route ID", false),
                ("route_index", "1-based page-local position", false),
            ],
            returns: "New focus node, new route set, navigation depth",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123", "route_id": "r-def456", "route_set_version": 1}"#,
            next: &[
                "perspective_routes",
                "perspective_back",
                "perspective_suggest",
            ],
        },
        ToolDoc {
            name: "perspective_suggest",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Get next best move suggestion based on navigation history",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
                ("route_set_version", "Version for staleness check", true),
            ],
            returns: "Suggested route with reasoning based on coverage gaps",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123", "route_set_version": 1}"#,
            next: &["perspective_follow", "perspective_inspect"],
        },
        ToolDoc {
            name: "perspective_affinity",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Discover probable connections a route target might have",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
                ("route_set_version", "Version for staleness check", true),
                ("route_id", "Stable route ID", false),
                ("route_index", "1-based page-local position", false),
            ],
            returns: "Affinity edges with strength scores and shared dimensions",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123", "route_id": "r-def456", "route_set_version": 1}"#,
            next: &["perspective_follow", "perspective_inspect"],
        },
        ToolDoc {
            name: "perspective_branch",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Fork the current navigation state into a new branch",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
                ("branch_name", "Optional name for the branch", false),
            ],
            returns: "New perspective ID for the branch, inherited state",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123", "branch_name": "auth-deep-dive"}"#,
            next: &["perspective_routes", "perspective_compare"],
        },
        ToolDoc {
            name: "perspective_back",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Navigate back to previous focus, restoring checkpoint state",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Active perspective ID", true),
            ],
            returns: "Restored focus node, previous route set",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123"}"#,
            next: &["perspective_routes", "perspective_follow"],
        },
        ToolDoc {
            name: "perspective_compare",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Compare two perspectives on shared/unique nodes and dimension deltas",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id_a", "First perspective ID", true),
                ("perspective_id_b", "Second perspective ID", true),
                ("dimensions", "Dimensions to compare (empty = all)", false),
            ],
            returns: "Shared nodes, unique nodes per perspective, dimension deltas",
            example: r#"{"agent_id": "jimi", "perspective_id_a": "p-abc123", "perspective_id_b": "p-def456"}"#,
            next: &["perspective_inspect", "perspective_branch"],
        },
        ToolDoc {
            name: "perspective_list",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "List all perspectives for an agent",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Active perspectives with focus nodes, route counts, depth",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["perspective_start", "perspective_close"],
        },
        ToolDoc {
            name: "perspective_close",
            category: "Perspective",
            glyph: GLYPH_PATH,
            one_liner: "Close a perspective and release associated locks",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("perspective_id", "Perspective ID to close", true),
            ],
            returns: "Confirmation with released resource count",
            example: r#"{"agent_id": "jimi", "perspective_id": "p-abc123"}"#,
            next: &["perspective_list", "perspective_start"],
        },
        // --- Lock ---
        ToolDoc {
            name: "lock_create",
            category: "Lock",
            glyph: GLYPH_CONNECTION,
            one_liner: "Pin a subgraph region and capture a baseline for change monitoring",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                (
                    "scope",
                    "Lock scope: node | subgraph | query_neighborhood | path",
                    true,
                ),
                ("root_nodes", "Root node IDs for the lock", true),
                ("radius", "BFS radius for subgraph scope (1-4)", false),
                ("query", "Query for query_neighborhood scope", false),
                ("path_nodes", "Ordered nodes for path scope", false),
            ],
            returns: "Lock ID, baseline snapshot, locked node count",
            example: r#"{"agent_id": "jimi", "scope": "subgraph", "root_nodes": ["file::auth.py"], "radius": 2}"#,
            next: &["lock_watch", "lock_diff", "lock_release"],
        },
        ToolDoc {
            name: "lock_watch",
            category: "Lock",
            glyph: GLYPH_CONNECTION,
            one_liner: "Set a watcher strategy on a lock (manual, on_ingest, on_learn)",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("lock_id", "Lock to configure", true),
                (
                    "strategy",
                    "Watcher strategy: manual | on_ingest | on_learn",
                    true,
                ),
            ],
            returns: "Updated lock with active watcher strategy",
            example: r#"{"agent_id": "jimi", "lock_id": "lk-abc123", "strategy": "on_ingest"}"#,
            next: &["lock_diff", "lock_release"],
        },
        ToolDoc {
            name: "lock_diff",
            category: "Lock",
            glyph: GLYPH_CONNECTION,
            one_liner: "Compute what changed in a locked region since baseline",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("lock_id", "Lock to diff", true),
            ],
            returns: "Added/removed/modified nodes and edges since baseline",
            example: r#"{"agent_id": "jimi", "lock_id": "lk-abc123"}"#,
            next: &["lock_rebase", "lock_release", "impact"],
        },
        ToolDoc {
            name: "lock_rebase",
            category: "Lock",
            glyph: GLYPH_CONNECTION,
            one_liner: "Re-capture lock baseline from current graph without releasing",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("lock_id", "Lock to rebase", true),
            ],
            returns: "Updated baseline with new snapshot timestamp",
            example: r#"{"agent_id": "jimi", "lock_id": "lk-abc123"}"#,
            next: &["lock_diff", "lock_watch"],
        },
        ToolDoc {
            name: "lock_release",
            category: "Lock",
            glyph: GLYPH_CONNECTION,
            one_liner: "Release a lock and free its resources",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("lock_id", "Lock to release", true),
            ],
            returns: "Confirmation with lock duration and change summary",
            example: r#"{"agent_id": "jimi", "lock_id": "lk-abc123"}"#,
            next: &["lock_create", "perspective_start"],
        },
        // --- Temporal Intelligence ---
        ToolDoc {
            name: "timeline",
            category: "Temporal",
            glyph: GLYPH_DIMENSION,
            one_liner: "Git-based temporal history -- changes, co-changes, velocity, stability",
            params: &[
                (
                    "node",
                    "Node external_id (e.g. file::backend/chat_handler.py)",
                    true,
                ),
                ("agent_id", "Calling agent identifier", true),
                (
                    "depth",
                    "Time depth: 7d, 30d, 90d, all (default: 30d)",
                    false,
                ),
                (
                    "include_co_changes",
                    "Include co-changed files with coupling scores (default: true)",
                    false,
                ),
                (
                    "include_churn",
                    "Include lines added/deleted churn data (default: true)",
                    false,
                ),
                (
                    "top_k",
                    "Max co-change partners to return (default: 10)",
                    false,
                ),
            ],
            returns: "Commit history, co-change coupling matrix, churn velocity, stability score",
            example: r#"{"node": "file::backend/chat_handler.py", "agent_id": "jimi", "depth": "30d"}"#,
            next: &["diverge", "predict", "impact"],
        },
        ToolDoc {
            name: "diverge",
            category: "Temporal",
            glyph: GLYPH_DIMENSION,
            one_liner: "Detect structural drift between a baseline and current graph state",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                (
                    "baseline",
                    "Baseline reference: ISO date, git ref, or last_session",
                    true,
                ),
                ("scope", "File path glob to limit scope", false),
                (
                    "include_coupling_changes",
                    "Include coupling matrix delta (default: true)",
                    false,
                ),
                (
                    "include_anomalies",
                    "Detect anomalies like test deficits, velocity spikes (default: true)",
                    false,
                ),
            ],
            returns: "Structural deltas, coupling drift, anomalies with severity",
            example: r#"{"agent_id": "jimi", "baseline": "last_session"}"#,
            next: &["timeline", "drift", "impact"],
        },
        // --- Investigation Memory ---
        ToolDoc {
            name: "trail_save",
            category: "Trail",
            glyph: GLYPH_PATH,
            one_liner: "Persist current investigation state -- nodes, hypotheses, conclusions",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("label", "Human-readable label for this investigation", true),
                (
                    "hypotheses",
                    "Hypotheses formed during investigation",
                    false,
                ),
                ("conclusions", "Conclusions reached", false),
                ("open_questions", "Open questions remaining", false),
                ("tags", "Tags for organization and search", false),
                ("summary", "Summary (auto-generated if omitted)", false),
                ("visited_nodes", "Visited nodes with annotations", false),
                (
                    "activation_boosts",
                    "Map of node_id -> boost weight [0.0, 1.0]",
                    false,
                ),
            ],
            returns: "Trail ID, persisted node count, saved timestamp",
            example: r#"{"agent_id": "jimi", "label": "auth flow investigation", "tags": ["security", "auth"]}"#,
            next: &["trail_resume", "trail_list", "trail_merge"],
        },
        ToolDoc {
            name: "trail_resume",
            category: "Trail",
            glyph: GLYPH_PATH,
            one_liner:
                "Resume an investigation with actionable continuity, next focus, and next tool",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("trail_id", "Trail ID to resume", true),
                (
                    "force",
                    "Resume even if trail is stale (>50% missing nodes) (default: false)",
                    false,
                ),
            ],
            returns: "Restored state with staleness report, resume_hints, next_focus_node_id, and next_suggested_tool",
            example: r#"{"agent_id": "jimi", "trail_id": "trail-abc123"}"#,
            next: &["timeline", "view", "activate"],
        },
        ToolDoc {
            name: "trail_merge",
            category: "Trail",
            glyph: GLYPH_PATH,
            one_liner: "Combine two or more investigation trails -- discover cross-connections",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("trail_ids", "Two or more trail IDs to merge", true),
                (
                    "label",
                    "Label for the merged trail (auto-generated if omitted)",
                    false,
                ),
            ],
            returns: "Merged trail with cross-connections, shared nodes, combined hypotheses",
            example: r#"{"agent_id": "jimi", "trail_ids": ["trail-abc", "trail-def"]}"#,
            next: &["trail_resume", "trail_list"],
        },
        ToolDoc {
            name: "trail_list",
            category: "Trail",
            glyph: GLYPH_PATH,
            one_liner: "List saved investigation trails with optional filters",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                (
                    "filter_agent_id",
                    "Filter to a specific agent's trails",
                    false,
                ),
                (
                    "filter_status",
                    "Filter by status: active, saved, archived, stale, merged",
                    false,
                ),
                ("filter_tags", "Filter by tags (any match)", false),
            ],
            returns: "Trails with labels, timestamps, node counts, status",
            example: r#"{"agent_id": "jimi", "filter_status": "active"}"#,
            next: &["trail_resume", "trail_save"],
        },
        // --- v0.4.0 new tools ---
        ToolDoc {
            name: "panoramic",
            category: "Panoramic",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Full graph health scan -- per-module risk from 7 signals",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("scope", "File path prefix filter", false),
                ("top_n", "Max modules to return (default: 50)", false),
            ],
            returns: "Per-module risk scores, critical alerts, overall health",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["impact", "antibody_scan"],
        },
        ToolDoc {
            name: "savings",
            category: "Efficiency",
            glyph: GLYPH_DIMENSION,
            one_liner: "Token economy -- how much m1nd saved vs grep/Read",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Session + global token/cost savings",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["report", "help"],
        },
        ToolDoc {
            name: "report",
            category: "Report",
            glyph: GLYPH_DIMENSION,
            one_liner: "Session intelligence report -- queries, savings, graph evolution",
            params: &[("agent_id", "Calling agent identifier", true)],
            returns: "Markdown report with query log, savings, graph evolution",
            example: r#"{"agent_id": "jimi"}"#,
            next: &["savings", "trail_save"],
        },
        ToolDoc {
            name: "audit",
            category: "Report",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Profile-aware one-call audit over topology, scans, verification, and git state",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("path", "Root path to audit", true),
                (
                    "profile",
                    "auto | quick | coordination | production | security | migration",
                    false,
                ),
                ("depth", "quick | surface | full", false),
                ("cross_verify", "Compare graph vs filesystem state", false),
                ("include_git", "Include git state and recent history", false),
                ("include_config", "Include selected dotfiles/config directories", false),
                ("external_refs", "Discover explicit external path references", false),
            ],
            returns: "Identity, inventory, topology, scan results, verification, health grades, recommendations",
            example: r#"{"agent_id": "jimi", "path": "/project", "profile": "auto"}"#,
            next: &["batch_view", "cross_verify", "scan_all"],
        },
        ToolDoc {
            name: "help",
            category: "Help",
            glyph: GLYPH_DIMENSION,
            one_liner: "Self-documenting tool reference with visual identity",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                (
                    "tool_name",
                    "Specific tool name (omit for full index)",
                    false,
                ),
            ],
            returns: "Formatted help text with params, examples, next steps, workflows, and state handoffs",
            example: r#"{"agent_id": "jimi", "tool_name": "activate"}"#,
            next: &["activate", "ingest"],
        },
        ToolDoc {
            name: "mission_start",
            category: "Mission",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Start a bounded agent mission with route, budget, and proof non-claims",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("repo", "Repository path this mission is scoped to", true),
                ("task", "Mission task in plain language", true),
                ("mode", "bug_hunt | review | refactor | docs_drift | architecture | release", false),
                ("budget", "short | normal | deep", false),
                ("risk", "low | medium | high", false),
            ],
            returns: "Mission id, route, trust projection, budget envelope, starter moves, and non-claims",
            example: r#"{"agent_id": "jimi", "repo": "/project", "task": "audit auth/session boundary", "mode": "review", "budget": "short", "risk": "medium"}"#,
            next: &["mission_event", "mission_next", "search", "audit"],
        },
        ToolDoc {
            name: "mission_event",
            category: "Mission",
            glyph: GLYPH_CONNECTION,
            one_liner: "Record one observed mission action with evidence class and digest",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("mission_id", "Mission id returned by mission_start", true),
                ("event", "Observed action object such as file_read, test_run, graph_query, dissent, or coverage_sweep", true),
            ],
            returns: "Event id, normalized event, evidence class, event count, digest, and non-claims",
            example: r#"{"agent_id": "jimi", "mission_id": "msn_123_jimi", "event": {"event": "file_read", "path": "src/auth.rs", "outcome": "supports claim"}}"#,
            next: &["mission_next", "mission_verify", "mission_handoff"],
        },
        ToolDoc {
            name: "mission_next",
            category: "Mission",
            glyph: GLYPH_PATH,
            one_liner: "Advance a mission by one move and emit do-not guardrails",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("mission_id", "Mission id returned by mission_start", true),
                ("last_event", "Optional event from the action just taken", false),
            ],
            returns: "One next move, phase, do-not list, budget use, and dissent protocol",
            example: r#"{"agent_id": "jimi", "mission_id": "msn_123_jimi", "last_event": {"event": "graph_query", "tool": "seek", "outcome": "inconclusive"}}"#,
            next: &["mission_event", "mission_verify", "mission_handoff", "mission_close"],
        },
        ToolDoc {
            name: "mission_verify",
            category: "Mission",
            glyph: GLYPH_CONNECTION,
            one_liner: "Check whether a mission claim has direct proof instead of graph-only evidence",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("mission_id", "Mission id returned by mission_start", true),
                ("claim", "Candidate conclusion to validate", true),
                ("evidence_refs", "Direct proof refs such as file_read:path:line or test_run:name", false),
                ("confidence", "Optional agent confidence before verification", false),
            ],
            returns: "Verdict, evidence grade, missing proof, and next required move",
            example: r#"{"agent_id": "jimi", "mission_id": "msn_123_jimi", "claim": "logout clears session", "evidence_refs": ["file_read:src/auth.rs:42"]}"#,
            next: &["mission_next", "mission_handoff", "mission_close"],
        },
        ToolDoc {
            name: "mission_handoff",
            category: "Mission",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Serialize a resumable mission packet for another agent or later session",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("mission_id", "Mission id returned by mission_start", true),
                ("summary", "Optional handoff summary", false),
                ("recipient_agent_id", "Optional recipient agent id", false),
                ("include_events", "Include full event stream in the packet", false),
            ],
            returns: "Handoff packet with verified claims, open hypotheses, dead paths, graph anchors, next move, digest, gaps, and non-claims",
            example: r#"{"agent_id": "jimi", "mission_id": "msn_123_jimi", "summary": "resume at direct proof", "recipient_agent_id": "reviewer"}"#,
            next: &["mission_next", "mission_close"],
        },
        ToolDoc {
            name: "mission_close",
            category: "Mission",
            glyph: GLYPH_STRUCTURE,
            one_liner: "Close a mission with a proof packet, gaps, rejected claims, and non-claims",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("mission_id", "Mission id returned by mission_start", true),
                ("summary", "Optional concise mission summary", false),
                ("non_claims", "Extra non-claims to preserve", false),
                ("gaps", "Known remaining gaps", false),
            ],
            returns: "Proof packet with verified claims, rejected claims, events, budget, gaps, and non-claims",
            example: r#"{"agent_id": "jimi", "mission_id": "msn_123_jimi", "summary": "verified logout boundary"}"#,
            next: &["report", "trail_save"],
        },
        ToolDoc {
            name: "view",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Fast file reader with line numbers — replaces View/cat/head/tail",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("file_path", "Absolute or workspace-relative path", true),
                ("offset", "Start line (0-based, default: 0)", false),
                ("limit", "Max lines to return (default: all)", false),
                (
                    "auto_ingest",
                    "Auto-ingest if file not in graph (default: true)",
                    false,
                ),
            ],
            returns: "File content with line numbers, total_lines, lines_returned",
            example: r#"{"file_path": "src/main.rs", "offset": 50, "limit": 20, "agent_id": "jimi"}"#,
            next: &["apply", "surgical_context_v2", "impact"],
        },
        ToolDoc {
            name: "batch_view",
            category: "Surgical",
            glyph: GLYPH_CONNECTION,
            one_liner: "Read multiple files or globs in one call with summaries and stable delimiters",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                ("files", "File paths and/or glob-like patterns", true),
                ("max_lines_per_file", "Maximum lines per file", false),
                ("summary_mode", "Add per-file summaries", false),
                ("auto_ingest", "Auto-ingest discovered files", false),
            ],
            returns: "Multi-file read payload with per-file summaries and truncation metadata",
            example: r#"{"agent_id": "jimi", "files": ["README.md", "src/**/*.rs"]}"#,
            next: &["coverage_session", "search"],
        },
        ToolDoc {
            name: "glob",
            category: "Foundation",
            glyph: GLYPH_SIGNAL,
            one_liner: "Graph-aware file glob — find files by pattern in the ingested graph",
            params: &[
                ("agent_id", "Calling agent identifier", true),
                (
                    "pattern",
                    "Glob pattern (e.g. **/*.rs, src/**/test_*.go)",
                    true,
                ),
                ("scope", "Root directory filter", false),
                ("top_k", "Max results (default: 100)", false),
                (
                    "sort",
                    "Sort order: path, modified, activation (default: path)",
                    false,
                ),
            ],
            returns: "List of matching files with path, extension, line_count, graph connections",
            example: r#"{"pattern": "**/*.rs", "scope": "src/", "agent_id": "jimi"}"#,
            next: &["search", "view", "surgical_context_v2"],
        },
    ]
}

/// Format the full help index.
pub fn format_help_index(show_temponizer: bool) -> String {
    let docs = tool_docs();
    let width = 60;
    let mut out = String::new();

    out.push_str(&gradient_top_border(width));
    out.push('\n');
    out.push_str(&format!(
        "{}{}  m1nd  {}-- neuro-symbolic code graph engine{}\n",
        ANSI_BOLD, ANSI_CYAN, ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "{}  {} SIGNAL  {} PATH  {} STRUCTURE  {} DIMENSION  {} CONNECTION{}\n",
        ANSI_DIM,
        GLYPH_SIGNAL,
        GLYPH_PATH,
        GLYPH_STRUCTURE,
        GLYPH_DIMENSION,
        GLYPH_CONNECTION,
        ANSI_RESET
    ));
    out.push_str(&gradient_bottom_border(width));
    out.push('\n');
    out.push('\n');

    // Group by category
    let categories = [
        ("Foundation", GLYPH_SIGNAL, ANSI_CYAN),
        ("Perspective", GLYPH_PATH, ANSI_MAGENTA),
        ("Lock", GLYPH_CONNECTION, ANSI_BLUE),
        ("Temporal", GLYPH_DIMENSION, ANSI_GOLD),
        ("Trail", GLYPH_PATH, ANSI_GOLD),
        ("Superpowers", GLYPH_STRUCTURE, ANSI_GOLD),
        ("Extended", GLYPH_DIMENSION, ANSI_MAGENTA),
        ("Surgical", GLYPH_CONNECTION, ANSI_GREEN),
        ("Panoramic", GLYPH_STRUCTURE, ANSI_RED),
        ("Efficiency", GLYPH_DIMENSION, ANSI_GREEN),
        ("Report", GLYPH_DIMENSION, ANSI_BLUE),
        ("Help", GLYPH_DIMENSION, ANSI_CYAN),
    ];

    for (cat_name, glyph, color) in &categories {
        let cat_tools: Vec<&ToolDoc> = docs.iter().filter(|d| d.category == *cat_name).collect();
        if cat_tools.is_empty() {
            continue;
        }

        out.push_str(&format!(
            "{}{} {} ({}):{}\n",
            color,
            glyph,
            cat_name,
            cat_tools.len(),
            ANSI_RESET
        ));
        for doc in cat_tools {
            let short_name = doc.name.strip_prefix("").unwrap_or(doc.name);
            out.push_str(&format!(
                "  {}{}  {}{}{}\n",
                ANSI_BOLD, short_name, ANSI_DIM, doc.one_liner, ANSI_RESET
            ));
        }
        out.push('\n');
    }

    out.push_str(&format!(
        "{}use help(tool_name=\"activate\") for detailed help on any tool{}\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "{}decision guide: search=text, glob=filenames, seek=intent, trace=errors, validate_plan=edit risk, surgical_context_v2=connected edit prep{}\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "{}common errors should be treated as reroute hints: read the hint, example, and next-step guidance before retrying.{}\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!("{}tip: if you're unsure which tool to use, describe what you need — help can suggest the right one.{}\n", ANSI_DIM, ANSI_RESET));
    if show_temponizer {
        out.push('\n');
        out.push_str(&format!(
            "{}⚡ TEMPONIZER:{} You suffer from TIB — you estimate in human-time but execute 15-60× faster.\n",
            ANSI_GOLD, ANSI_RESET
        ));
        out.push_str(&format!(
            "{}  corrected = estimate ÷ 20 (floor 1 min). Fill recovered time with MORE deliverables, not padding.{}\n",
            ANSI_DIM, ANSI_RESET
        ));
        out.push_str(&format!(
            "{}  Full spec: .m1nd/boot/temponizer.json{}\n",
            ANSI_DIM, ANSI_RESET
        ));
    }
    out
}

/// Format detailed help for a single tool.
pub fn format_tool_help(doc: &ToolDoc) -> String {
    let width = 60;
    let mut out = String::new();

    out.push_str(&gradient_top_border(width));
    out.push('\n');

    let short_name = doc.name.strip_prefix("").unwrap_or(doc.name);
    out.push_str(&format!(
        "{}{} {}  {}  m1nd.{}{}\n",
        ANSI_CYAN,
        doc.glyph,
        doc.category.to_uppercase(),
        ANSI_BOLD,
        short_name,
        ANSI_RESET
    ));
    out.push_str(&format!("{}{}{}\n\n", ANSI_DIM, doc.one_liner, ANSI_RESET));

    // Params section
    out.push_str(&format!("{}\u{2338} PARAMS{}\n", ANSI_GOLD, ANSI_RESET)); // ⌸
    for (i, (name, desc, required)) in doc.params.iter().enumerate() {
        let connector = if i == doc.params.len() - 1 {
            "\u{2514}\u{2500}"
        } else {
            "\u{251C}\u{2500}"
        };
        let req_mark = if *required {
            format!("{}*{}", ANSI_RED, ANSI_RESET)
        } else {
            String::new()
        };
        out.push_str(&format!(
            "  {} {}{}{} {}{}{}\n",
            connector, ANSI_BOLD, name, req_mark, ANSI_DIM, desc, ANSI_RESET
        ));
    }
    out.push('\n');

    // Returns section
    out.push_str(&format!("{}\u{234D} RETURNS{}\n", ANSI_GREEN, ANSI_RESET)); // ⍍
    out.push_str(&format!("  {}{}{}\n\n", ANSI_DIM, doc.returns, ANSI_RESET));

    // When to use section
    out.push_str(&format!(
        "{}\u{25B7} WHEN TO USE{}\n",
        ANSI_CYAN, ANSI_RESET
    ));
    for line in when_to_use(doc.name) {
        out.push_str(&format!("  {}- {}{}\n", ANSI_DIM, line, ANSI_RESET));
    }
    out.push('\n');

    // Avoid when section
    out.push_str(&format!("{}\u{26A0} AVOID WHEN{}\n", ANSI_RED, ANSI_RESET));
    for line in avoid_when(doc.name) {
        out.push_str(&format!("  {}- {}{}\n", ANSI_DIM, line, ANSI_RESET));
    }
    out.push('\n');

    // Example section
    out.push_str(&format!("{}\u{233C} EXAMPLE{}\n", ANSI_MAGENTA, ANSI_RESET)); // ⌼
    out.push_str(&format!("  {}{}{}\n\n", ANSI_DIM, doc.example, ANSI_RESET));

    let notes = agent_notes(doc.name);
    if !notes.is_empty() {
        out.push_str(&format!(
            "{}\u{2699} AGENT NOTES{}\n",
            ANSI_GOLD, ANSI_RESET
        ));
        for line in notes {
            out.push_str(&format!("  {}- {}{}\n", ANSI_DIM, line, ANSI_RESET));
        }
        out.push('\n');
    }

    let recovery = error_recovery_notes(doc.name);
    if !recovery.is_empty() {
        out.push_str(&format!(
            "{}\u{21BB} ERROR RECOVERY{}\n",
            ANSI_RED, ANSI_RESET
        ));
        for line in recovery {
            out.push_str(&format!("  {}- {}{}\n", ANSI_DIM, line, ANSI_RESET));
        }
        out.push('\n');
    }

    let bench = benchmark_notes(doc.name);
    if !bench.is_empty() {
        out.push_str(&format!(
            "{}\u{25C8} BENCHMARK TRUTH{}\n",
            ANSI_MAGENTA, ANSI_RESET
        ));
        for line in bench {
            out.push_str(&format!("  {}- {}{}\n", ANSI_DIM, line, ANSI_RESET));
        }
        out.push('\n');
    }

    let flows = workflow_patterns(doc.name);
    if !flows.is_empty() {
        out.push_str(&format!("{}\u{21AA} WORKFLOWS{}\n", ANSI_BLUE, ANSI_RESET));
        for line in flows {
            out.push_str(&format!("  {}- {}{}\n", ANSI_DIM, line, ANSI_RESET));
        }
        out.push('\n');
    }

    let handoffs = state_handoffs(doc.name);
    if !handoffs.is_empty() {
        out.push_str(&format!(
            "{}\u{21C4} STATE HANDOFF{}\n",
            ANSI_GREEN, ANSI_RESET
        ));
        for line in handoffs {
            out.push_str(&format!("  {}- {}{}\n", ANSI_DIM, line, ANSI_RESET));
        }
        out.push('\n');
    }

    // Next section
    out.push_str(&format!("{}\u{2350} NEXT{}\n", ANSI_CYAN, ANSI_RESET)); // ⍐
    for next in doc.next {
        out.push_str(&format!(
            "  {} {}{}{}\n",
            ANSI_CYAN, ANSI_BOLD, next, ANSI_RESET
        ));
    }
    out.push('\n');

    out.push_str(&gradient_bottom_border(width));
    out.push('\n');
    out
}

/// Format the "about" help -- m1nd's philosophy and identity.
pub fn format_about() -> String {
    let width = 72;
    let mut out = String::new();

    out.push_str(&gradient_top_border(width));
    out.push('\n');
    out.push_str(&format!("{}{}  m1nd{}\n", ANSI_BOLD, ANSI_CYAN, ANSI_RESET));
    out.push_str(&format!(
        "{}  operational intelligence for coding agents{}\n\n",
        ANSI_DIM, ANSI_RESET
    ));

    out.push_str(&format!(
        "{}  A local intelligence layer for coding agents.{}\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "{}  It turns code, docs, history, runtime signals, and graph-native knowledge{}\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "{}  into a local system an agent can reason over before, during, and after change.{}\n\n",
        ANSI_DIM, ANSI_RESET
    ));

    out.push_str(&format!(
        "{}  WHAT THAT INTELLIGENCE COVERS{}\n",
        ANSI_BOLD, ANSI_RESET
    ));
    out.push_str(&format!(
        "  {}- structure:{} retrieval, neighborhoods, routes, type flow, layers\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "  {}- change:{} blast radius, co-change, validation, edit prep, execution\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "  {}- docs:{} universal ingest, L1GHT, bindings, drift, provider health\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "  {}- operations:{} audits, verification, daemons, alerts, overlays, reports\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "  {}- continuity:{} perspectives, trails, coverage, boot memory, handoffs\n\n",
        ANSI_DIM, ANSI_RESET
    ));

    out.push_str(&format!("{}  RUNTIME{}\n", ANSI_BOLD, ANSI_RESET));
    out.push_str(&format!("  {}- local execution{}\n", ANSI_DIM, ANSI_RESET));
    out.push_str(&format!("  {}- MCP over stdio{}\n", ANSI_DIM, ANSI_RESET));
    out.push_str(&format!(
        "  {}- optional HTTP/UI surface in the default build{}\n\n",
        ANSI_DIM, ANSI_RESET
    ));

    out.push_str(&format!(
        "{}  call help(tool_name=\"activate\") for exact tool doctrine{}\n",
        ANSI_DIM, ANSI_RESET
    ));
    out.push_str(&format!(
        "{}  call help(stage=\"plan\", intent=\"validate a risky change\") for routing{}\n",
        ANSI_DIM, ANSI_RESET
    ));

    out.push_str(&gradient_bottom_border(width));
    out.push('\n');
    out
}

/// Find the closest matching tool name for "did you mean?" suggestions.
pub fn find_similar_tools(query: &str) -> Vec<String> {
    let docs = tool_docs();
    let query_lower = query.to_lowercase();
    let query_lower = query_lower.strip_prefix("").unwrap_or(&query_lower);

    let mut matches: Vec<(&str, usize)> = docs
        .iter()
        .map(|d| {
            let name = d.name.strip_prefix("").unwrap_or(d.name);
            let dist = levenshtein_distance(query_lower, &name.to_lowercase());
            (d.name, dist)
        })
        .filter(|(_, dist)| *dist <= 4)
        .collect();

    matches.sort_by_key(|(_, dist)| *dist);
    matches
        .into_iter()
        .take(3)
        .map(|(name, _)| name.to_string())
        .collect()
}

fn levenshtein_distance(a: &str, b: &str) -> usize {
    let a_bytes = a.as_bytes();
    let b_bytes = b.as_bytes();
    let a_len = a_bytes.len();
    let b_len = b_bytes.len();
    let mut dp = vec![vec![0usize; b_len + 1]; a_len + 1];

    for (i, row) in dp.iter_mut().enumerate().take(a_len + 1) {
        row[0] = i;
    }
    for (j, val) in dp[0].iter_mut().enumerate().take(b_len + 1) {
        *val = j;
    }

    for i in 1..=a_len {
        for j in 1..=b_len {
            let cost = if a_bytes[i - 1] == b_bytes[j - 1] {
                0
            } else {
                1
            };
            dp[i][j] = (dp[i - 1][j] + 1)
                .min(dp[i][j - 1] + 1)
                .min(dp[i - 1][j - 1] + cost);
        }
    }
    dp[a_len][b_len]
}
