Skip to content

Recommend

After Discover env ran, pick the right Log10x app to deploy and get its plan. Returns a ranked comparison across Reporter, Receiver, and Retriever when no goal is set, or a single concrete checklist when a goal is given (cut-cost, compact, archive, just-metrics).

Example

You

ranked install paths for snap-abc123

Log10x

Top pick: Reporter (standalone DaemonSet). No forwarder changes required.

Path Status Why
Reporter standalone ✓ ready parallel DaemonSet, no forwarder edits
Receiver inline (filter) ✓ ready fluent-bit detected, Helm-managed
Receiver inline (compact) ✓ ready fluent-bit + Helm + verified path
Retriever ✗ blocked missing S3 bucket, SQS queues, IRSA role

Re-run with goal=cut-cost (or compact / archive / just-metrics) for a concrete plan instead of a comparison.

More to ask

  • "concrete plan: cut logging costs"
  • "compact-mode plan, fluent-bit"
  • "archive plan with lx_live_... key"

Prerequisites

A fresh snapshot_id from Discover env. No Log10x components needed.

Schema and samples

Input example

Representative call (synthetic, not captured from the live demo env).

{
  "snapshot_id": "snap-abc123",
  "app": "receiver",
  "forwarder": "fluentbit",
  "backends": ["log10x"]
}
Input schema

Agent-facing JSON Schema (the canonical shape the MCP server publishes via tools/list):

{
  "type": "object",
  "properties": {
    "snapshot_id": {
      "type": "string",
      "description": "ID returned by `log10x_discover_env`. The snapshot is cached for 30 min."
    },
    "app": {
      "type": "string",
      "enum": [
        "reporter",
        "receiver"
      ],
      "description": "Which Log10x app to install. **reporter** = a dedicated DaemonSet forwarder (zero-touch, runs alongside your existing forwarder); **receiver** = a sidecar plugged into your existing forwarder (filters/samples/compacts events in-flight). When omitted, the wizard asks the user."
    },
    "forwarder": {
      "type": "string",
      "enum": [
        "fluentbit",
        "fluentd",
        "filebeat",
        "logstash",
        "otel-collector",
        "vector"
      ],
      "description": "Receiver-only: which detected forwarder kind to sidecar into. Auto-uses the snapshot's detected forwarder when there's exactly one; the wizard asks when there are multiple."
    },
    "backends": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "log10x",
          "datadog",
          "elastic",
          "cloudwatch",
          "signalfx",
          "prometheus"
        ]
      },
      "description": "Where the engine emits TenXSummary metrics. Multi-destination — a user can report to log10x SaaS AND their own backend simultaneously, e.g. `[\"log10x\", \"datadog\"]`. Choices: **log10x** (Log10x-managed Prometheus — recommended; no infra to run), **datadog**, **elastic**, **cloudwatch**, **signalfx**, **prometheus** (customer-owned). The wizard pre-fills detected backends from the snapshot. The only mutual exclusion is `airgapped: true` + `\"log10x\"` in this list."
    },
    "airgapped": {
      "type": "boolean",
      "description": "When true, the Log10x agents send nothing to log10x.com — engine metrics, license re-validation, and update checks all go silent. Use to reduce CISO friction. Conflicts with `\"log10x\"` in `backends` (the wizard surfaces the conflict). **Demo licenses cannot actually run airgapped** — the engine downgrades to online mode with a warning. The wizard surfaces this softly when both are picked."
    },
    "backend_credentials": {
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "properties": {
          "secretName": {
            "type": "string",
            "description": "Name of the Kubernetes Secret holding sensitive env vars for this backend."
          },
          "plainValues": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Non-sensitive env var overrides keyed by env var name (e.g., `{ DD_SITE: \"us5.datadoghq.com\" }`)."
          }
        },
        "required": [
          "secretName"
        ],
        "additionalProperties": false
      },
      "propertyNames": {
        "enum": [
          "log10x",
          "datadog",
          "elastic",
          "cloudwatch",
          "signalfx",
          "prometheus"
        ]
      },
      "description": "Per-backend credential configuration, keyed by backend kind (must be one of: log10x, datadog, elastic, cloudwatch, signalfx, prometheus). **Only set for non-`log10x` backends** — `log10x` SaaS uses the license JWT and needs no extra credentials. Each entry has a `secretName` (the Kubernetes Secret the user creates out-of-band holding sensitive env vars like `DD_API_KEY`; default per backend is `<backend>-credentials`) and optional `plainValues` (overrides for non-sensitive env vars like `DD_SITE`). Example: `{ \"datadog\": { \"secretName\": \"datadog-secret\", \"plainValues\": { \"DD_SITE\": \"us5.datadoghq.com\" } } }`."
    },
    "license_source": {
      "type": "string",
      "enum": [
        "signin",
        "demo",
        "paste"
      ],
      "default": "signin",
      "description": "How the wizard should acquire the engine's license JWT. **Defaults to `\"signin\"`** when omitted — the wizard tries to mint a user-scoped license via the user's Auth0 session, and emits `signin_required` mode (chain through `log10x_signin_start` then re-invoke) when no session exists. Pass **`\"demo\"`** ONLY when the user explicitly asks for a quick 14-day anonymous demo (transient, can't run airgapped). Pass **`\"paste\"`** with `license_jwt_paste: \"<jwt>\"` when the user already has a JWT."
    },
    "license_jwt_paste": {
      "type": "string",
      "description": "License JWT supplied by the user when `license_source: \"paste\"`. Mints from `POST /api/v1/license` (signed-in) or `POST /api/v1/license/demo` (anonymous). Maps to the chart's license Secret."
    },
    "namespace": {
      "type": "string",
      "description": "Target namespace. Default: snapshot.recommendations.suggestedNamespace."
    },
    "release_name": {
      "type": "string",
      "description": "Helm release name. Default: `my-<app>` (e.g., `my-reporter`)."
    },
    "action": {
      "type": "string",
      "enum": [
        "install",
        "verify",
        "teardown",
        "all"
      ],
      "description": "Plan scope when the wizard is ready to emit. Default: `all`."
    }
  },
  "required": [
    "snapshot_id"
  ],
  "additionalProperties": false
}

