{
  "manifestVersion": 1,
  "tools": {
    "log10x_siem_connector": {
      "title": "Emit SIEM connector for an offload bucket",
      "description": "Generate the customer-applied SIEM-side connector config (Datadog Forwarder Lambda, or the Splunk Add-on for AWS SQS-based S3 input) that makes a SIEM pull log10x's offload output from the customer's own S3 bucket. Call this when the user has offloaded a pattern's data to S3 (the offload action / a log10x_offload_add destination) and asks how to get Datadog or Splunk to ingest it, e.g. 'ship my offload bucket to Splunk' or 'wire Datadog to read these logs'. log10x deliberately never pushes to a SIEM (vendor-driven re-ingest collides with Datadog Rehydration billing, Splunk HEC permissions, and Elastic _bulk limits); it lands NDJSON in the customer bucket and the SIEM pulls, and this tool emits exactly that pull-side connector. Args: siem (required: datadog / splunk / both), bucket (required: the offload bucket), account_id (required), region (default us-east-1), prefix (optional, default app/), plus per-SIEM options (datadog_forwarder_arn, sqs_queue_name, sourcetype, index). Returns, per target: the discovery model, ordered setup steps, paste-ready terraform (an SNS fan-out plus IAM, and for Splunk the SQS queue and the S3-to-SNS-to-SQS notification), the SIEM-native config (the Splunk inputs.conf aws_sqs_based_s3 stanza), and verified caveats. Recipes are matched to log10x's actual offload output (uncompressed NDJSON, one event per line, Hive-partitioned keys) and encode the key gotcha: the offload bucket usually already notifies the 10x indexer's SQS, and S3 allows only one notification config per overlapping prefix, so both recipes fan out via SNS rather than a second raw bucket notification. Honest caveats are surfaced: Datadog is logs-only (use log10x_backfill_metric for per-pattern metrics), and the Splunk SQS-based input collects only objects created after setup (backfill older data with a Generic S3 input). Read-only: it generates config and does not create AWS resources or mutate any env document.",
      "annotations": {
        "title": "Emit SIEM connector for an offload bucket",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_start": {
      "title": "Log10x orientation",
      "description": "CALL THIS FIRST whenever the user asks any open-ended cost question, says save X%, asks where do I start, what should I do, how can you help — before any other tool. Detects the customer's tier (Dev CLI / Reporter / Receiver / Retriever) via three live probes (gateway auth, Reporter metric counts, Retriever resolution), detects the SIEM, and returns a structured orientation envelope with three compliance levers the agent MUST obey: `must_render_verbatim` (markdown to surface to the user as-is, no summarising), `must_ask_user` (a numbered question the agent MUST ask before any follow-up tool call), and `forbidden_next_actions` (tool names the agent MUST NOT call until the user has picked an option). Also returns a 5-phase journey (Visibility → Attribution → Mitigation → Forensic → Commitment) showing where the customer is, an action menu gated by available capabilities (compact_installable, tier_down_available, offload_ready, forensic_query_available), and the resolved tier. The tool is read-only, takes an optional `intent_hint` (cost / forensic / install / orient), and is safe to call on any boot state — including when no env is configured yet (skips gateway/Reporter probes and treats the customer as Dev CLI tier). Accepts siem_lens (what-if destination): keeps the real volumes, prices + gates for that destination at list rates, and stamps siem_actual vs siem_lens in the envelope.",
      "annotations": {
        "title": "Log10x orientation",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "orient"
    },
    "log10x_cost_options": {
      "title": "Cost reduction options",
      "description": "CALL THIS after the user picks 'show me what cutting costs would look like' from log10x_start. At Receiver/Retriever tier returns the 6-mode outcome-first menu (drop / sample / compact / tier_down / offload / observe_only), each gated by the customer's detected capabilities (receiver tier, SIEM type, offload bucket). At Reporter-only or Dev tier, collapses to 2 entries: observe_only + install_receiver (with prose explaining that the full 6-mode menu requires the Receiver in-path). All non-observe modes route to log10x_explain_mode. The envelope carries must_render_verbatim (show to user as-is), must_ask_user (numbered question), and forbidden_next_actions (do not call estimate_savings, configure_engine, or pattern_mitigate until the user picks). Accepts siem_lens (what-if destination): keeps the real volumes, prices + gates for that destination at list rates, and stamps siem_actual vs siem_lens in the envelope.",
      "annotations": {
        "title": "Cost reduction options",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_explain_mode": {
      "title": "Explain enforcement mode",
      "description": "CALL THIS AFTER log10x_cost_options when the user picks a mode. Explains the chosen enforcement mode (drop / sample / compact / tier_down / offload / observe_only) in service-level plain language, with dollar math when byte metrics are available. Returns must_render_verbatim (plain-text three-section card, no markdown), must_ask_user (Apply or Preview choice), and forbidden_next_actions (locks apply tools and log10x_preview_filter until the user picks). routes_to.apply routes all non-observe modes to log10x_configure_engine; observe_only has routes_to.apply === null (no enforcement step). routes_to.preview routes to log10x_preview_filter with { service, mode }.",
      "annotations": {
        "title": "Explain enforcement mode",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_preview_filter": {
      "title": "Preview filter patterns",
      "description": "CALL THIS AFTER log10x_explain_mode when the user picks Preview. Shows the list of patterns that would be affected by applying a given enforcement mode to a service, before any action is taken. Returns a fixed-width plain-text table (no markdown pipes) with columns: rank, descriptor, volume, %, service, severity, first seen, trend sparkline. Writes a CSV to /tmp/log10x-preview-<mode>-<service>.csv. must_ask_user offers: drill into pattern #N (calls log10x_pattern_detail), Apply, or go back to pick a different mode. forbidden_next_actions locks log10x_configure_engine, log10x_pattern_mitigate, and log10x_advise_retriever until the user commits.",
      "annotations": {
        "title": "Preview filter patterns",
        "readOnlyHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_pattern_detail": {
      "title": "Pattern detail",
      "description": "CALL THIS AFTER log10x_preview_filter when the user drills into a specific pattern by number. Returns a full single-pattern view: 24h line chart (up to 12 rows, 72 chars wide), ASCII horizontal bar chart for cross-service byte distribution (top 8 services), severity breakdown, and up to 5 sample events truncated to 120 chars each. Requires pattern_hash (tenx_hash from preview_filter.data.patterns[].tenx_hash). must_ask_user: Back to preview list, or Apply with this in the picture. actions[]: log10x_preview_filter (back) and log10x_configure_engine (apply).",
      "annotations": {
        "title": "Pattern detail",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_event_lookup": {
      "title": "Event lookup",
      "description": "Resolve a raw log line or pattern name to its stable pattern identity (the hash of its representing-token subset), then return byte volume + share per service (with cost overlay when $/GB is set), before→after delta, first-seen timestamp within the observation window, an AI classification (error/debug/info) with a recommended action (filter/keep/reduce), and the current offload disposition (pass / sample / compact / drop) read from the Reporter `routeState` label. **Call this first** whenever a user pastes a SINGLE log line and asks \"what is this\", \"is this new\", \"is this safe to drop\", or \"is this being dropped / offloaded\". The lookup is structural, not byte-exact — different timestamps/request IDs/user IDs on the same underlying pattern resolve to the same identity. If no match is returned, say so honestly. Use log10x_resolve_batch instead when the user pastes MULTIPLE events, a SIEM dump, or a batch to triage.",
      "annotations": {
        "title": "Event lookup",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "identify"
    },
    "log10x_pattern_examples": {
      "title": "Pattern examples",
      "description": "Pull recent live events for a pattern from the customer's log analyzer (Splunk, Datadog, Elasticsearch, CloudWatch) and return them grouped by templateHash with template-extracted slot values per match. **Bounded to a 24-hour window** (live log analyzer retention); for older history use `log10x_retriever_query`. Input is either a Symbol Message (pattern name like `Payment_Gateway_Timeout`) or a pasted raw log line; pasted lines resolve via the same templater path as `log10x_resolve_batch`. The tool runs a SIEM phrase-search probe, runs returned events through the local templater, groups by templateHash (one bucket per template variant of the pattern; the stable pattern identity is the tenx_hash carried on each bucket), applies a content-token Jaccard similarity threshold (≥0.85) to discriminate the matching pattern's events from look-alikes, and returns the top buckets by event count. Output is honest about partial extractions: per-bucket templateHash labels, recall counts, and explicit `parseFailed` markers when slot extraction fails. Multi-line group templates report head-line-only with an explicit warning. **Designed as an orchestration primitive** called by `log10x_investigate` when the chain needs concrete event evidence after a metric-tier identification. Direct user-facing use is fine but rare; prefer `log10x_event_lookup` + `log10x_pattern_trend` for single-line inspection.",
      "annotations": {
        "title": "Pattern examples",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "identify"
    },
    "log10x_product_qa": {
      "title": "Product Q&A from shipped docs",
      "description": "Answer Log10x product questions from the docs corpus that ships inside the MCP build (chunked + indexed at install time). Use whenever the user asks a factual product question — \"what is the Receiver\", \"how is pattern_hash computed\", \"what data leaves my network\", \"does the Reporter modify data\" — instead of answering from training data. Inputs: `topic` for an exact docs-slug lookup (e.g. `faq/security/data-protection`), or `query` for natural-language TF-IDF search across the corpus. `category` narrows search to one of faq / apps / engine / api / config / manage. `max_results` caps the result count (default 3). Output is a standard chassis envelope with `found`, ranked `results` (each carrying matched chunks + canonical_url), and `similar_topics` as a did-you-mean fallback. Always cite `canonical_url` when surfacing an answer to the user. The corpus is shipped from `config/mksite/docs` at build time; in development the loader also honors `LOG10X_PRODUCT_KB_PATH`.",
      "annotations": {
        "title": "Product Q&A from shipped docs",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "identify"
    },
    "log10x_savings": {
      "title": "Pipeline savings",
      "description": "Show pipeline savings — what percent of bytes the receiver (filtering + compaction) and retriever (indexing) are removing, with a dollar overlay when an analyzer $/GB rate is set (account profile list price, or per-call `effective_ingest_per_gb` override). Without a rate, the headline is percent-and-bytes only — never a fabricated $1/GB number. Use for \"how much are we saving\", \"pipeline ROI\", or \"what is the Log10x stack worth financially\". Accepts siem_lens (what-if destination): keeps the real volumes, prices + gates for that destination at list rates, and stamps siem_actual vs siem_lens in the envelope.",
      "annotations": {
        "title": "Pipeline savings",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_pattern_trend": {
      "title": "Pattern trend",
      "description": "Return the volume history for a single pattern over a chosen window (e.g. 1h, 24h, 7d, 30d), with a sparkline and spike detection — ranked by byte volume (with cost overlay when $/GB is set). **Call this after log10x_event_lookup** when the user asks \"is this getting worse\", \"has it been louder before\", \"when did it start\", or wants temporal context on a pattern surfaced in an earlier step. Always state the observation window explicitly in the reply — \"flat at 2/h for the last 6 months of observation, spiked at 13:58 today\" — and never claim history older than the window. Pass `include` to select the cohort: `admitted` (default), `dropped` (offloaded-only trend — useful for \"is the receiver dropping more of this lately\"), or `both` (total ingest). The envelope reports which cohort the series represents so the agent never conflates admitted-only with total volume.",
      "annotations": {
        "title": "Pattern trend",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "identify"
    },
    "log10x_services": {
      "title": "Services",
      "description": "[FRESH-SESSION ROUTING: if this is the user first cost question of the session, call log10x_start first instead — it returns the orientation menu the user needs before any per-tool action.] List every service the Log10x pipeline is watching, ranked by byte volume (with cost overlay when $/GB is set) plus per-service share of total AND the four action-axis columns (bytes_passed / bytes_offloaded / bytes_compacted / bytes_dropped) derived by joining routeState=\"drop\" events against the cap-CSV. Pass `exception_services` to mark customer-flagged services as current_mode=pass — their next_action points at log10x_pattern_mitigate instead of log10x_configure_engine. Call first on open-ended cost questions, before drilling into a specific service.",
      "annotations": {
        "title": "Services",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_overflow_contents": {
      "title": "Overflow contents",
      "description": "The contents view of the customer-owned offload S3 bucket — per-pattern bytes, event count, time-first-seen, time-last-seen, and growth rate. Filtered to action=offload via the cap-CSV the MCP wrote (`drop` patterns are NOT in S3; `compact` and `tier_down` route elsewhere). Call this as the maintenance-loop review: \"what's accumulating in my overflow queue?\" Routes the agent to log10x_retriever_query for rehydration when an incident or audit needs the data back in the SIEM.",
      "annotations": {
        "title": "Overflow contents",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_dependency_check": {
      "title": "Dependency check command",
      "description": "Given a pattern identity, generate commands to scan the user's SIEM/observability stack (Datadog monitors, Splunk saved searches, Grafana dashboards, Prometheus alert rules) for anything that depends on that pattern. **Call this before any mute, drop, or source-code deletion** — deleting a log line that feeds a live alert silently breaks the alert. Also call when a developer asks \"am I allowed to delete this log.info() call\" or \"what references this pattern\". This is the blast-radius check that turns a risky refactor into a reviewed one.",
      "annotations": {
        "title": "Dependency check command",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "drop"
    },
    "log10x_discover_labels": {
      "title": "Discover labels",
      "description": "List the labels Log10x metrics can be filtered or grouped by. Call at the start of a session, or before calling any tool that takes a label/filter argument — stops the model from guessing label names like \"namespace\" when the real name is \"k8s_namespace\". Pass a label name to get its distinct values.",
      "annotations": {
        "title": "Discover labels",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_configure_env": {
      "title": "Configure metrics env",
      "description": "Register a metrics backend with the MCP and persist it to `~/.log10x/envs.json`. **Use this when the user's MCP is not yet configured** and a metric tool has returned a `not_configured` response. The flow: ask the user where their 10x engine ships metrics (log10x hosted, self-hosted Prometheus, Mimir, Cortex, AMP, Datadog, Grafana Cloud Prom, or GCP Managed Prom), collect the URL + auth, then call this tool with the corresponding `metricsBackend` config. The tool runs a 4-step live-backend validation (reachable, authenticated, engine metrics present, expected labels present) and refuses to persist if validation fails — the user fixes the underlying issue and re-runs. Credentials should be wrapped in `${VAR_NAME}` references (resolved from env) rather than passed as literals; the tool refuses literals that look like real secrets.",
      "annotations": {
        "title": "Configure metrics env",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_set_gitops_repo": {
      "title": "Set gitops repo on env",
      "description": "Write the `gitops.repo` field (owner/name format) to an env entry in `~/.log10x/envs.json` so `log10x_configure_engine` can author cap-CSV PRs against the right GitHub repo. **Call this when `log10x_configure_engine` returns error_type=config_missing with a gitops-not-resolved hint.** Args: `gitops_repo` (required, owner/repo format e.g. `acme-corp/platform-config`), `environment` (optional nickname — omit to update the default env), `gitops_lookup_path` (optional override for cap-CSV path inside the repo), `confirm: \"set-now\"` (required safety gate). After writing, the MCP server must restart to pick up the change — run `log10x_dev_restart` or restart manually. Does NOT require metricsBackend credentials (unlike `log10x_configure_env`, which validates the live backend). Use this for gitops-only field updates on an already-configured env.",
      "annotations": {
        "title": "Set gitops repo on env",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_dest_set": {
      "title": "Set SIEM destination on env",
      "description": "Update the SIEM destination block (siem_vendor, region, log_group_prefix, ingest_url) on a stored env-config document at `~/.log10x/envs/<env_id>.json`. **Call this when** the customer is switching SIEMs, moving regions, repointing the log_group_prefix, or onboarding a new self-hosted ingest_url. Args: `env_id` (required — env_id UUID or nickname), `siem_vendor` (required — one of splunk / datadog / elasticsearch / clickhouse / cloudwatch / azure-monitor / gcp-logging / sumo / other), `region` / `log_group_prefix` / `ingest_url` (all optional). The tool reads the doc, swaps the destination block, re-validates against the canonical zod schema, and writes the updated doc atomically. Idempotent — a no-op edit returns ok:true with empty changes. Pairs naturally with `log10x_env_validate` to confirm the new destination passes cross-field sanity (region required for cloudwatch/datadog/azure-monitor/gcp-logging; ingest_url shape sanity for splunk).",
      "annotations": {
        "title": "Set SIEM destination on env",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_env_validate": {
      "title": "Validate env config doc",
      "description": "Run schema validation + cross-field sanity checks on a stored env-config document at `~/.log10x/envs/<env_id>.json`. **Call this** after any edit to the env doc (via `log10x_dest_set` / hand-edit / restore) or pre-flight before downstream tools that need a coherent config (commitment_report, configure_engine, offload-recipe emitters). Args: `env_id` (required — env_id UUID or nickname). Returns the canonical zod schema parse result PLUS findings across: destination.region required for vendors that need it (cloudwatch / datadog / azure-monitor / gcp-logging); ingest_url shape sanity (http(s):// prefix, splunk /services/collector suffix); streamer.url / retriever.url shape; cluster cloud type vs offload destination type alignment (eks↔s3, gke↔gcs, aks↔azure_blob); at-least-one active offload destination; SIEM region vs offload destination region (cross-region egress warning). Each finding carries severity (error / warning / info) and a remediation recommendation. Errors block downstream actions; warnings/info surface for the user.",
      "annotations": {
        "title": "Validate env config doc",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_env_diff_vs_envvars": {
      "title": "Diff env doc vs LOG10X_* env vars",
      "description": "Compare the stored env-config document against the `LOG10X_*` environment variables the env-var bridge would have produced, and report per-field disagreements with remediation recommendations. **Call this when** the user says \"but I set the env var\" or downstream tools report a value the user thinks they overrode — the on-prem store wins over env vars per resolver precedence, and silent-override is the most common boot-time surprise. Args: `env_id` (required — env_id UUID or nickname). For each disagreeing field (env_id, nickname, cluster.*, destination.*, streamer.*, retriever.*, offload_destinations[0].*), returns `{ field, stored, envvar, recommendation }`. The recommendation tells the user to either unset the LOG10X_* env var (preferred — on-prem store is the source of truth) or to update the stored doc via the matching setter (log10x_dest_set for destination, log10x_set_gitops_repo for gitops). Pure-on-prem-store configs (no LOG10X_* env vars set) return ok:true with an empty diff and a note that no ambiguity is possible.",
      "annotations": {
        "title": "Diff env doc vs LOG10X_* env vars",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_offload_add": {
      "title": "Add offload destination to env",
      "description": "Append a new entry to an env-config document's `offload_destinations[]` array. **Call this when** the customer is provisioning a new bucket for the Receiver to drain the routeState=\"drop\" slice into — a brand-new offload target, a regional bucket alongside an existing primary, or a second destination during a bucket-rotation. Args: `env_id` (required — env_id UUID or nickname), `nickname` (required — must be unique within the env's offload_destinations list), `type` (required — one of s3 / gcs / azure_blob / file), `bucket` / `storage_account` / `prefix` / `region` / `auth` / `note` (optional, type-specific; `azure_blob` takes the blob container in `bucket` and requires `storage_account`, and the write is refused without it because the read path addresses the container as `<storage_account>.blob.core.windows.net/<bucket>`), `status` (optional, defaults to `active`). Resolves the env-config document via the store chain (k8s ConfigMap → AWS SSM → GCP Secret Manager → Azure App Config → local file) and writes the mutated document back to the same store. Refuses on nickname collision so the operator can address destinations by label. Multi-target is the documented use case — the schema allows multiple `active` destinations so a legacy bucket can be drained while a new one is primary. Pairs with `log10x_env_validate` to confirm cluster-type ↔ destination-type alignment (eks↔s3, gke↔gcs, aks↔azure_blob) after the write.",
      "annotations": {
        "title": "Add offload destination to env",
        "readOnlyHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_offload_archive": {
      "title": "Archive offload destination on env",
      "description": "Flip one offload destination's `status` to `archived` on an env-config document and stamp `archived_at`. The entry is NOT removed from the list — it stays as a historical reference (e.g. for retroactive Retriever scans of the legacy bucket). **Call this when** the customer is rotating out a bucket and wants the Receiver to stop writing to it, but keep the bucket's existence in the document so audits and stale-pointer fetches still resolve. Args: `env_id` (required — env_id UUID or nickname), `nickname` (required — must match an existing destination exactly), `archived_at` (optional ISO-8601 timestamp, defaults to now), `note` (optional free-form note appended to the destination). **REFUSES when the target is the only active destination on the env** — the Receiver requires at least one active offload destination to route the dropped slice to, and silently stranding offload traffic is the failure mode this guard prevents. The error envelope names the non-active destinations so the agent can advise the user to activate one first (call `log10x_offload_add` or hand-edit a `draining`/`failed` entry back to `active`).",
      "annotations": {
        "title": "Archive offload destination on env",
        "readOnlyHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_retriever_register": {
      "title": "Register Retriever on env",
      "description": "Attach the Retriever endpoint + queue coordinates to an existing environment-config document. **Call this after `log10x_advise_retriever` has produced the install plan and the user has deployed the Retriever.** Args: `env_id` (required — must already exist in the env-config store), `url` (required — Retriever query endpoint), `input_bucket` (required — S3 archive bucket), `query_queues` (required — the four SQS queues: `index`, `subquery`, `stream`, `query`), `input_prefix` (optional), `query_log_group` (optional CloudWatch log group), `helm_release` (optional `{name, namespace, chart_version?}`). Refuses with `env_not_found` if the env does not exist — the agent should call `log10x_env_register` first. Idempotent: re-running with the same env_id replaces the retriever block in place and refreshes `updated_at`. After success, follow up with `log10x_retriever_probe` to verify the endpoint is reachable.",
      "annotations": {
        "title": "Register Retriever on env",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_top_patterns": {
      "title": "Top patterns",
      "description": "Return the top N log patterns ranked by byte volume (with cost overlay when $/GB is set), optionally with a delta column vs a `comparison_window` baseline (week-over-week / day-over-day / 1h-vs-prior-1h). Use for \"what is expensive right now\", \"what are the noisy patterns in <service> this hour\", \"give me a snapshot of my loudest events\", \"what changed this week\", \"did the deploy add cost\". Can be scoped by service label. `timeRange` accepts free-form `<n><m|h|d>` durations (e.g., `48h`, `3d`, `15m`) — there's no enum snap. Pass `comparison_window` to get a per-row delta column; omit for current-rank-only. Pass `include` to choose which cohort to rank: `admitted` (default — what the receiver let through), `dropped` (the offloaded / overflow cohort alone), or `both` (total ingest pre-receiver). Use `dropped` for \"what is the receiver throwing away\" and `both` for an apples-to-apples pre/post comparison. Accepts siem_lens (what-if destination): keeps the real volumes, prices + gates for that destination at list rates, and stamps siem_actual vs siem_lens in the envelope. REQUIRES Reporter-tier metrics. Before anything is deployed, the POC tools answer the same question from your own logs.",
      "annotations": {
        "title": "Top patterns",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_pattern_diff": {
      "title": "Pattern diff (set diff across a time boundary)",
      "description": "Set diff of patterns across a time boundary. Compares pattern presence in two windows (the most recent `timeRange` window as \"after\" vs the immediately preceding `timeRange` window as \"before\") and returns four sets: `new` (present after, absent before), `retired` (present before, absent after), `persistent` (present in both), and `re_emerged` (flagged as new but actually existed prior to the before-window — the \"the bug we thought we fixed is back\" case, derived by checking first_seen against the before-window boundary). Plus `co_emergence_clusters`: groups of 3+ patterns whose first_seen timestamps cluster within ±co_emergence_window_seconds (default 60s). That cluster is a deploy fingerprint — no CI/CD integration required; the agent can then query the customer's deploy system externally with the cluster timestamp. This tool is coherent ONLY because log10x pattern_hash is stable across queries; competitors that re-cluster per query (Datadog Log Patterns, Cribl, Edge Delta) can't answer the diff question because their \"patterns\" on either side of the boundary aren't comparable. Use for \"what changed since last deploy\", \"which patterns disappeared this week\", \"did the rollback bring back the old errors\", or paired with log10x_pattern_examples on a flagged hash to see slot distribution. Scoping: `service` and `severity` narrow the universe; `limit` caps rows per category. Returns structured envelope under `data.diff` with the four sets plus an `incidents` block when co_emergence clusters are detected.",
      "annotations": {
        "title": "Pattern diff (set diff across a time boundary)",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_whats_changing": {
      "title": "What's changing — patterns ranked by delta vs baseline",
      "description": "Patterns ranked by delta vs a baseline window — the \"what grew (or shrank) the most since X\" question. Distinct from `log10x_top_patterns` which ranks by current cost; this tool ranks by delta and applies gates (`min_delta_usd`, `min_delta_contribution_pct`) that drop noise-level changes. `comparison_window: \"auto\"` (default) averages three offsets (1×, 2×, 3× the timeRange) for noise smoothing; specific offsets like `\"7d\"` compare to a single anchor — e.g. `{timeRange: \"1d\", comparison_window: \"1d\"}` is today vs yesterday (deploy-delta), `{timeRange: \"7d\", comparison_window: \"7d\"}` is this week vs last week. Brand-new patterns (no baseline samples) are EXCLUDED — they go to `log10x_whats_new` for clean separation of stories. Restores the capability of the deleted log10x_cost_drivers tool (commit 27dce7d, chk-15) using the modern StructuredOutput envelope and the shared baseline machinery in `top-volume-extras.ts` / gates in `lib/gates.ts`. Use for \"what grew most this week\", \"which patterns regressed after the deploy\", \"what's driving cost up since yesterday\". Returns patterns with per-row delta_usd, baseline_usd, current_usd, delta_pct, and a flag for whether each row crossed the contribution gate.",
      "annotations": {
        "title": "What's changing — patterns ranked by delta vs baseline",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_whats_new": {
      "title": "What's new — patterns by first_seen recency",
      "description": "Patterns whose first_seen timestamp falls inside a recency window — the \"what showed up recently\" question. Distinct from `log10x_top_patterns` (current cost ranking) and `log10x_whats_changing` (delta vs baseline). New patterns have no baseline, so delta math is meaningless; this tool exists so they get a clean home and don't pollute the changing-vs-baseline surface. Implementation: queries bytes_per_pattern in the current `timeRange` window to find candidate hashes, then for each hash queries the 30-day history to find the earliest non-zero datapoint via `fetchFirstSeenBatch`. A pattern is \"new\" when its first_seen timestamp is younger than `first_seen_within` (default `1d`). Default sort: by first_seen recency descending (most recent first). Use `first_seen_within: \"1h\"` for incident triage, `\"1d\"` for daily-deploy review, `\"7d\"+` for weekly observability hygiene. Returns patterns with first_seen, age, cost_now_usd, bytes_now, events_now, and the service + severity attribution.",
      "annotations": {
        "title": "What's new — patterns by first_seen recency",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "cost"
    },
    "log10x_investigate": {
      "title": "Investigate",
      "description": "Single-call root-cause investigation for any log line, pattern, service, or environment. Returns a complete causal chain (for acute spikes) or co-drifter cohort (for gradual drift) with confidence scores derived mechanically from data signal quality, plus ready-to-run verification commands. Per-pattern blocks include `offload_status` (pass / sample / compact / drop) so the narrative reflects whether the receiver is admitting or dropping the implicated patterns, matching `top_patterns` and `pattern_trend`. Call whenever the user asks 'what is going on with X', 'why is X spiking', 'investigate X', or pastes a log line / alert and asks for diagnosis. Input is the user's natural-language target — pass their words verbatim. The tool detects whether the input is a raw log line, pattern identity, service name, or 'environment' and runs the appropriate flow. It also detects whether the trajectory is acute or gradual drift and renders a different report shape for each. Confidence percentages decompose into named sub-scores (stat × lag × chain for acute; slope_sig × cohort for drift) — walk the user through the decomposition when asked. Show the entire markdown report to the user without modification.",
      "annotations": {
        "title": "Investigate",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "investigate"
    },
    "log10x_resolve_batch": {
      "title": "Triage",
      "description": "Templatize a batch of log events and return per-pattern triage. **This is one of two tools that ACTUALLY RUN A LOCAL LOG10X PIPELINE on the user's machine** (the other is `log10x_extract_templates`) — call this whenever the user asks 'can you run log10x locally', 'do a local pipeline run', 'templatize these events', or supplies any batch to analyze (Datadog/Splunk/Elastic query results, Slack incident attachments, kubectl logs, raw text). Does NOT need Kubernetes, a deployed Reporter, or a Log10x account — the pipeline runs in-process on the host. Output structures the batch by a paste-local templateHash with per-pattern frequency + severity + full template structure + per-slot variable distribution. Each top pattern carries `actions[]` chaining to `log10x_investigate` (historical correlation) and `log10x_retriever_query` (archive retrieval). Do NOT call for single-line resolution — use `log10x_event_lookup` for that. REQUIRES a local engine: the tenx binary on PATH, or Docker with LOG10X_TENX_MODE=docker.",
      "annotations": {
        "title": "Triage",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "paste"
    },
    "log10x_extract_templates": {
      "title": "Extract templates",
      "description": "Extract the structural template library from a log corpus by RUNNING A LOCAL LOG10X PIPELINE on the user's machine. Returns per-template records (the engine-internal templateHash + the template body with variable slots) and event count. Companion to `log10x_resolve_batch` — both tools answer 'can you run log10x locally / templatize these events'. Does NOT need Kubernetes, a deployed Reporter, or a Log10x account; the pipeline runs in-process on the host via either a locally-installed `tenx` binary or a `docker run log10x/pipeline-10x` container. Use for: (a) bootstrapping a pattern catalog before wiring up a Reporter, (b) offline auditing of archived log corpora, (c) validating that a config change produces expected template identities. **Validation mode**: pass `expected.min_templates`, `expected.required_patterns`, and/or `expected.forbidden_merges` to turn extraction into assertion-checked validation — each assertion reports PASS/FAIL in the output. REQUIRES a local engine: the tenx binary on PATH, or Docker with LOG10X_TENX_MODE=docker. No preflight checks for it: log10x_doctor does not probe the engine.",
      "annotations": {
        "title": "Extract templates",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "paste"
    },
    "log10x_compile": {
      "title": "Compile symbol library",
      "description": "Compile a symbol library from any mix of sources, waiting inline for the result when it is quick and handing back a pollable `job_id` when it is not. It waits up to `max_wait_ms` (default 45s): a small compile, and EVERY re-run (which reuses prior units via the pinned output folder), finishes inside that window and returns the finished library plus the full scan/link diagnostics in ONE call; a long first compile of a large tree overruns the wait and returns a running `job_id` to poll with log10x_compile_status, or just call this tool again later, since the output is pinned and a finished run is collected near-instantly. `max_wait_ms: 0` returns the job_id immediately (fire-and-forget). Sources combine freely: a local folder of source code / binaries (`source_path`), GitHub repositories via the GitHub REST API (`github_repos`, with optional `github_branch` / `github_folders`), docker/OCI images (`docker_images`), Helm charts (`helm_charts`), and Artifactory artifacts (`artifactory_instance` + `artifactory_repo`, with `artifactory_files` / `artifactory_folders`). The run scans the sources (Java, Go, Python, JS/TS, Scala, C/C++, C#, plus binaries) and writes per-file `.10x.json` symbol units plus a single linked `.10x.tar` library, the AOT artifact the 10x runtime later uses to assign hidden classes (TenXTemplates) to events. GitHub pull REQUIRES a token even for public repos: pass `github_token` or set GH_TOKEN; without one the tool returns not_configured. Docker-image pull is daemonless (podman bundled in compiler-10x, `--cap-add SYS_ADMIN` granted automatically) and public images need no credentials. Helm pull is a meta-source (renders the chart, by default also pulls the images it references); OCI/URL chart refs resolve standalone while a bare `repo/chart` needs a matching `helm_repos` entry. Artifactory pull needs a token (`artifactory_token` or ARTIFACTORY_TOKEN). REQUIRES the COMPILER flavor: runs `log10x/compiler-10x @apps/compiler` by default, or a local compiler-flavor `tenx` with mode=\"local\". An engine built before the flavor rename reports that flavor as `cloud`, and both spellings are accepted; the native runtime build has no `generate` pipeline unit and is refused. No Kubernetes or Log10x account needed. `.jar` files are not scanned directly; provide extracted `.class`.",
      "annotations": {
        "title": "Compile symbol library",
        "readOnlyHint": false,
        "idempotentHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "category": "compile"
    },
    "log10x_compile_status": {
      "title": "Compile status",
      "description": "Poll an asynchronous compile started by log10x_compile (or a link started by log10x_compile_link), by its `job_id`. Returns `job_status` (running / completed / failed / timed_out), the units produced so far + the linked `.10x.tar` (path + size), elapsed time, the engine exit code, and a credential-redacted tail of the engine log. Crucially, it promotes the engine's scan/link DIAGNOSTICS into the envelope so the compiler is not a black box at 100k–500k-file scale: per-language scan-failure counts with capped failure samples (which files failed to parse and why), and the link report (units merged / skipped, files excluded by folder/name filter, and the symbol-type histogram: class / enum / log / exec). Those appear once the compiler-10x image carries the engine diagnostics change; on an older image the tool degrades to unit counts + the log tail. The first terminal poll captures the exit code into the job record and frees the container; later polls stay readable and the compiled library is never removed.",
      "annotations": {
        "title": "Compile status",
        "readOnlyHint": true,
        "idempotentHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "category": "compile"
    },
    "log10x_compile_link": {
      "title": "Link symbol units",
      "description": "Link an existing folder of `.10x.json` symbol units (from a prior compile) into a single `.10x.tar` library, with NO source scan. This is the same compiler-flavor Compiler app invoked with link-only arguments: the units folder is the `outputSymbolFolder` and no source is mounted, so the engine reuses the units already on disk (scans 0 new files) and merges them into the library, which is written into that same folder. Like log10x_compile it waits inline up to `max_wait_ms` (default 45s; linking is usually fast, so it normally returns the linked library in ONE call) and otherwise hands back a `job_id` to poll with log10x_compile_status. Use it to re-link after editing or pruning units, to assemble a library from a units tree built piecemeal, or to rebuild a library from the output folder of a prior log10x_compile. REQUIRES the COMPILER flavor (runs `log10x/compiler-10x @apps/compiler` by default, or a local compiler-flavor `tenx` with mode=\"local\"; an engine built before the flavor rename reports it as `cloud` and both spellings are accepted, the native runtime build is refused). No Kubernetes or Log10x account needed.",
      "annotations": {
        "title": "Link symbol units",
        "readOnlyHint": false,
        "idempotentHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "category": "compile"
    },
    "log10x_retriever_query": {
      "title": "Retriever query",
      "description": "Forensic retrieval / rehydration from the Log10x Retriever archive (the customer's own S3 bucket) by the engine's STABLE pattern identity. The use case: events the receiver offloaded to the archive instead of the SIEM, or that aged out of SIEM retention, recovered by querying the stamped identity over a historical window. Pre-computed Bloom filters scope the scan to the matching pattern identity (tenx_user_pattern) so only relevant byte ranges are fetched (the moat: query-side token precision, not a full S3 scan). Matched events land as a list of `*.jsonl` objects in the customer's S3; the tool returns an in-context preview (capped by `limit`) PLUS `data.results_location` (the S3 bucket + prefix holding the full object set). A capable agent reads those objects directly to answer, or hands the S3 object list to the customer's own S3-to-SIEM path. No re-ingestion pipeline, no proprietary format. The envelope additionally carries per-pattern `offload_status` so retrieval results agree with the live metric-surface disposition (pass / sample / compact / drop) without a second tool call. Call for: events matching a pattern OUTSIDE SIEM retention; events filtered by a variable value that is not a faceted SIEM dimension (e.g. 'all payment_retry events for customer acme-corp 90 days ago'); compliance / audit / forensic exact retrieval; confirming what the receiver actually offloaded for a given pattern. Optional JavaScript `filters` refine over payloads after the Bloom-scoped fetch. For a time-bucketed series instead of raw events, use `log10x_retriever_series`. The envelope carries by_severity / by_service / by_day rollups with a rollup_basis provenance stamp (qrs_summaries = whole-match from engine summaries; events_capped = derived from the capped download).",
      "annotations": {
        "title": "Retriever query",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "retrieve"
    },
    "log10x_retriever_series": {
      "title": "Retriever time series",
      "description": "Materialize a fidelity-aware time series from the customer's S3 archive over an arbitrary window, with optional group-by on enrichment fields. Auto-selects between exact full aggregation (Strategy A) and per-window-sampled fan-out (Strategy B) based on Reporter pattern volume — small/moderate-volume queries get exact counts; high-volume / long-window queries get a sampled series with time-distribution + group-ranking fidelity preserved and tail caveats reported. Pathological volume is refused with structured narrowing guidance, never silently truncated. Call when: (a) the user wants a 'rate of pattern X over the last 30 days, broken down by tenant' answer that exceeds SIEM retention/budget, (b) a baseline needs building from cost-driver patterns where Prometheus has continuous metrics but the *grouped breakdown* lives only in the S3 archive. Use `log10x_retriever_query` instead when you need the actual event payloads (not aggregates).",
      "annotations": {
        "title": "Retriever time series",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "retrieve"
    },
    "log10x_retriever_query_status": {
      "title": "Retriever query status",
      "description": "Post-hoc diagnostic surface for a specific retriever query, addressed by `queryId` (returned from `log10x_retriever_query` or recovered from the S3 results prefix). Pulls the coordinator's `_DONE.json` stats (scanned / matched / streamRequests / streamBlobs / submittedTasks / expectedMarkers), counts per-worker byte-count markers under `q/<queryId>/`, lists result JSONL files under `qr/<queryId>/`, optionally filters CloudWatch events from the `queryLogGroup` for the queryId substring (when the chart's `queryLogGroup` is configured), and runs a diagnostics engine that classifies the run into states like `dispatcher_failure` (scanned=0 + submittedTasks>0 — typical signature of the chart 1.0.20 incomplete streamer→retriever rename), `results_not_uploaded`, or `observability_disabled`. When pod logs are reachable from the MCP host, fetches a tail and greps for the `cloud/streamer/subquery` include-resolution signature to confirm the dispatcher-failure category. Call this whenever `log10x_retriever_query` returns 0 events but the wall-clock implies real scan work, or whenever an offline post-mortem needs the structured timeline for a specific queryId. Pass fetch_results: true to ALSO recover the completed results from S3 (10-event preview + counts + results_location) after a partial or timed-out query, without resubmitting.",
      "annotations": {
        "title": "Retriever query status",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "retrieve"
    },
    "log10x_retriever_probe": {
      "title": "Retriever e2e probe",
      "description": "End-to-end probe of the deployed Retriever chain. Fires a synthetic query at the picked top-volume tenx_hash (or an explicit target_hash) and asserts every stage in order: offload bucket has recent data, indexer pipeline is running (kubectl logs grep for 'starting pipeline - Tenx: @/apps/retriever/index'), SQS subquery + stream queues drained (depth ≤ 10), retriever pod containers all ready, then submits the query and asserts CloudWatch scan complete events have matched>0, CloudWatch stream worker complete events exist, S3 qr/<queryId>/*.jsonl files were written, and the MCP returned events_matched>0 AND events_returned>0. Returns a structured verdict (green / broken / unknown) with per-assert observed + remedy. Call this as the post-install verify step (chained from log10x_advise_retriever step_verify) OR as a deep doctor diagnostic when log10x_retriever_query returns 0 events and the cause is unclear. Catches the silent-failure shapes that take hours to debug manually: indexer not booted, chart 1.0.20 / runtime-name stream pipeline launch failures, IRSA s3:PutObject misconfigured, MCP input_bucket misaligned with engine write location.",
      "annotations": {
        "title": "Retriever e2e probe",
        "readOnlyHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "retrieve"
    },
    "log10x_backfill_metric": {
      "title": "Backfill metric",
      "description": "Niche / legacy: write a historical metric (Datadog or Prometheus remote_write) backfilled from the Retriever archive. This is thin output-piping left from an earlier metric-rehydration use case, NOT the retriever's headline. Prefer `log10x_retriever_series` to get the time-bucketed series itself (the agent reads it directly); use this only when the customer specifically needs the series WRITTEN into their own TSDB for an existing dashboard/alert from day one and cannot backfill from the TSDB's own data. Shipping a series into a TSDB is ordinary piping the customer's environment can usually do itself. Datadog + Prometheus remote_write are wired; others return 'not yet implemented'. Do NOT call when the metric already exists in the destination.",
      "annotations": {
        "title": "Backfill metric",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "retrieve"
    },
    "log10x_doctor": {
      "title": "Doctor (health check)",
      "description": "Run a startup health check on the Log10x MCP installation. Probes: environment configuration validity, prometheus.log10x.com reachability and auth, Reporter tier detection (Edge / Cloud / none), Retriever endpoint configuration (informational), Datadog destination credentials (informational), paste endpoint reachability, cross-pillar enrichment floor (v1.4, when LOG10X_CUSTOMER_METRICS_URL is set). Returns a markdown report with pass / warn / fail per check and remediation hints. Call this once at the start of a session to verify the install, or any time a tool returns an unexpected error and you want to isolate whether the problem is configuration or transient.",
      "annotations": {
        "title": "Doctor (health check)",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "install"
    },
    "log10x_login_status": {
      "title": "Login status",
      "description": "List the user's Log10x ACCOUNT environments and report credential / login state. **Call this, and ONLY this, for any of these phrasings**: 'which Log10x environments do I have', 'which environments are available to me', 'list my envs', 'what tenants/accounts can I query', 'am I logged in', 'switch envs'. **For 'log me in' / 'sign me up' / 'create a Log10x account' / 'use my real account'**: call `log10x_signin_start` (browser Auth0 device flow; the model chains to `log10x_signin_complete` automatically), or call `log10x_signin_complete` directly with `{ api_key: \"<key>\" }` if the user already has a key. **Do NOT call `log10x_discover_env` for these questions** — that tool scans the user's Kubernetes/AWS infrastructure, unrelated to Log10x account environments. In demo mode (no key set, or key failed validation), the response is a step-by-step config guide. In signed-in mode, lists the user's identity, every env they can reach with permissions (OWNER/WRITE/READ), the default env, and the most-recently used env this session. Read-only, takes no args.",
      "annotations": {
        "title": "Login status",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "account"
    },
    "log10x_signin_start": {
      "title": "Sign in (start browser flow)",
      "description": "Step 1 of the Log10x browser sign-in chain. **Call this for any of these phrasings**: 'sign me up for Log10x', 'create a Log10x account', 'log me in to Log10x', 'set up my Log10x account', 'switch from demo to my own data'. Requests an Auth0 device code, opens the user's browser to auth.log10x.com with the user_code pre-embedded, and returns IMMEDIATELY (no polling). Response carries `user_code`, `verification_uri_complete`, and the opaque `device_code`. **What the model MUST do after this returns**: (1) show the user the `user_code` and `verification_uri_complete` so they can verify the code in their browser matches, then (2) AUTOMATICALLY call `log10x_signin_complete` with `{ device_code: \"<the device_code from this response>\" }` as the next tool call. The user does NOT need to ask for that second step. **For pasted-key sign-in instead of browser**: skip this tool and call `log10x_signin_complete` directly with `{ api_key: \"<key>\" }`.",
      "annotations": {
        "title": "Sign in (start browser flow)",
        "readOnlyHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_signin_complete": {
      "title": "Sign in (complete)",
      "description": "Step 2 of the Log10x sign-in chain. Two mutually-exclusive paths controlled by which arg you pass. (a) **`{ device_code: \"<...>\" }`**: finishes the browser flow that `log10x_signin_start` began. The model should call this AUTOMATICALLY right after `log10x_signin_start` returns, passing back the opaque `device_code` from that response unchanged. Polls Auth0's `/oauth/token` until the user confirms the device authorization in their browser, then exchanges the Auth0 access token for a long-lived Log10x API key. (b) **`{ api_key: \"<key>\" }`**: pasted-key path, no browser. Validates the key against `/api/v1/user` and saves it. **Pass exactly one of `device_code` or `api_key`**; both or neither is rejected with a clear error. Either path writes the resolved API key to `~/.log10x/credentials` (mode 0600), hot-reloads the MCP's env list in-process, and (if `LOG10X_API_KEY` is set in the host config and would override the new file) clears that env var in-process and tells the user to remove it from their host config to make the change permanent.",
      "annotations": {
        "title": "Sign in (complete)",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_signout": {
      "title": "Sign out",
      "description": "Wipe the persistent credentials file at `~/.log10x/credentials` and reload envs so subsequent calls fall back to demo mode (or whichever lower-priority configuration source picks up). **Call this for**: \"sign me out of Log10x\", \"log out\", \"remove my Log10x credentials\", \"stop using my Log10x account\", \"go back to demo mode\". Idempotent — running it without saved credentials is a no-op. Does NOT revoke the API key on the BE; the user must do that from console.log10x.com → Profile → API Settings if they want to invalidate the key everywhere (mirrors `gh auth logout` and `aws sso logout`). If the user has `LOG10X_API_KEY` set in their MCP host config, that env var will still be active after sign-out — the tool result will flag this so the LLM can tell the user to also unset it and restart.",
      "annotations": {
        "title": "Sign out",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "account"
    },
    "log10x_update_settings": {
      "title": "Update account settings",
      "description": "Update the user's Log10x account metadata (analyzer cost ($/GB), AI provider settings, display name, etc.) via `POST /api/v1/user`. **Call this for**: \"set my analyzer cost to $3\", \"switch my AI provider to OpenAI\", \"use my own Anthropic key\", \"disable AI\", \"update my company name\". Idempotent — repeated calls converge to the same state. The metadata field is a free-form key/value object; common fields are documented in the schema. Existing fields not in the payload are preserved (PATCH-like semantics). On success, the in-process env list is reloaded so subsequent tool calls see the updated metadata immediately (e.g., new analyzer_cost is honored on the next cost_drivers run).",
      "annotations": {
        "title": "Update account settings",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_create_env": {
      "title": "Create environment",
      "description": "Provision a new Log10x environment on the user's account via `POST /api/v1/user/env`. **Call this for**: \"create a staging env\", \"I need a new environment for my dev cluster\", \"set up a separate env for ${customer-name}\". Pairs naturally with the install advisor — after creating the env, call `log10x_advise_install` with the new env_id to get the Reporter / Receiver / Retriever install plan scoped to it. The new env's id is returned in the result so the LLM can chain. NOT idempotent — duplicate names are rejected with 409 Conflict; the tool pre-checks the in-memory env list to surface a friendly error before the round-trip.",
      "annotations": {
        "title": "Create environment",
        "readOnlyHint": false,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_update_env": {
      "title": "Update environment",
      "description": "Update an existing Log10x environment via `PUT /api/v1/user/env`: rename it, or change which env is the user's default. **Call this for**: \"rename my staging env to dev\", \"make production the default\", \"set my main account as the default env\". Idempotent. The env_id is required (get it from `log10x_login_status`). Pass at least one of `name` or `is_default`.",
      "annotations": {
        "title": "Update environment",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_delete_env": {
      "title": "Delete environment (destructive)",
      "description": "Remove an environment from the user's Log10x account via `DELETE /api/v1/user/env`. **DESTRUCTIVE — irrecoverable.** Metric history scoped to the env is also lost. Backend rejects 401 if the caller is not the env owner. **Call this only when the user has explicitly asked to delete an env and confirmed the env name back.** The tool requires a `confirm_name` arg matching the env's exact display name (case-sensitive); if it doesn't match, the tool refuses without contacting the backend and shows the correct name. Mirrors `gh repo delete` and the GitHub web \"type the repo name to confirm\" pattern. **Best practice**: when the user says \"delete X env\", state the name and env_id back, ask for explicit confirmation, then call this with the confirmed name.",
      "annotations": {
        "title": "Delete environment",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_env_register": {
      "title": "Register environment descriptor",
      "description": "Persist a full EnvironmentConfig document — cluster identity, SIEM destination, offload destinations, streamer + retriever endpoints — to whichever on-prem env-config store the customer's cloud uses (Kubernetes ConfigMap, AWS SSM, GCP Secret Manager, Azure App Configuration, or a local file for dev). **Distinct from log10x_create_env**: that mints account-level identity on the SaaS backend; this writes the cluster-side descriptor every tool resolves against when it needs the streamer URL, retriever URL, SIEM kind, or offload bucket. **Call this for**: \"register my new cluster with log10x\", \"persist the env descriptor for prod\", \"wire up the staging cluster's env config\". Validates the document against the schema before any store write — partial writes are not allowed. Pin a backend with `target_store` to refuse silent fallback; omit it for first-available auto-pick (k8s → aws_ssm → gcp_sm → azure_ac → local).",
      "annotations": {
        "title": "Register environment descriptor",
        "readOnlyHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_rotate_api_key": {
      "title": "Rotate API key (destructive)",
      "description": "Replace the user's Log10x API key with a freshly-minted UUID via `POST /api/v1/user/rotate-key`. **DESTRUCTIVE — the previous key is invalidated immediately on the backend.** Other devices / scripts / hosts holding the old key will start receiving `401 Unauthorized` on the next request. **Call this for**: \"rotate my Log10x API key\", \"I think my key was leaked\", \"regenerate my API key\". Requires a `confirm: \"rotate-now\"` literal to prevent accidental triggering — always ask the user to confirm before calling. On success the tool: writes the new key to `~/.log10x/credentials` (so other MCP hosts on this machine pick it up), clears any in-process `LOG10X_API_KEY` so the new key takes effect for THIS server immediately, hot-reloads envs. The new key is shown in the response (also viewable later at console.log10x.com → Profile → API Settings). The result message lists every place the user should update — host configs, scripts, CI secrets, etc.",
      "annotations": {
        "title": "Rotate API key",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "account"
    },
    "log10x_customer_metrics_query": {
      "title": "Customer metrics query",
      "description": "Low-level PromQL passthrough to the customer metric backend configured via LOG10X_CUSTOMER_METRICS_URL. Returns the raw Prometheus response shape plus metadata about which backend served the query. This is the escape hatch for cross-pillar investigations the higher-level primitives don't cover — use it to explore the customer backend's label universe, run a one-off PromQL expression, or verify that a specific metric exists before correlating against it. For typical cross-pillar workflows, compose the deterministic primitives: `log10x_metrics_that_moved` → `log10x_rank_by_shape_similarity` → `log10x_metric_overlay`.",
      "annotations": {
        "title": "Customer metrics query",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "investigate"
    },
    "log10x_discover_join": {
      "title": "Discover join label",
      "description": "Auto-discover the structural join label between Log10x pattern metrics and the customer metric backend. Runs Jaccard similarity on label value sets across candidate label pairs, returns the best pair above the 0.7 threshold plus runner-ups above 0.5. The result is cached per-session keyed by (environment, customer-backend-endpoint) so the cross-pillar primitives (metrics_that_moved, rank_by_shape_similarity, metric_overlay) can auto-run this once at session start and reuse the cached join without re-probing. Agents should normally NOT need to call this tool directly — the primitives call it internally. The explicit tool exists for power users who want to inspect the join universe or force a re-discovery after backend changes. When no pair crosses the threshold, returns a structured `no_join_available` response with the full probed-label matrix and recommended next actions.",
      "annotations": {
        "title": "Discover join label",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "investigate"
    },
    "log10x_metrics_that_moved": {
      "title": "Metrics that moved",
      "description": "First step of cross-pillar investigation: deterministic filter on which customer metrics actually moved while an anchor was active. Anchor is either a Log10x pattern (`anchor_type: \"log10x_pattern\"`) OR a customer metric expression (`anchor_type: \"customer_metric\"`); candidates are all sibling series from the OTHER pillar. Partitions the anchor's window into high-phase / low-phase buckets by median rate and keeps only candidates whose mean value differs ≥15% between the two phases. Returns `moved[]`, `not_moved[]`, `evaluation_failed[]` — no Pearson, no tier, no causal framing. This is the cheap deterministic cut that pares the candidate set before the more expensive shape-similarity pass. Compose with `log10x_rank_by_shape_similarity` and `log10x_metric_overlay`.",
      "annotations": {
        "title": "Metrics that moved",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "investigate"
    },
    "log10x_rank_by_shape_similarity": {
      "title": "Rank by shape similarity",
      "description": "Second step of cross-pillar investigation: Pearson correlation + signed lag on a pre-filtered candidate set (typically the `moved[]` output of `log10x_metrics_that_moved`). Returns per-candidate: `pearson_magnitude`, `pearson_signed` (direction preserved), `lag_seconds` (signed: negative = candidate leads anchor, positive = candidate lags), `lag_at_bound` (flag: peak landed at search-window boundary), `lag_tightness` (how sharply the Pearson surface peaks), `anchor_phase_gap`, `anchor_phase_aligned` (flag: candidate value differs ≥15% between anchor's high-phase and low-phase buckets), `n_buckets`. No tier, no causal label — the agent reads the flags and decides. Compose with `log10x_metric_overlay` for the final per-candidate aligned-timeseries view.",
      "annotations": {
        "title": "Rank by shape similarity",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "investigate"
    },
    "log10x_metric_overlay": {
      "title": "Metric overlay",
      "description": "Third step of cross-pillar investigation: return aligned anchor + candidate timeseries plus deterministic facts (`peak_at`, `peak_offset_seconds`, `n_buckets_aligned`). No Pearson, no tier — pure raw data for the agent to interpret. Use this once `log10x_rank_by_shape_similarity` has narrowed to a single suspect, or to manually verify any anchor/candidate pair side-by-side. Bucket size auto-selected from window length; both series are right-aligned to the same trailing bucket grid so a sparse anchor and dense candidate compare on the same chaos window.",
      "annotations": {
        "title": "Metric overlay",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "investigate"
    },
    "log10x_poc_from_siem_submit": {
      "title": "POC from SIEM (submit)",
      "description": "Kick off a full log-cost-optimization POC against the user's SIEM. Pulls a representative event sample, templatizes into stable pattern identities, and renders a 9-section markdown report covering top cost drivers, Receiver recommendations, ready-to-paste native SIEM exclusion configs, Compact mode potential, risk/dependency checks, and deployment paths. Supported SIEMs: cloudwatch (AWS CloudWatch Logs via IAM credential chain), datadog (DD_API_KEY + DD_APP_KEY), sumo (Sumo Logic), gcp-logging (GCP Cloud Logging), elasticsearch (Elastic Cloud / self-hosted), azure-monitor (Azure Monitor / Log Analytics), splunk (SPLUNK_HOST + SPLUNK_TOKEN), clickhouse (OpenObserve / SigNoz / custom schemas). Auto-detects the SIEM from env vars when `siem` omitted — explicitly pass `siem` if multiple credential sets exist. `scope` and `query` are SIEM-specific: CloudWatch (log group + filter pattern), Datadog (index + query), Sumo (_sourceCategory + query), GCP (project id + filter), Elasticsearch (index pattern + KQL), Azure (workspace id + KQL), Splunk (index + SPL), ClickHouse (database + SQL WHERE). For ClickHouse, also pass `clickhouse_table` (required) and column-mapping args for custom schemas (OpenObserve/SigNoz auto-detected). Returns a `snapshot_id` — poll via log10x_poc_from_siem_status to retrieve progress and the final report. Report is also written to `${LOG10X_REPORT_DIR:-/tmp/log10x-reports}/poc_from_siem-<timestamp>.md`. Default window is 7d, default target event count is 250k, default max pull time is 5 min — the pull stops at whichever of the two ceilings hits first. **Tier prerequisites**: none. No log10x API key required. **Templating defaults to privacy_mode=true**: events are templated by a local Log10x engine, either a native `tenx` CLI (install for macOS/Linux/Windows: https://doc.log10x.com/install/) or a local Docker container (set `LOG10X_TENX_MODE=docker`, auto-detected and preferred when the mode is unset), and never leave the machine. Set `privacy_mode: false` to route through the public Log10x paste endpoint — demo use only, not production log content. **Two modes, and the agent should name whichever the user's phrasing invites.** This tool is the NETWORKED one: it reads the analyzer directly over the network with the caller's credentials, and the MCP mints one licence. The FENCED mode runs the same POC with no network at all — `log10x_emit_sample_plan` renders a read-only export script the user runs themselves, and the analysis happens in a container started with `--network none`, so 'cannot exfiltrate' is a kernel fact the user checks with one `docker inspect` rather than a claim we make. Offer it; do not ask which one first.",
      "annotations": {
        "title": "POC from SIEM (submit)",
        "readOnlyHint": false,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "poc"
    },
    "log10x_poc_from_siem_status": {
      "title": "POC from SIEM (status)",
      "description": "Retrieve progress or a view of the report from a log10x_poc_from_siem_submit run. Pass `snapshot_id`; optionally `view` to select the level of detail. **In-progress** responses report status (pulling / templatizing / rendering), progress_pct, step_detail, and elapsed_seconds — poll every ~30s until done. **Complete** responses render one of six views: `summary` (default, ~30 lines — exec banner + top-5 wins + views CTA), `full` (complete 9-section report, ~300 lines), `yaml` (paste-ready Receiver mute-file for the top N patterns), `configs` (native SIEM exclusion configs — Datadog exclusion filter / Splunk props.conf / etc.), `top` (expanded N-row drivers table), `pattern` (deep-dive on one identity — requires `pattern` arg). **Failures** include partial_report_markdown when any events were successfully pulled before the error. The full report is also written to ${LOG10X_REPORT_DIR:-/tmp/log10x-reports}/poc_from_siem-<timestamp>.md regardless of which view the caller requested. Snapshots live in-memory per MCP process; a restart clears them, so persist the final report path if you need it later. **Unified envelope**: response carries `status`, `query_count`, `total_latency_ms`, `backend_pressure_hint`, `human_summary`, plus the existing snapshot-lifecycle fields. Errors (unknown snapshot_id, render failure) come back as `status: 'error'` with a structured `PrimitiveError` envelope. See `docs/cross-pillar-primitives.md` for the agent behavior contract. **Two modes, and the agent should name whichever the user's phrasing invites.** This tool is the NETWORKED one: it reads the analyzer directly over the network with the caller's credentials, and the MCP mints one licence. The FENCED mode runs the same POC with no network at all — `log10x_emit_sample_plan` renders a read-only export script the user runs themselves, and the analysis happens in a container started with `--network none`, so 'cannot exfiltrate' is a kernel fact the user checks with one `docker inspect` rather than a claim we make. Offer it; do not ask which one first.",
      "annotations": {
        "title": "POC from SIEM (status)",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "poc"
    },
    "log10x_poc_from_local": {
      "title": "POC from local logs (kubectl)",
      "description": "Run a log-cost-optimization POC entirely from local log sources — pass `path` for one log file (wrapper-normalized) or `paths` for files, directories and globs; `kubectl` samples pod logs; `docker` and `journald` to follow. No log-analyzer credentials required. Use when the prospect has no SIEM connection or has not yet shared API keys. Returns a synchronous markdown report with: (a) **sample composition** table — top-N pods by byte volume; the prospect must confirm the sample looks like their production mix, (b) **industry-pricing matrix** — projected savings at Datadog / Splunk / CloudWatch / Sumo / Elastic / OpenSearch list prices, NOT a prediction of any specific bill, (c) **top patterns** in the kubectl-sourced sample. For native exclusion configs, paste-ready Receiver YAML, and the full 9-section report tied to a specific log analyzer's actual GB-billed volume, run `log10x_poc_from_siem` once credentials are available. **No automatic fallthrough**: this tool is invoked explicitly. If `log10x_poc_from_siem` failed on missing credentials, the calling LLM should ask the user before re-invoking with this tool — local-source framing is genuinely different from SIEM-attached framing and silent fallthrough would be a bait-and-switch. REQUIRES a local engine: the tenx binary on PATH, or Docker with LOG10X_TENX_MODE=docker. No log-analyzer credentials and no deployment are needed, but without an engine this returns an error rather than a report. Pass target_percent_reduction as a whole-number percent (e.g. 40 for 40%) to get a feasibility verdict against that target. **Two modes, and the agent should name whichever the user's phrasing invites.** Run normally, this tool reads local files but the server around it still has network. Run inside the FENCED profile (`TENX_AIRGAPPED=true`, `--network none`, the `log10x/poc` image) it is the same analysis with no network at all, and its output carries its own `docker inspect` proof. `log10x_emit_sample_plan` produces the sample for that mode from the user's own analyzer. Offer it; do not ask which one first.",
      "annotations": {
        "title": "POC from local logs (kubectl)",
        "readOnlyHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      },
      "category": "poc"
    },
    "log10x_emit_sample_plan": {
      "title": "Emit a sample-export script for the fenced POC",
      "description": "Render a read-only shell script that exports a log sample out of the user's OWN log analyzer, with the user's OWN credentials, on a machine the user chooses — and then stop. This server does not run the script and, in the fenced profile, could not: it runs inside a container started with `--network none`. That split is the point. Code that sees log data has no network; code that has network is the user's own `aws` / `curl` driven by a script short enough to read once. Use this as step 2 of the fenced POC (step 1 is minting the licence with one visible curl, step 3 is running `log10x_poc_from_local` inside the fenced container over the exported files, step 4 is verifying the fence with `docker inspect` and by turning Wi-Fi off). Also use it whenever the credentials live somewhere this process does not — a jump host, a locked-down laptop, another team. Args: siem (required: cloudwatch / splunk / elasticsearch / opensearch / datadog), window (default 14d), target_event_count (default 1,000,000 — the same default `log10x_poc_from_siem` uses, so both paths sample the same size), scope, query, output_dir (default ./poc/logs), write_script (default true, writes export-sample.sh mode 0755 in the working directory). Returns the script text, the read-only API operations and credential variables it touches, a review checklist, and the exact `log10x_poc_from_local` arguments to call next. The sampling matches `log10x_poc_from_siem` bucket for bucket — same stratified sub-windows, same per-bucket cap — so a fenced POC and a credentialed POC over the same window differ because the logs differ. Emitted scripts contain no log10x hostname; the server refuses to return one that does. ClickHouse, Azure Monitor, Coralogix, GCP Logging and Sumo Logic are follow-up work. Read-only: it renders text and writes one script file; it contacts nothing.",
      "annotations": {
        "title": "Emit a sample-export script for the fenced POC",
        "readOnlyHint": true,
        "idempotentHint": false,
        "openWorldHint": false
      },
      "category": "poc"
    },
    "log10x_discover_env": {
      "title": "Discover env (k8s + AWS)",
      "description": "Read-only discovery of the caller's Kubernetes cluster + AWS account — i.e. the customer's INFRASTRUCTURE environment, NOT their Log10x account. **When the user wants to install Log10x: call this tool FIRST and then `log10x_advise_install` — that's the whole pre-flight. Do NOT call `log10x_doctor` / `log10x_login_status` / `log10x_savings` / etc. before the install; the wizard handles all login + license logic internally, and surfacing those tools' optional-capability warnings (Retriever, Datadog backfill, cross-pillar metrics) makes the install feel more complicated than it is.** Probes kubectl (workloads, DaemonSets, Helm releases, service-account IRSA annotations, metrics-backend agents) and AWS (EKS, S3, SQS, CloudWatch log groups) to detect: which forwarder is running (Fluent Bit, Fluentd, Filebeat, Logstash, OTel Collector, Vector), which log10x apps are already installed (Reporter, Receiver, Retriever), and which metrics backends are already deployed (Datadog Agent, Prometheus, Elastic, CloudWatch Agent, etc.). Returns a terse markdown report + a `snapshot_id` (cached 30 min) the advisor tools consume. **Do NOT call this tool to answer \"which Log10x environments do I have access to\" / \"list my envs\" / \"switch envs\" — those are about the user's Log10x ACCOUNT environments, use `log10x_login_status` for that.** Call THIS tool only when the question is about k8s workloads, AWS infra, or \"what's deployed in my cluster\". Every shell call is logged in the snapshot's `probeLog` for audit. No writes, no state mutation: only `kubectl get` and `aws ... describe/list` verbs. **Tier prerequisites**: none — this is a pre-install tool and runs against any customer environment.",
      "annotations": {
        "title": "Discover env (k8s + AWS)",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "install"
    },
    "log10x_advise_retriever": {
      "title": "Advise: Retriever install",
      "description": "Given a DiscoverySnapshot (from `log10x_discover_env`), produce an install/verify/teardown plan for the Log10x Retriever. Unlike Reporter + Receiver, the Retriever has no forwarder choice: it is a standalone set of workloads (indexer + query-handler + stream-worker) that read source logs from object storage through a queue and serve an HTTP query endpoint. Two storage providers, picked by `storage_provider`: **aws** (S3 input bucket with an `indexing-results/` prefix, four SQS queues, an IRSA-annotated ServiceAccount), auto-detected from the discovery snapshot or supplied explicitly; **azure** (AKS, Azure Blob containers, four Azure Storage Queues, workload identity), where the chart's own `provision-retriever.sh` creates the resources and the plan quotes it. `blockers` carries the inputs a complete plan is still missing and the plan emits no steps while it is non-empty; the preflight table is the state report beside it, and a FAIL row there is reported, not a gate, so read `preflight_summary.fail` as well as `blockers`. Verify probes follow the provider: pods Ready, indexer processing, query endpoint responding, then S3 + SQS probes on aws and Blob + Storage Queue probes on azure. Teardown uninstalls the Helm release; on aws the S3 / SQS / IAM lifecycle stays with Terraform, on azure the last step runs the provisioning script with `--destroy` to delete the resource group it created.",
      "annotations": {
        "title": "Advise: Retriever install",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_advise_install": {
      "title": "Install wizard",
      "description": "Progressive install wizard for the Log10x Reporter / Receiver on Kubernetes. **This is the SINGLE entry point for installs — call it first.** Do NOT call `log10x_doctor` or `log10x_login_status` as a pre-flight; the wizard handles login state, license acquisition, and demo-mode fallback internally, and surfacing the doctor's optional-capability warnings (Retriever, Datadog backfill, cross-pillar metrics) ahead of the install confuses users with concepts that are unrelated to deploying the Reporter/Receiver. Takes a `snapshot_id` from `log10x_discover_env` and walks the user through five decisions, asking one at a time and remembering each answer across turns (the snapshot's wizard session): (1) **app** — `reporter` (dedicated DaemonSet forwarder, zero-touch) or `receiver` (sidecar inside the user's existing forwarder); (2) **forwarder** — Receiver-only, auto-picked when one is detected, asked when multiple; (3) **backends** — array of metrics destinations, can be multiple (e.g., `[\"log10x\", \"datadog\"]` to report to both SaaS + own backend simultaneously); (4) **airgapped** — opt-in CISO-friction reducer, conflicts only with `\"log10x\"` in `backends` (engine sends NOTHING to log10x.com); (5) **license_jwt** — auto-fetched from `/api/v1/license/demo` if the user is not signed in, or from `/api/v1/license` with the persisted Auth0 token if they are. Each call merges new args into the session and either asks the next question (returning a markdown prompt) or emits the final install plan once all answers are in. Demo + airgapped surfaces a soft warning (engine downgrades to online mode on demo licenses). Plan is plan-only: emits helm commands + values.yaml; the user runs them. **Tier prerequisites**: none — this is a pre-install tool.",
      "annotations": {
        "title": "Install wizard",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_configure_engine": {
      "title": "Configure engine",
      "description": "[FRESH-SESSION ROUTING: if this is the user first cost question of the session, call log10x_start first instead — it returns the orientation menu the user needs before any per-tool action.] Unified per-pattern action-plan PR author. Resolves a monthly $ budget against a per-destination cost model (Splunk, Datadog, Elasticsearch, CloudWatch, Azure, GCP, Sumo, ClickHouse) into a per-pattern action plan (pass | sample | compact | drop | tier_down) and emits a gitops PR. Defaults to auto-applying via `gh` CLI (industry-standard MCP write-tool behavior, mirrors github/github-mcp-server). Set `auto_apply: false` or `read_only: true` for evaluation / dry-run / headless contexts. REQUIRES a Receiver in-path to enact the policy: at Reporter or Dev tier this still renders a valid PR, but nothing consumes it and no bytes change. Check tier with log10x_start first; install via log10x_advise_install.",
      "annotations": {
        "title": "Configure engine",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      },
      "category": "install"
    },
    "log10x_estimate_savings": {
      "title": "Estimate savings",
      "description": "[FRESH-SESSION ROUTING: if this is the user first cost question of the session, call log10x_start first instead — it returns the orientation menu the user needs before any per-tool action.] Two-mode savings estimator with percent-first reporting and a dollar overlay. `forecast` projects bytes_in -> bytes_out and percent reduction for a proposed plan; pass `effective_ingest_per_gb` (or rely on the account profile list-price rate) to overlay $/mo per pattern and in totals. `verify` counts realized savings from the engine `routeState` label over a window with cap-hit / drift / new-patterns / leakage attribution, leading with percent and adding the dollar overlay only when a rate is set. Without a rate, dollar fields are emitted as null (never as a fabricated $1/GB number); the envelope carries `rate_source: list_price | customer_supplied | unset` so callers can show how the overlay was derived. Accepts siem_lens (what-if destination): keeps the real volumes, prices + gates for that destination at list rates, and stamps siem_actual vs siem_lens in the envelope. REQUIRES Reporter-tier cost attribution (per-pattern bytes in the metrics backend). Before anything is deployed, use log10x_poc_from_local or log10x_poc_from_siem_submit instead.",
      "annotations": {
        "title": "Estimate savings",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "cost"
    },
    "log10x_baseline": {
      "title": "Baseline readiness",
      "description": "Pre-flight readiness gate for cost-reduction tools. Verifies Reporter age (default 7d), pattern-coverage stability, and absence of acute anomalies before configure_engine / estimate_savings should run. Returns structured `not_ready` with the specific gate(s) that failed.",
      "annotations": {
        "title": "Baseline readiness",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "cost"
    },
    "log10x_commitment_report": {
      "title": "Commitment report",
      "description": "CFO-facing weekly aggregate against a previously-opened commitment record. Applies a Bayesian Beta(2,2) prior to realized-savings estimates and renders a markdown summary suitable for sharing. REQUIRES a commitment record opened by a prior configure_engine apply; without one there is no baseline to report against.",
      "annotations": {
        "title": "Commitment report",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "cost"
    },
    "log10x_find_skew": {
      "title": "Find skew",
      "description": "Identify patterns where one slot value dominates the field (>= 60% of events by default). Surfaces sampling opportunities: \"slot `verb` is `get` 78% of events — sample the get case at 1/10 and save volume without losing signal.\" Differentiated against analyzer field histograms because the engine groups by per-pattern field-set, so dominance is measured within the structural pattern, not globally. **Stage 1**: accepts events as a paste array (same shape as log10x_resolve_batch). **Calibration honesty**: the 60% concentration floor and 1/10 sampling rate are hand-picked defaults tagged `unvalidated_default` in the output. The envelope surfaces the empirical `observed_dominant_pct_distribution` across all candidate slots so the agent can judge whether 0.6 is well above or below the noise floor for this dataset. See `docs/cross-pillar-primitives.md` for the agent behavior contract.",
      "annotations": {
        "title": "Find skew",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "detect"
    },
    "log10x_pattern_mitigate": {
      "title": "Pattern mitigate",
      "description": "[FRESH-SESSION ROUTING: if this is the user first cost question of the session, call log10x_start first instead — it returns the orientation menu the user needs before any per-tool action.] Given one pattern (symbolMessage identity or tenx_hash), return the env-gated CAPABILITY MENU of which mitigation paths are reachable: drop_at_analyzer, drop_at_forwarder, mute_at_10x, compact_at_10x. Each option carries `enabled` (true/false), `label`, and `disabled_reason` when not reachable. This is a REACHABILITY-FIRST router: it answers \"which of the four tiers can I use right now given my env wiring\" — NOT \"how much would each save\". Per-option estimated savings (% reduction, $/mo) and paste-ready config snippets are surfaced by the next-tool chain (log10x_cost_options for the action menu, then the specific action tool for the snippet) — NOT this envelope. The agent surfaces the menu to the user; the user picks; chain to log10x_cost_options for the action-level breakdown. **Action-shaped tool — calibration honesty**: the envelope's `recommendation_basis` tells the agent WHERE the capability detection came from (envs.json, snapshot, env vars, or unknown). `recommendation_audit.capability_sources` carries the per-field source, and `snapshot_age_seconds` carries snapshot staleness. The agent SHOULD NOT auto-route to the chosen sub-tool until the user picks an option, and SHOULD verify the basis before treating capability detection as authoritative (e.g., a stale snapshot may mis-flag mute as enabled when the receiver was uninstalled). See `docs/cross-pillar-primitives.md` for the agent behavior contract. **Call this** when a previous tool surfaced a high-cost pattern and the user asks 'what should I do' / 'how do I drop this' / 'how do I reduce this'.",
      "annotations": {
        "title": "Pattern mitigate",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "drop"
    },
    "log10x_advise_compact": {
      "title": "Advise: compact-lookup PR",
      "description": "Emit a literal `gh` PR command + the file diff for a compactReceiver change against the customer's GitOps repo. Two modes: `mode=csv` (default) edits `compact-lookup.csv` — the engine hot-reloads on each gitops poll (no pipeline restart, no event drops); `mode=js` replaces `compact-object-global.js` with new predicate logic — the engine triggers `restartPipeline()`. Use `js` only when CSV-keyed lookup is insufficient (regex match, multi-field-set OR semantics, external-flag gate). The compactReceiver decides per-event whether each event is emitted via `encode()` (compact templateHash+vars, ~20-40x volume reduction) or as `fullText`, keyed off `compactReceiverFieldNames` (default: `[symbolMessage]`). This tool is a renderer, not a decider: the caller decides which patterns to compact (typically via `log10x_top_patterns` filtered to high-volume rows) and passes the lists in. Output is markdown with a diff summary, the new full file content, and two ready-to-run shell snippets. Pass either `gitops_repo` directly OR `snapshot_id` (from `log10x_discover_env`) — when given a snapshot, the tool auto-resolves the repo from a running receiver pod's `GH_REPO` env var.",
      "annotations": {
        "title": "Advise: compact-lookup PR",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_measure_compaction": {
      "title": "Measure compaction",
      "description": "Measure real per-pattern compaction ratios from a SIEM sample. Pulls `sample_size` events for a service over `timeRange`, runs them through the local tenx engine, and returns per-pattern `compaction_ratio_x` (original bytes / encoded bytes) derived from actual measurements. Use this to replace generic 5-10x estimates in `log10x_estimate_savings` and `log10x_pattern_detail` with measured values for this customer environment. Requires: tenx CLI installed locally (LOG10X_TENX_PATH or `tenx` on PATH) AND SIEM credentials (same as `log10x_poc_from_siem`). Confidence tiers: high (>=50 events), medium (10-49), low (<10). Results flow into `log10x_estimate_savings` to improve savings projections. REQUIRES a local engine: the tenx binary on PATH, or Docker with LOG10X_TENX_MODE=docker.",
      "annotations": {
        "title": "Measure compaction",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "detect"
    },
    "log10x_setup_recurring": {
      "title": "Set up recurring cost-reduction",
      "description": "Conversational wizard that configures a recurring autonomous cost-reduction agent. Walks the user through seven decisions — target services, savings target (%), tick schedule, scheduler runtime, gitops config repo, exception services, and final confirm — then emits two ready-to-commit artifacts: `policy.yaml` (the declarative policy the tick CLI consumes) and a scheduler manifest (Kubernetes CronJob YAML, GitHub Actions workflow, or crontab entry + wrapper script depending on the chosen scheduler). Each call merges the latest answer into the wizard session and either asks the next missing question or emits the artifacts once all answers are present. Re-invoke with the same `session_id` on every subsequent turn; sessions live 30 minutes. To skip interactive Q&A, supply all fields (`target_services`, `target_percent`, `schedule`, `scheduler`, `config_plane`, `confirm: true`) in a single call. Optional overrides: `exceptions` (services never touched), `min_delta_pp` (minimum savings delta before committing a new CSV, default 2pp), `env_id`, `namespace`, `secret_name`. Apply instructions for the chosen scheduler are in `data.apply_instructions`. After the first tick runs, call `log10x_commitment_report` to verify realized savings. REQUIRES nothing deployed to ASK: it renders manifests from your answers and writes to no account. The emitted tick needs a scheduler runtime (k8s CronJob, GitHub Actions, crontab, EventBridge, Container Apps job) and a policy repo or S3 prefix you control before it runs.",
      "annotations": {
        "title": "Set up recurring cost-reduction",
        "readOnlyHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      },
      "category": "install"
    },
    "log10x_dev_restart": {
      "title": "Restart MCP server (dev only)",
      "description": "DEV ONLY — only registered when LOG10X_DEV_MODE=true. Exits the MCP server process after returning a confirmation envelope; the MCP host respawns the process so the updated build loads. Call with no arguments. Re-fetch tool schemas after the respawn — the new process may expose a different tool set. Never visible in production builds.",
      "annotations": {
        "title": "Restart MCP server (dev only)",
        "readOnlyHint": true,
        "idempotentHint": false,
        "openWorldHint": false
      },
      "category": "orient"
    }
  }
}
