Recommend
After Discover env ran, pick the right Log10x app to deploy and get its plan.
It 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).
On a serverless snapshot (Lambda functions running an OTel collector extension, no reachable cluster) the Kubernetes wizard is skipped entirely: the tool returns the Extension plan, collector splice, engine environment, CDK construct, and the Coralogix TCO policy path.
An Azure serverless snapshot (Function Apps, no cluster, no Lambda) returns the Streams plan instead: Event Hub setup, the certified collector configuration, and the engine environment. Function Apps offer no process slot, so regulation runs centrally.
With log_destination: "datadog", a Receiver plan adds the step after the POC: the fleet default for every service the POC report gives no rule. The step prints the Flex index with its @routeState:tier_down filter as Terraform (or the S3 branch for offload), states the always-pass sample of up to 1,800 lines a day of every statement on each node, and says what an error monitor sees. The limit comes in as fleet_default.cap_bytes_per_window_per_node, the value log10x_poc_from_local or log10x_configure_engine returns with fleet_default; without it the plan writes no fleet default. k8s_team_label names the pod label whose value is the owning team, so the metrics carry tenx_team. The plan writes both only on an engine release that reads them.
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).
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`, and the one arg the wizard cannot infer. The snapshot is cached for 30 min. Call `log10x_discover_env` first when there is no snapshot yet."
},
"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",
"prometheus"
]
},
"description": "Where the engine emits TenXSummary metrics: the user's own TSDB(s), one or more of **prometheus**, **datadog**, **elastic**, **cloudwatch**. When omitted, the wizard asks, listing any backend whose agent discovery detected first. **log10x** (the Log10x-hosted TSDB) is for the public demo, not customer installs: it is never suggested, and is accepted only when the user explicitly asks for it. It then needs a user licence (`license_source: \"signin\"` or `\"paste\"`); on the default built-in Free tier it receives nothing. `airgapped: true` + `\"log10x\"` is rejected."
},
"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",
"prometheus"
]
},
"description": "Per-backend credential configuration, keyed by backend kind (one of: datadog, elastic, cloudwatch, prometheus; `log10x` needs none, since it authenticates with the licence JWT). 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": [
"builtin",
"signin",
"demo",
"paste"
],
"description": "How the engine is licensed. **Defaults to `\"builtin\"`** when omitted: the plan carries no licence and the engine runs its built-in Free tier (up to 10 nodes, no expiry, airgapped). Nothing is minted or stored, and no licence Secret is created. Pass **`\"signin\"`** when the user wants their own user-scoped licence: the wizard mints it via the user's Auth0 session and emits `signin_required` mode (chain through `log10x_signin_start`, then re-invoke) when no session exists. Pass **`\"paste\"`** with `license_jwt_paste: \"<jwt>\"` when the user already has a JWT. Pass **`\"demo\"`** only when the user explicitly asks for the anonymous 1-node, 14-day demo JWT. Every choice other than `builtin` adds a step that creates the licence Secret. Omitting this arg on a later call keeps the earlier choice."
},
"license_jwt_paste": {
"type": "string",
"description": "License JWT supplied by the user when `license_source: \"paste\"` (passing it alone implies `paste`). Minted 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`."
},
"log_destination": {
"type": "string",
"enum": [
"datadog",
"clickhouse",
"elasticsearch"
],
"description": "Where the forwarder ships the log events (not the metrics; `backends` is the metrics). `datadog` adds the step after the POC to a Receiver plan: the fleet default for every service the POC report gives no rule, with the Flex index and its `@routeState:tier_down` filter (or the S3 branch for offload), the always-pass sample, and what an error monitor sees. `clickhouse` installs the Receiver the rows run (log10x_setup_recurring `rows_per_hour`) holds: limits and totals in lines, `tenx_hash` on every record. `elasticsearch` installs the Receiver the hot-tier run (log10x_setup_recurring `hot_tier_gb`) holds: limits in bytes, and `tenx_hash` and `utf8Size` (the size the limits count) on every record it returns."
},
"fleet_default": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"tier_down",
"offload"
],
"description": "Where a statement above the fleet limit goes: `tier_down` (Flex, the default where the account has Flex) or `offload` (S3)."
},
"error_floor": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Share of ERROR and CRITICAL lines above the limit that stay in Standard. Default 0.5 with offload, 0 with tier_down."
},
"cap_bytes_per_window_per_node": {
"type": "number",
"exclusiveMinimum": 0,
"description": "The limit in the engine's unit, as `log10x_configure_engine` or `log10x_poc_from_local` with `fleet_default` returns it (`fleet_default.cap_bytes_per_window_per_node`). Without it the plan writes no fleet default."
},
"cap_events_per_window_per_node": {
"type": "number",
"exclusiveMinimum": 0,
"description": "The same limit in lines per window per node (`fleet_default.cap_events_per_window_per_node` from `log10x_configure_engine`). Written instead of the byte limit when the Receiver counts events (Datadog on engine 1.1.146 or later)."
}
},
"additionalProperties": false,
"description": "The fleet default for a Datadog Receiver plan (with `log_destination: \"datadog\"`). The Receiver values are written only on an engine release that reads `rateReceiverDefaultAction`."
},
"regulator_unit": {
"type": "string",
"enum": [
"bytes",
"events"
],
"description": "What a Datadog Receiver's limits and totals count. `events` (the default on engine 1.1.146 or later, as Datadog bills Standard per event) is written as `rateReceiverUnit events` and recorded in the policy ConfigMap, where the budget run checks it. `bytes` keeps byte limits for log10x_configure_engine plans."
},
"policy_git": {
"type": "object",
"properties": {
"repo": {
"type": "string",
"pattern": "^[\\w.-]+\\/[\\w.-]+$",
"description": "The policy repo on GitHub, owner/name (GH_REPO)."
},
"branch": {
"type": "string",
"minLength": 1,
"description": "The dedicated branch the Receiver pulls and the budget run commits to (GH_BRANCH). Default: log10x-policy."
},
"token_secret": {
"type": "string",
"minLength": 1,
"description": "The Secret holding GH_TOKEN for the Receiver. Default: log10x-policy-git."
}
},
"required": [
"repo"
],
"additionalProperties": false,
"description": "Receiver: pull the policy files (caps, actions, totals, config-generation) from `log10x/policy/` on a git branch with GH_ENABLED, instead of the policy ConfigMap. For buyers who cannot run the budget run in the cluster: its GitHub Actions run commits to that branch. The plan seeds the four files on the branch before the Receiver starts."
},
"keep_count": {
"type": "integer",
"minimum": 0,
"description": "Datadog Receiver: error lines over a limit that still pass, per statement per node per 4-minute window (`rateReceiverKeepCounts`, one entry each for ERROR, CRITICAL and FATAL), on engine 1.1.146 or later. Default 50."
},
"service_actions": {
"type": "object",
"additionalProperties": {
"type": "string",
"enum": [
"tier_down",
"offload"
]
},
"description": "Datadog Receiver: where each service's lines over its limit go, as the POC report or log10x_configure_engine planned them. Any `offload` keeps half of the error lines over a limit in Standard on engines before 1.1.146 (S3 has no monitors)."
},
"k8s_team_label": {
"type": "string",
"description": "A pod label key whose value names the owning team (e.g. `team`). Receiver plans write `k8sTeamLabel` with it, on an engine release that reads that option, so the metrics carry `tenx_team`."
}
},
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}
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'
| 'serverless_plan'
| 'azure_serverless_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 === 'serverless_plan'
estate?: 'serverless';
function_count?: number;
functions_with_otel_extension?: number;
log_groups_unsubscribed?: number;
// mode === 'azure_serverless_plan'
function_app_count?: number;
container_app_count?: number;
event_hub_namespace_count?: number;
// 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).