Source: src/tools/advise-install.ts.

Output example

Representative envelope (synthetic, not captured from the live demo env). view: "summary" returns the full StructuredOutput with typed data.

Headline (the 1-line agent-facing answer):

receiver all plan on fluentbit: 6 install / 4 verify / 3 teardown, release "my-receiver" in namespace "logging".

{
  "schema_version": "1.0",
  "schema_epoch": "engine-1.0.9",
  "tool": "log10x_advise_install",
  "view": "summary",
  "summary": {
    "headline": "receiver all plan on fluentbit: 6 install / 4 verify / 3 teardown, release \"my-receiver\" in namespace \"logging\"."
  },
  "data": {
    "mode": "plan",
    "ok": true,
    "app": "receiver",
    "snapshot_id": "snap-abc123",
    "release_name": "my-receiver",
    "namespace": "logging",
    "forwarder": "fluentbit",
    "action": "all",
    "preflight": [
      { "name": "namespace exists", "status": "ok", "detail": "logging present" },
      { "name": "helm release detected", "status": "ok", "detail": "fluent-bit v0.46.0" }
    ],
    "preflight_summary": { "ok": 2, "warn": 0, "fail": 0, "unknown": 0 },
    "install_step_count": 6,
    "install_file_count": 2,
    "install_requires_chmod": false,
    "license_kind": "user-scoped",
    "install_mode": "upgrade-existing",
    "existing_helm_release": { "name": "fluent-bit", "namespace": "logging" },
    "verify_probe_count": 4,
    "verify_probes": [
      {
        "name": "engine pod Ready",
        "question": "Is the Log10x sidecar Ready?",
        "commands": ["kubectl -n logging get pods -l app=fluent-bit"],
        "expectOutput": "1/1 Running",
        "timeoutSec": 60
      }
    ],
    "teardown_step_count": 3,
    "blockers": [],
    "notes": [
      "license JWT pre-filled from signed-in user session",
      "metrics emit to log10x SaaS via license JWT"
    ],
    "has_gitops_section": false,
    "human_summary": "Install wizard produced a receiver all plan on fluentbit for release \"my-receiver\" in namespace \"logging\". 6 install steps across 2 files, 4 verify probes. Preflight: 2 ok, 0 warn, 0 fail.",
    "markdown": "# Receiver install plan\n\n..."
  },
  "actions": [
    {
      "tool": "log10x_doctor",
      "args": {},
      "reason": "verify the install once the helm release rolls out, checks engine pods Ready, metrics flowing, license-Secret mounted",
      "role": "optional-followup"
    },
    {
      "tool": "log10x_top_patterns",
      "args": {},
      "reason": "once events are flowing, see which patterns dominate cost and offer mitigation via log10x_pattern_mitigate",
      "role": "optional-followup"
    }
  ],
  "warnings": [],
  "truncated": false
}
Output schema

The data block inside the StructuredOutput envelope:

interface ToolData {
  // Discriminated union over every wizard outcome. Agents read
  // `data.mode` and narrow to the per-mode shape.
  mode:
    | 'plan'
    | 'next_question'
    | 'missing_snapshot'
    | 'session_error'
    | 'cancelled'
    | 'license_error'
    | 'signin_required'
    | 'demo_airgapped_warning'
    | 'unknown_args';
  ok: boolean;
  snapshot_id?: string;
  markdown: string;
  human_summary: string;

  // mode === 'next_question'
  question_id?:
    | 'app'
    | 'forwarder'
    | 'no-forwarder'
    | 'backends'
    | 'airgapped-log10x-conflict'
    | 'backend-credentials'
    | 'airgapped'
    | 'license-paste';
  shape?: unknown;

  // mode === 'license_error'
  error_message?: string;

  // mode === 'demo_airgapped_warning'
  is_signed_in?: boolean;

  // mode === 'unknown_args'
  unknown_keys?: string[];
  suggestions?: Array<{ unknown: string; did_you_mean: string | null }>;
  valid_keys?: string[];

  // mode === 'plan', fields below come from AdvisePlanSummary.
  app?: 'reporter' | 'receiver' | 'retriever';
  release_name?: string;
  namespace?: string;
  forwarder?: string;
  action?: 'install' | 'verify' | 'teardown' | 'all';
  preflight?: Array<{
    name: string;
    status: 'ok' | 'warn' | 'fail' | 'unknown';
    detail: string;
  }>;
  preflight_summary?: { ok: number; warn: number; fail: number; unknown: number };
  install_step_count?: number;
  install_file_count?: number;
  install_requires_chmod?: boolean;
  license_kind?: 'user-scoped' | 'demo' | 'user-pasted' | 'placeholder';
  install_mode?: 'upgrade-existing' | 'fresh-release';
  existing_helm_release?: { name: string; namespace: string };
  verify_probe_count?: number;
  verify_probes?: Array<{
    name: string;
    question: string;
    commands: string[];
    expectOutput?: string;
    timeoutSec?: number;
  }>;
  teardown_step_count?: number;
  blockers?: string[];
  notes?: string[];
  has_gitops_section?: boolean;
}

Envelope-level fields the agent should also read: summary.headline (1-line answer), actions[] (next-call chain hints as {tool, args, reason}, e.g. log10x_doctor post-install, log10x_signin_start when signin is required), truncated: boolean, warnings[] (plan blockers, demo-license caveats), schema_epoch (engine-ID stability boundary).