Skip to navigation

Planner Configuration (PlannerConfig)

Field reference for the PlannerConfig JSON/YAML object consumed by the Dynamo Planner service.

View as Markdown

PlannerConfig is the configuration object for the Dynamo Planner. The Planner service parses it with Pydantic, so every field, type, default, and constraint on this page comes from the PlannerConfig model. For the deployment workflow and scaling-mode concepts, see the Planner Guide; for the autoscaler overview, see the Planner overview.

How the config is loaded

The Planner service loads PlannerConfig from a single required --config argument — a path to a .json, .yaml, or .yml file, or an inline JSON string. The service auto-detects which, loads it, and validates it against the PlannerConfig model. A value that is neither a readable file nor valid JSON fails at startup. How you supply it depends on where you run the Planner.

Set the object under spec.features.planner in a DynamoGraphDeploymentRequest (DGDR). DGDR passes it through without field-level validation, mounts it as a planner-config-* ConfigMap, and launches the Planner with --config pointing at the mounted file. The Planner validates it at startup. Every field below can be set here.

spec:
features:
planner:
mode: disagg
backend: vllm
# optimization_target defaults to "throughput" — works with no further config

Several Prometheus fields default from environment variables and are excluded when the config is serialized back out. Set them either in the config object or through the environment variable noted on each field. See Environment variables.

Core settings

mode
stringDefaults to disagg

Planner operating mode, matching the deployment topology.

Allowed values: disagg prefill decode agg
backend
stringDefaults to vllm

Inference backend the Planner scales.

Allowed values: vllm sglang trtllm mocker
environment
stringDefaults to kubernetes

Runtime environment that determines how the Planner applies scaling actions.

Allowed values: kubernetes virtual global-planner
namespace
stringDefaults to env DYN_NAMESPACE, else dynamo

Dynamo namespace of the deployment the Planner manages. Defaults from DYN_NAMESPACE, which the operator injects as {k8s_namespace}-{dgd_name}. Excluded from serialized output.

model_name
stringDefaults to null

Optional model name override. Auto-detected from the deployment when unset.

global_planner_namespace
stringDefaults to null

Namespace where the GlobalPlanner runs. Required when environment is global-planner. See the Global Planner Guide.

log_dir
stringDefaults to null

Optional directory for Planner log output.

Optimization target

optimization_target
stringDefaults to throughput

Scaling strategy. throughput and latency use static thresholds on queue depth and KV cache utilization — no SLA targets or profiling required. load uses user-defined prefill queue-token and decode KV-utilization thresholds. sla uses the Planner engine-query layer and AIC core performance model to target specific ttft_ms / itl_ms values.

Allowed values: throughput latency load sla

When optimization_target is throughput, latency, or load, the Planner forces load-based scaling on and throughput-based scaling off, and it ignores ttft_ms / itl_ms. The two scaling-mode flags below apply only when optimization_target is sla.

enable_throughput_scaling
booleanDefaults to true

Enable predictive, traffic-based scaling. Only honored when optimization_target is sla.

enable_load_scaling
booleanDefaults to false

Enable reactive, load-based scaling. Only honored when optimization_target is sla. At least one scaling mode must be enabled.

ttft_ms
numberDefaults to 500.0

Time To First Token SLA target, in milliseconds. Also accepts the alias ttft. Must be greater than 0. Used only under optimization_target: sla.

itl_ms
numberDefaults to 50.0

Inter-Token Latency SLA target, in milliseconds. Also accepts the alias itl. Used only under optimization_target: sla.

Performance model and pre-deployment sweeping

pre_deployment_sweeping_mode
stringDefaults to rapid

How to generate optional bootstrap performance data. none skips bootstrap data; rapid uses AIConfigurator to simulate engine performance (~30s); thorough measures on real GPUs (several hours).

Allowed values: none rapid thorough
profile_results_dir
stringDefaults to profiling_results

Directory holding profiler-generated performance data (npz or JSON), used to bootstrap or tune the performance model when the get_perf_metrics endpoint is unavailable.

ais_perf_model
AISPerfModelSpecDefaults to null

Role-indexed AISimulate forward-pass configurations. Constructs each model through aisimulate_core.sdk.RustForwardPassPerfModel.best_available(config) without an interpolation sweep. Configure model identity and estimator controls through ais_perf_model.roles, or select local dataset manifests with dataset_profiles; the retired aic_perf_model and hf_id / pick shape are rejected.

roles
objectDefaults to {}

Maps deployment roles to complete upstream ForwardPassPerfModelConfig objects. Supply prefill and decode for disagg, the matching single role for prefill or decode, and aggregated for agg. Each key must match worker_type. Each required role must appear in exactly one of roles and dataset_profiles.

dataset_profiles
objectDefaults to {}

Maps prefill, decode, or aggregated to an execution-profile manifest in a local AISimulate dataset. The manifest supplies the complete canonical configuration; Planner does not override its model, runtime, or pin.

dataset_profiles.<role>.root
string

Required absolute path to the dataset snapshot already installed in the container. Planner performs no downloads and needs no Hugging Face credentials.

dataset_profiles.<role>.manifest
string

Required path relative to root, selecting an execution-profile manifest for that role. AISimulate validates artifact hashes, the compiled graph, and retained inputs. Planner prepares a private temporary directory once per role/source and retains it across worker-limit changes. Provide writable temporary storage and bundled or existing local model metadata. Restart Planner to adopt changed dataset contents.

roles.<role>.model / system / backend
stringRequired

Model identifier, AISimulate system identifier, and inference backend (vllm, sglang, or trtllm). Optional backend_version, tp, pp, attention_dp, MoE axes, quantization, KV block size, and speculation fields use the upstream schema. Published worker capabilities must agree with the configured identity.

roles.<role>.estimation_mode
stringDefaults to auto

auto searches op_level, fpm_interpolation, then fpm_regression. Explicit modes select the named estimator.

roles.<role>.fallback_policy
stringDefaults to deny

deny rejects failure of an explicitly selected mode. allow tries the other modes in op_level, fpm_interpolation, fpm_regression priority order; regression permits a regression fallback. Auto selection searches the full priority order even with deny.

roles.<role>.systems_paths
list[string]Defaults to []

Ordered performance-data roots. The SDK resolves its packaged root when unset. database_mode and transfer_policy are also passed through unchanged.

roles.<role>.estimator_config
objectDefaults to {}

Complete upstream estimator controls, including independent regression and correction sampling, fit settings, feature weights, and correction bounds. Explicit settings override Planner sampling defaults. A legacy total bucket count of 16 maps to bins_per_axis: [4, 4]. Unknown fields are rejected by AISimulate. See the AISimulate core API.

Local execution-profile datasets

Download the AISimulate dataset snapshot into the container image during the image build, or mount a local copy before starting Planner. Use the generic AISimulate wheel; measurements do not belong inside the wheel. Use matching AISimulate Python and Rust releases that support execution profiles through the common forward-pass query API. This integration pins Python 0.13.0.dev202610290000000087 and Rust 0.13.0-dev.202610290000000087, which include that support. Use version-2 execution profiles; version 1 retains its legacy direct-phase queries and must be explicitly migrated and repinned.

The following configuration illustrates the paths to supply for a prefill role:

mode: prefill
pre_deployment_sweeping_mode: none
ais_perf_model:
dataset_profiles:
prefill:
root: /opt/aisim-data
manifest: metadata/prefill-manifest.json

Set the paths to the installed snapshot and its selected manifest. For disaggregated serving, supply separate prefill and decode sources. For mode: agg, use an aggregated source whose profile contains both phase graphs. Canonical prepared configs containing estimator_config.op_level.execution_profile also work through roles.

Planner applies its existing workload estimates, including queue scaling, prefix-cache discounts, and next-request estimates, before calling AISimulate’s common forward-pass query API. The prediction path is the same for built-in and external inputs, including mixed steps. If it cannot estimate the resulting shape, Planner skips scaling decisions that depend on that estimate.

aic_interpolation
AICInterpolationSpecDefaults to null

AIConfigurator interpolation spec. Populated by the profiler in rapid mode and written onto the Planner ConfigMap; you do not normally set this by hand. When present, the Planner runs the AIC sweep in-process at bootstrap to seed the performance model. See AICInterpolationSpec.

GPU budget

max_gpu_budget
integerDefaults to 8

Maximum total GPUs the Planner may allocate across worker types.

min_gpu_budget
integerDefaults to -1

Per-DGD GPU floor enforced by the local Planner. -1 disables it. When set with max_gpu_budget such that min == max, the Planner pins the per-DGD total and only redistributes replicas between prefill and decode.

min_endpoint
integerDefaults to 1

Minimum engine endpoints (replicas) for aggregated deployments. In disaggregated deployments, this value applies to both prefill and decode unless a role-specific value is set. In prefill-only or decode-only deployments, it supplies the active role when the corresponding role-specific value is unset. Must be nonnegative; use 0 for scale-to-zero compatibility.

prefill_min_endpoint
integerDefaults to null

Minimum prefill endpoints in disagg and prefill modes. When set, replaces the prefill value supplied by min_endpoint. Must be at least 1.

decode_min_endpoint
integerDefaults to null

Minimum decode endpoints in disagg and decode modes. When set, replaces the decode value supplied by min_endpoint. Must be at least 1.

The Planner does not have per-component maximum endpoint fields. max_gpu_budget, the power budget when enabled, Global Planner allocation, and cluster capacity continue to bound scale-up. At startup and for runtime updates, the Planner rejects minimum endpoint combinations that cannot fit the configured GPU or power budget. Send min_gpu_budget and max_gpu_budget with the endpoint fields to PATCH /v1/min-endpoints to update them atomically at runtime. Set either budget to -1 to disable that bound. When both budgets are enabled, min_gpu_budget must not exceed max_gpu_budget. The response from GET or PATCH includes both budgets.

decode_engine_num_gpu
integerDefaults to null

GPUs per decode engine replica. Auto-detected from the deployment when unset.

prefill_engine_num_gpu
integerDefaults to null

GPUs per prefill engine replica. Auto-detected from the deployment when unset.

Throughput-based scaling

throughput_adjustment_interval_seconds
integerDefaults to 180

Seconds between throughput-based scaling decisions. Also accepts the alias throughput_adjustment_interval.

max_throughput_scaling_replicas
integerDefaults to 8

Maximum replica-count change per component from one throughput observation. The Planner caps and stores the throughput lower bound, so load-scaling ticks cannot repeatedly apply the same uncapped prediction. GPU and power budgets can reduce the change further. At the nominal minimum GPU budget, scale-down-only requests hold. At a full GPU budget, two scale-up requests hold; an opposing prefill/decode proposal applies only the largest atomic pair that fits the budget. Endpoint and out-of-band budget recovery take precedence over this limit. Must be greater than 0.

throughput_metrics_source
stringDefaults to frontend

Prometheus traffic source. frontend reads dynamo_frontend_* metrics from the public Frontend; router reads dynamo_component_router_* from a LocalRouter (use for a pool-local Planner in GlobalPlanner deployments).

Allowed values: frontend router

Load-based scaling

load_adjustment_interval_seconds
integerDefaults to 5

Seconds between FPM tuning updates and load-based scaling decisions. Even when only throughput scaling is enabled, live FPM observations feed the performance model at this interval. Also accepts the alias load_adjustment_interval. Must be greater than 0 and, when both scaling modes are on, shorter than throughput_adjustment_interval_seconds.

max_num_fpm_samples
integerDefaults to 64

Maximum retained ForwardPassMetrics observations for online tuning and regression fallback.

fpm_sample_bucket_size
integerDefaults to 16

Number of buckets for observation retirement. Must be a perfect square.

load_scaling_down_sensitivity
integerDefaults to 80

Scale-down sensitivity from 0 to 100 (0 = never scale down, 100 = aggressive).

load_min_observations
integerDefaults to 5

Minimum observations before load-based scaling decisions begin (cold-start threshold).

prefill_scale_up_queue_tokens
integerDefaults to null

Prefill queue-token count that triggers scale-up. Required (with the scale-down field) when optimization_target is load and mode includes prefill. Must be greater than 0 and greater than prefill_scale_down_queue_tokens.

prefill_scale_down_queue_tokens
integerDefaults to null

Prefill queue-token count that allows scale-down. Required alongside prefill_scale_up_queue_tokens.

decode_scale_up_kv_rate
numberDefaults to null

Decode KV-utilization percentage (0–100) that triggers scale-up. Required (with the scale-down field) when optimization_target is load and mode includes decode. Must be greater than decode_scale_down_kv_rate.

decode_scale_down_kv_rate
numberDefaults to null

Decode KV-utilization percentage (0–100) that allows scale-down. Required alongside decode_scale_up_kv_rate.

speculative_nextn
integerDefaults to 0

Manual fallback speculative-decoding depth. A worker’s published runtime_config.runtime_data.spec_decode.nextn takes precedence when present. Must be 0 or greater.

Load prediction

load_predictor
stringDefaults to arima

Prediction method for request count, ISL, and OSL.

Allowed values: constant arima kalman prophet
load_predictor_log1p
booleanDefaults to false

Apply a log1p transform to predicted request count, ISL, and OSL.

prophet_window_size
integerDefaults to 50

Window size (seconds) for the Prophet predictor.

load_predictor_warmup_trace
stringDefaults to null

Path to a warmup trace file for bootstrapping predictions.

kalman_q_level
numberDefaults to 1.0

Kalman process noise for the level component.

kalman_q_trend
numberDefaults to 0.1

Kalman process noise for the trend component.

kalman_r
numberDefaults to 10.0

Kalman measurement noise.

kalman_min_points
integerDefaults to 5

Minimum data points before Kalman predictions activate.

Prometheus metrics

These fields default from environment variables and are excluded from serialized output. Set them in the config object or through the noted environment variable.

metric_pulling_prometheus_endpoint
stringDefaults to env PROMETHEUS_ENDPOINT

Prometheus endpoint the Planner queries for traffic metrics. Defaults to PROMETHEUS_ENDPOINT, else http://prometheus-kube-prometheus-prometheus.monitoring.svc.cluster.local:9090.

metric_pulling_prometheus_token
stringDefaults to env PROMETHEUS_TOKEN

Optional bearer token sent as Authorization: Bearer <token> on every PromQL request. Read once at startup.

metric_pulling_prometheus_token_file
stringDefaults to env PROMETHEUS_TOKEN_FILE

Path to a file containing a bearer token, re-read before every request so rotated tokens are picked up without a restart.

metric_pulling_prometheus_ssl_verify
booleanDefaults to false

Verify the upstream Prometheus TLS certificate. Defaults from PROMETHEUS_SSL_VERIFY (1/true/yes enable it). Pair with a CA bundle for a private CA.

metric_pulling_prometheus_extra_query_params
objectDefaults to env PROMETHEUS_EXTRA_QUERY_PARAMS

Fixed key/value pairs appended as URL query parameters on every PromQL request. Set PROMETHEUS_EXTRA_QUERY_PARAMS as a URL query string, for example namespace=my-ns&tenant=foo.

metric_pulling_prometheus_ca_bundle
stringDefaults to env PROMETHEUS_CA_BUNDLE

Path to a CA bundle for verifying the upstream Prometheus TLS certificate. When set, the bundle is used for verification regardless of metric_pulling_prometheus_ssl_verify. Must point to an existing file.

metric_pulling_prometheus_request_timeout_seconds
numberDefaults to 10.0

Connection and read inactivity timeout in seconds for each Prometheus API request. Defaults from DYN_PLANNER_PROMETHEUS_REQUEST_TIMEOUT_SECONDS and must be greater than 0. This is not a total wall-clock deadline: a response that continues delivering data can run longer. The Planner does not retry failed requests within the same collection cycle.

metric_reporting_prometheus_port
integerDefaults to 0

Port on which the Planner exposes its own dynamo_planner_* metrics. Defaults from PLANNER_PROMETHEUS_PORT. 0 disables.

Advisory mode

advisory
booleanDefaults to false

Suggestion-only mode. The Planner computes, logs, exports, and reports recommended replica counts and retune decisions without executing any of them or changing the deployment. Use it to evaluate a new configuration or validate SLA targets against production traffic. The runtime configuration APIs, such as PATCH /v1/min-endpoints, still change the Planner’s own settings.

Planner-in-the-loop replay honors it too: an advisory replay keeps the simulated deployment at its starting replicas and router parameters, reports the recommendations in planner.recommended_scaling_events, and records a retune decision that would apply with outcome advisory. See Replay in Advisory Mode.

Diagnostics and reporting

report_interval_hours
numberDefaults to 24.0

Generate an HTML diagnostics report every N hours (simulated time). Set to null to disable. Must be a positive finite number or null.

report_output_dir
stringDefaults to ./planner_reports

Directory for HTML diagnostics reports.

report_filename
stringDefaults to null

Fixed report filename written under report_output_dir. When unset, a timestamped name is used.

report_write_gzip_log
booleanDefaults to true

Write a compressed JSONL diagnostics log (.log.jsonl.gz) next to each HTML report.

live_dashboard_port
integerDefaults to 8080

Port for the live diagnostics dashboard HTTP server. 0 disables. When enabled, visit http://host:port/ for a real-time Plotly report.

Runtime configuration

control_api_port
integerDefaults to 9086

Port for the runtime minimum-endpoint API. The server listens only on 127.0.0.1; 0 disables it. Updates are process-local, are not persisted to the Planner ConfigMap, and take effect on the next planner tick.

Runtime minimum endpoint API

The Planner exposes GET /v1/min-endpoints and partial PATCH /v1/min-endpoints. The request and response fields depend on the active mode:

ModeRuntime fields
disaggprefill_min_endpoint, decode_min_endpoint
prefillprefill_min_endpoint
decodedecode_min_endpoint
aggmin_endpoint

The API has no authentication and is not exposed by a Kubernetes Service. For Kubernetes deployments, port-forward directly to the Planner pod:

kubectl port-forward pod/<planner-pod> 9086:9086
curl http://127.0.0.1:9086/v1/min-endpoints
curl --request PATCH http://127.0.0.1:9086/v1/min-endpoints \
--header 'Content-Type: application/json' \
--data '{"prefill_min_endpoint": 2}'

PATCH is atomic. Malformed JSON, unknown fields, and empty patches return HTTP 400. null, a negative min_endpoint, component-specific minimums below 1, fields that are inactive for the current mode, and minimums that exceed the configured GPU or power budget return HTTP 422 without changing the active configuration.

System-port reconfiguration API

enable_runtime_reconfiguration
booleanDefaults to false

Enable the Planner control API on the existing DYN_SYSTEM_PORT listener. The runtime must have a system listener enabled. Kubernetes Planner deployments configure this port as 9090.

runtime_warmup_trace_dir
stringDefaults to null

Directory containing permitted runtime warmup traces. Required when submitting warmup_trace; paths must remain inside this directory, and symlinks are rejected. This setting cannot be changed through the runtime API.

This API changes scaling behavior and has no application authentication. Restrict access to the system listener to trusted controllers and operators before enabling it. The existing localhost 9086 API remains available with its original configuration.

Method and pathResponse
GET /engine/planner/configApplied settings, instance_id, revision, and supported_fields.
PATCH /engine/planner/config202 with an operation ID after validation and admission.
GET /engine/planner/operations/{request_id}Operation state: preparing, warming, applied, or failed.

The supported configuration groups are:

GroupFields
Endpoint floors and GPU budgetsMode-specific minimum endpoint fields from the table above, min_gpu_budget, max_gpu_budget.
SLA targetsttft_ms, itl_ms.
Scaling policymax_throughput_scaling_replicas, load_scaling_down_sensitivity, prefill_scale_up_queue_tokens, prefill_scale_down_queue_tokens, decode_scale_up_kv_rate, decode_scale_down_kv_rate.
Load predictionload_predictor, load_predictor_log1p, prophet_window_size, kalman_q_level, kalman_q_trend, kalman_r, kalman_min_points.

Fields retain their normal mode-specific meaning. For example, the explicit queue/KV thresholds are used by optimization_target: load. Predictor replacement requires optimization_target: sla with throughput scaling enabled. Scheduling intervals, AIS performance models, deployment topology, and other fields are rejected by this API.

Use the instance ID and revision returned by GET when submitting an update:

{
"instance_id": "<instance_id from GET>",
"expected_revision": 0,
"request_id": "sweep-42",
"config": {
"ttft_ms": 800,
"load_predictor": "kalman",
"kalman_min_points": 5
},
"warmup_trace": "recent-traffic.jsonl"
}

config is a nonempty partial update. A predictor change requires either warmup_trace or explicit cold_start: true. The trace must be a single regular Dynamo/Mooncake JSONL or JSONL.GZ file inside runtime_warmup_trace_dir. Relative paths are resolved from that directory; absolute paths must also be inside it. Runtime warmup accepts at most 16 MiB of stored data and 16 MiB after decompression, and at most 4,096 aggregation intervals (including idle gaps). Directories and globs remain supported by the startup load_predictor_warmup_trace option but are rejected by runtime reconfiguration. Observations use the unchanged throughput adjustment interval. Warmup must provide enough effective samples for request count, ISL, and OSL and complete a successful forecast. SLA/budget-only updates do not require warmup. Supplying a trace explicitly also allows rewarming an unchanged predictor.

The active configuration continues serving while a candidate is prepared. Preparation has a 120-second deadline and only one preparation can run at a time. If a background fit outlives its deadline, its result cannot activate and further preparations are rejected until that work exits; updates that do not replace the predictor remain available. Invalid data, failed fitting, or a changed revision leave the active settings unchanged. Successful activation occurs between decisions and increments the revision. Updates preserve the existing prediction and scaling cadence, including changes to SLA targets, max_throughput_scaling_replicas, and predictor settings. The next scheduled throughput decision uses the active settings and the full trailing traffic window; predictor replacement does not delay that decision. Performance models, worker state, and already-admitted scaling operations are retained. applied means the configuration is active; it does not mean the deployment has finished scaling.

A successful write through the legacy minimum-endpoint API also changes the revision reported here. If it happens during preparation, the pending update fails with error_type: conflict. Updates are process-local and are not written to the Planner ConfigMap. A restart creates a new instance_id and restores startup settings. Address the intended Planner instance directly rather than distributing a conditional write across replicas.

Retry the identical request with the same request_id to retrieve its retained operation without applying it twice. The last 32 operations are retained in memory. Reusing an ID for different content returns 409; an evicted operation returns 404, so inspect the applied revision before submitting another update.

Malformed JSON returns 400; invalid or unsupported updates return 422; instance, revision, idempotency, and concurrent-update conflicts return 409; unavailable control returns 503. Requests exceeding 64 KiB return 413. Preparation failures after 202 are reported by the operation’s state, error, and error_type fields.

Scheduling and plugin pipeline

The Planner runs the builtin plugin pipeline by default. scheduling controls pipeline cadence; plugin_registration controls how plugins register, authenticate, and communicate. For the pipeline model, see the Planner Guide.

scheduling
SchedulingConfig

Plugin-pipeline scheduling. Rejects unknown fields.

scale_interval_seconds
numberDefaults to gcd of enabled builtin intervals

Base pipeline cadence. The pipeline wakes once per interval; each plugin’s execution_interval_seconds decides whether it fires. When unset, computed as the gcd of load_adjustment_interval_seconds and, when throughput scaling is enabled, throughput_adjustment_interval_seconds. Must be greater than 0 and evenly divide both adjustment intervals.

tick_max_duration_seconds
numberDefaults to 30.0

Outer wall-clock deadline wrapping the full 4-stage pipeline. Exceeding it aborts the tick; the next tick runs from a clean state. Replay does not apply it: a replayed tick runs to completion, however long it takes on the host. Must be greater than 0.

external_plugins
[]ExternalPluginEntryDefaults to []

Static external-plugin registrations applied at startup. Per-entry failures are logged but do not crash the Planner. See ExternalPluginEntry.

gateway
GatewayConfig

gRPC registration gateway for self-registering plugins. Disabled by default.

enabled
booleanDefaults to false

Open the gRPC gateway at listen. Not needed for static external_plugins.

listen
stringDefaults to unix:///var/run/dynamo/planner/registry.sock

Bind address. A unix: socket path for in-Pod registration, or host:port for TCP.

allow_insecure
booleanDefaults to false

Permit binding a plaintext (no-TLS) gateway on a TCP listen. Fails closed by default because the gateway receives plugins’ shared-secret tokens. unix: listens are always allowed.

plugin_registration
PluginRegistrationConfig

Plugin registry configuration — auth, transport, heartbeat, and in-process plugins. Rejects unknown fields.

auth
AuthConfig

Registry authentication. In the Planner process, an empty trusted_sources activates a legacy compatibility fallback to unauthenticated access and logs a warning. This fallback is DEV ONLY; do not rely on it as an intentional configuration. Select allow_unauthenticated explicitly for development. Production deployments must configure static_secret.

trusted_sources
[]stringDefaults to []

Accepted auth sources. Use ['allow_unauthenticated'] for development, or ['static_secret'] with static_secrets for production.

Allowed values: static_secret allow_unauthenticated
static_secrets
objectDefaults to {}

Map of secret_value to subject_label. Populate from a mounted Kubernetes Secret rather than hard-coding in the ConfigMap.

transport
TransportConfig

Outbound gRPC transport settings for calling plugins.

allow_insecure_grpc
booleanDefaults to false

Allow plaintext grpc:// plugin endpoints. Required to use any grpc:// endpoint; mTLS support is not yet shipped.

request_timeout_seconds
numberDefaults to 5.0

Per-RPC timeout applied to every plugin call. Replay does not apply it to in-process plugins: a replayed tick runs to completion, however long it takes on the host. Must be greater than 0.

keepalive_time_ms
integerDefaults to 30000

gRPC keepalive time, in milliseconds.

max_message_size_bytes
integerDefaults to 10485760

Maximum gRPC message size (10 MB).

protocol_version_min
stringDefaults to 1.0

Minimum accepted plugin protocol version.

protocol_version_max
stringDefaults to 1.0

Maximum accepted plugin protocol version.

heartbeat_timeout_seconds
numberDefaults to 15.0

Reserved liveness setting. Heartbeats update registry timestamps, but no monitor currently applies this timeout or evicts plugins automatically.

heartbeat_missed_threshold
integerDefaults to 2

Reserved liveness setting. Automatic missed-heartbeat eviction is not currently wired.

in_process_plugins
[]InProcessPluginSpecDefaults to []

In-process plugins loaded from Python modules at startup. See InProcessPluginSpec.

admin
AdminAuthConfig

Admin (ListPlugins) RBAC config. Parsed but currently inert — the gateway default-denies ListPlugins regardless of mode.

mode
stringDefaults to allow_all
Allowed values: allow_all k8s_rbac

Retune (Experimental, Simulation Only)

retune makes the Planner periodically replay the last window of recorded traffic against a grid of router and Planner parameters and apply the best point by objective, SLA goodput per GPU by default. This section is the field contract. For the concept, see Periodic Retune; for windows, scoring, and decision timing, see Planner Design; to run it, see Simulate Retune.

Experimental. In this release, retune runs only inside planner-in-the-loop offline replay: dynamo.replay.run_trace_replay with trace_format="dynamo", or aisimulate predict --stack dynamo on a Dynamo request trace. A live Planner rejects a config that sets retune at startup.

retune
RetuneConfigDefaults to null

Periodic replay-based retune. Rejects unknown fields. Requires mode agg or disagg, and a non-empty router or planner search domain.

To retune with fixed replicas (retune-only mode), set both enable_load_scaling: false and enable_throughput_scaling: false explicitly. Only that combination skips the easy-mode forcing and the “at least one scaling mode” rule; every other combination keeps them. A retune-only Planner never scales, not even to fit min_gpu_budget/max_gpu_budget or a minimum endpoint count, runs no load loop, and pulls no forward-pass metrics. It still ticks every scheduling.scale_interval_seconds (by default the 5-second load interval); to tick less often, set scheduling.scale_interval_seconds and load_adjustment_interval_seconds together.

With load or throughput scaling enabled, scheduling.external_plugins must be empty and scheduling.gateway.enabled must be false, because every candidate replay runs an inner Planner. That inner Planner always scales and never runs batch scheduling, even when the Planner is advisory.

With advisory: true, retune keeps sweeping and scoring, but a decision that would apply is recorded with outcome advisory and the point it recommends, and nothing changes.

interval_seconds
numberRequired

Window length and decision cadence T. Must be greater than 0 and a multiple of scheduling.scale_interval_seconds.

grace_seconds
numberDefaults to 60.0

Delay after a window ends before its sweep launches. Requests that complete after the launch time are excluded from the window. Must be 0 or greater.

history_seconds
numberDefaults to null

Trace history before each window that warms the load predictors of candidate planners and of a newly selected predictor. With throughput scaling, replay reads this history from the replayed trace and, before its first request, from load_predictor_warmup_trace, which must then be a Dynamo request trace that ends at or before the first replayed request; without throughput scaling no history is read. null resolves to the minimum the predictors need: throughput_adjustment_interval_seconds × max(prophet_window_size, kalman_min_points) over the current predictor and the load-predictor candidates, or 0 without throughput scaling. An explicit value must be 0 or greater, and a value smaller than that minimum is rejected.

decision_latency_seconds
number | measuredDefaults to 0.0

Delay from sweep launch to decision. A number is a fixed delay, 0 or greater. measured uses the sweep’s own wall-clock time, capped at timeout_seconds, times decision_latency_scale; it depends on the replay host, so it is not reproducible across hosts or runs. The decision lands no earlier than one Planner tick after launch. See Decision Timing for the mechanics and Decision Latency for choosing a value.

decision_latency_scale
numberDefaults to 1.0

Multiplier on the measured sweep time, for example to model a production sweep host that is slower or faster than the replay host. Must be greater than 0. A value other than 1 requires decision_latency_seconds: measured. Above 1, set timeout_seconds ≤ interval_seconds / scale (the default, interval_seconds, is rejected); the modeled deadline is then scale × timeout_seconds.

timeout_seconds
numberDefaults to null

Wall-clock deadline for one sweep; its workers are killed after it and the decision is timeout. null means interval_seconds. Must be greater than 0. Requires timeout_seconds ≤ interval_seconds. A numeric decision_latency_seconds must also be ≤ timeout_seconds; with measured, decision_latency_scale × timeout_seconds must also be ≤ interval_seconds. This keeps at most one sweep in flight.

objective
stringDefaults to GoodputPerGPU

Metric each candidate replay is scored on, written as the DGDR v1beta2 spec.objective.metric value. TTFT and E2ELatency are minimized; the others are maximized. See Objectives for what each one scores. With load or throughput scaling enabled, only GoodputPerGPU and ThroughputPerGPU are accepted; retune-only mode accepts every value.

Allowed values: Throughput ThroughputPerGPU ThroughputPerUser TTFT E2ELatency Goodput GoodputPerGPU
sla_ttft_ms
numberDefaults to null

TTFT SLA of the Goodput and GoodputPerGPU objectives; other objectives ignore it. Must be greater than 0. null uses the Planner’s ttft_ms; in aisimulate predict, null takes evaluation.sla.ttft_ms when it is set (see Requirements).

sla_itl_ms
numberDefaults to null

ITL SLA of the Goodput and GoodputPerGPU objectives; other objectives ignore it. Must be greater than 0. null uses the Planner’s itl_ms; in aisimulate predict, null takes evaluation.sla.itl_ms when it is set (see Requirements).

min_improvement_percentage
numberDefaults to 3.0

Apply the best candidate only if it beats the current point’s score on the same window by more than this percentage of that score: a higher score for a maximized objective, a lower one for TTFT and E2ELatency. Must be in [0, 100). Candidate replays share one random seed, so a candidate that changes no routing or scaling decision scores exactly the current point and is kept; see Candidates and the Sweep. To choose a value, see Measure the Gain.

max_candidates
integerDefaults to 512

Upper bound on the expanded grid size (the product of all domain sizes), on the values of each knob, and separately on the number of load-predictor candidates. Must be at least 1. A grid that exceeds it is rejected with the size of each dimension. For the candidate set a sweep replays, see Candidates and the Sweep.

max_parallel
integerDefaults to 2

Number of sweep worker processes. Must be at least 1. Each worker replays one candidate at a time, so memory grows with this value and the window size.

router
object | stringDefaults to null

Router search domain, written like the router section of aisimulate recommend --stack dynamo (see Search domains). A knob omitted from the map searches its AISimulate default domain; write a scalar to pin it. default searches the whole AISimulate default domain. null (or no router field) keeps every router parameter at its startup value; an empty map {} is rejected. A searched router requires router_mode="kv_router" (router.policy: kv_router in aisimulate predict) with the default worker-selection policy, no overlap_score_weight, and conditional disaggregation disabled.

planner
object | stringDefaults to null

Planner search domain, written like the planner section of aisimulate recommend --stack dynamo and limited to what a running Planner can change (see Search domains). default searches the parts of the AISimulate default domain that apply to this Planner. null (or no planner field) keeps every Planner field unchanged; an empty map {} is rejected. A written knob or group requires load or throughput scaling, and the scaling mode that uses it: for example, load_sensitivity needs load scaling, and load_predictor needs optimization_target: sla with throughput scaling. A searched field must have a value in the Planner config. ttft_ms and itl_ms are never searched.

Objectives

retune.objective takes the values of the DGDR v1beta2 spec.objective.metric enum, spelled the same, and scores each as the AISimulate optimization target the Dynamo operator maps it to. Scores are in the metric’s units, and decisions record them as baseline_score and best_score.

ValueAISimulate targetScoreBetter
ThroughputthroughputOutput tokens per second of the replayHigher
ThroughputPerGPUthroughput_per_gpuThroughput divided by the average provisioned GPUsHigher
ThroughputPerUserthroughput_per_userMean output tokens per second per user, over token gapsHigher
TTFTttftMean time to first token, in millisecondsLower
E2ELatencye2e_latencyMean end-to-end latency, in millisecondsLower
GoodputgoodputSLA-good output tokens per second of the windowHigher
GoodputPerGPU (default)goodput_per_gpuGoodput divided by the average provisioned GPUsHigher
  • SLA. Only Goodput and GoodputPerGPU count SLA-good tokens, against sla_ttft_ms and sla_itl_ms. The other objectives ignore both fields.
  • Time base. A candidate replay runs until every request of the window completes, so its duration is the window plus a drain that differs by candidate. Goodput and GoodputPerGPU are rescaled to the window length; the throughput objectives are not, so they rank the candidate that finishes the window’s tokens sooner. Scoring and Outcomes gives the formulas and the reasons.
  • Missing inputs. A replay that lacks an input of the objective fails that candidate instead of scoring it, for example TTFT with no first-token samples, or a per-GPU objective without GPU-hours.
  • Scaling. With load or throughput scaling enabled, each candidate replay runs a Planner that sizes its own replicas, and retune.planner can search min_workers and the GPU budgets. A metric that is not divided by GPUs improves with more GPUs and would apply the candidate that provisions the most, so only GoodputPerGPU and ThroughputPerGPU are accepted. ThroughputPerGPU ignores the SLA, so with scaling it favors the candidate that serves the window on the fewest GPUs, whatever its latency.

Search domains

retune.router and retune.planner use the knob names, value syntax, and default domains of the Dynamo router and Planner adapters of aisimulate recommend --stack dynamo:

  • Values. A knob takes the domain syntax of aisimulate recommend: a scalar, {choices: [...]}, {range: {min, max, step}}, or, for the load_sensitivity and load_predictor groups, {preset: ...}. Retune adds these rules:
    • A range must be enumerable: a range without step and a scale: log range are rejected. A range with min equal to max is one value. Stepped ranges are computed in decimal, so {min: 0.0, max: 0.3, step: 0.1} ends at 0.3.
    • Each knob may expand to at most max_candidates values.
    • A bare list ([0.5, 1.0]) is rejected; write {choices: [0.5, 1.0]}.
    • In YAML, write floats with a decimal point and a signed exponent (1.0e-3): YAML 1.1 reads 1e-3 as a string, which the schema rejects.
  • Infeasible points. When the Planner starts, a Planner grid point that fails PlannerConfig validation or does not fit the deployment, such as a min_workers above what max_num_gpus allows, is dropped, and one warning reports how many points were dropped. Startup fails only when some value of a searched Planner knob fits in no grid point, or when a load-predictor candidate is invalid. A decision that would apply Planner fields that no longer validate or fit, for example after a budget change, is failed.
  • Omitted knobs. A knob that has an AISimulate default domain searches it when omitted, as in aisimulate recommend. The retune-only knobs in the tables below keep their current value unless written. Knobs fixed at startup always keep their running value.
  • Names. Write the public names below. A live name, such as router_temperature, min_endpoint, or max_gpu_budget, is rejected with the public name to use. Decisions and report.planner.retune_events record the live names: the PATCH /router_policy parameter names and the PlannerConfig field names.

Router knobs:

KnobLive nameOmittedWritten
policyrouter_mode (startup)kv_routerMust be kv_router
prefill_load_model.typerouter_prefill_load_model (startup)Startup valueMust equal the startup value (none or ais)
overlap_score_creditoverlap_score_credit{0, 0.5, 1}; {0} when the startup credit is 0Domain; a positive value is rejected when the startup credit is 0
prefill_load_scaleprefill_load_scale{0, 0.25, 0.5, 1, 2, 4, 8, 16, 32}Domain
temperaturerouter_temperature{0, 0.2, 0.5, 1}Domain
overlap_score_credit_decay, decode_active_request_weight (retune only)SameStartup valueDomain, non-negative

router: default is 3 × 9 × 4 = 108 points.

The other router policy parameters are not retunable and are rejected:

  • host_cache_hit_weight and disk_cache_hit_weight: the startup router configuration also uses them to count a request’s cached tokens, which a runtime update does not change. A candidate replay would start its router with the candidate’s weights and score a router that no applied update can produce.
  • shared_cache_multiplier: replay reports no shared cache hits, so every value would score the same.

Planner knobs:

KnobLive nameOmittedWritten
load_sensitivity groupload_scaling_down_sensitivityWith load scaling: {70, 80, 90}, from the aggressive, default, and conservative presets{preset: [...]} with preset names or mappings, or {preset: false} with load_scaling_down_sensitivity as a domain
load_predictor groupPredictor fieldsWith optimization_target: sla and throughput scaling: the 11 simulation predictor presets{preset: [...]} with preset names or complete mappings, or {preset: false} with type and the predictor knobs as domains
min_workersmin_endpointCurrent valueDomain; mode: agg only
prefill_min_workers, decode_min_workersprefill_min_endpoint, decode_min_endpointCurrent valueDomain; mode: disagg only; null is rejected
max_num_gpus, min_num_gpusmax_gpu_budget, min_gpu_budgetCurrent valueDomain; values follow max_gpu_budget and min_gpu_budget (min_num_gpus: -1 disables the floor)
max_throughput_scaling_replicasSameCurrent valueDomain; requires throughput scaling
prefill_scale_up_queue_tokens, prefill_scale_down_queue_tokens (retune only)SameCurrent valueDomain; requires optimization_target: load and mode: disagg
decode_scale_up_kv_rate, decode_scale_down_kv_rate (retune only)SameCurrent valueDomain; requires optimization_target: load
policy, scaling_policy, fpm_sampling and their knobs, load_min_observations—Running valueRejected: fixed when the Planner starts
ttft_ms, itl_ms—FixedRejected: set sla_ttft_ms and sla_itl_ms to change the scoring SLA

The group rules are those of aisimulate recommend: to write a knob of a group, set the group to {preset: false}; a group that is omitted or {preset: default} cannot be combined with its knobs. Within these groups:

  • Load sensitivity. Retune searches only load_scaling_down_sensitivity; load_min_observations keeps its running value. A preset name contributes its sensitivity alone, so with a running load_min_observations other than 5 the default preset is applied only in part. A preset mapping must set load_min_observations to the running value.
  • Load predictor. The predictor is never a grid dimension: a pre-sweep picks one candidate per sweep. Candidates that give the same predictor are evaluated once ({preset: false} with the default knob domains is 256 combinations and 40 predictors). Records label a candidate with its preset name, or custom_<i> for the i-th entry. The number of candidates must not exceed max_candidates.
  • Planner defaults. planner: default searches load_scaling_down_sensitivity ∈ {70, 80, 90} with load scaling and the 11 predictor presets with optimization_target: sla and throughput scaling. Without scaling it expands to nothing.

An explicit domain for a disaggregated SLA Planner with load and throughput scaling. The router grid is 3 × 1 × 3 × 2 = 18 points and the Planner grid 3 × 2 = 6, so the sweep replays 108 grid points, after a pre-sweep over three predictors:

retune:
interval_seconds: 21600
router:
overlap_score_credit: {choices: [0.5, 1.0, 2.0]}
prefill_load_scale: 1.0 # pinned
temperature: {range: {min: 0.0, max: 0.2, step: 0.1}} # 0, 0.1, 0.2
decode_active_request_weight: {choices: [0.5, 1.0]} # retune-only knob
planner:
load_sensitivity: {preset: false}
load_scaling_down_sensitivity: {choices: [70, 80, 90]}
decode_min_workers: {choices: [1, 2]}
load_predictor: {preset: [arima_log1p, kalman_default_raw, kalman_reactive_log1p]}

Additional types

Nested object types referenced above, broken out to keep the field lists shallow.

PickedParallelConfig

A parallelism pick emitted by AIConfigurator. Referenced by AICInterpolationSpec.

tp
integerDefaults to 1

Tensor-parallel size.

pp
integerDefaults to 1

Pipeline-parallel size.

dp
integerDefaults to 1

Data-parallel (attention-DP) size.

moe_tp
integerDefaults to 1

Mixture-of-Experts tensor-parallel size.

moe_ep
integerDefaults to 1

Mixture-of-Experts expert-parallel size.

AICInterpolationSpec

Everything the Planner needs to reproduce a rapid-mode AIC sweep. Written by the profiler onto the Planner ConfigMap; not normally hand-authored.

hf_id
stringRequired

HuggingFace model id.

system
stringRequired

AIC system identifier.

backend
stringRequired
Allowed values: trtllm vllm sglang
isl
integerRequired

Input sequence length for the sweep. Must be greater than 0.

osl
integerRequired

Output sequence length for the sweep. Must be greater than 0.

sweep_max_context_length
integerRequired

Maximum context length swept. Must be greater than 0.

prefill_interpolation_granularity
integerRequired

Number of prefill interpolation points. Must be greater than 0.

decode_interpolation_granularity
integerRequired

Number of decode interpolation points. Must be greater than 0.

prefill_pick
PickedParallelConfigRequired

Prefill parallelism pick. See PickedParallelConfig.

decode_pick
PickedParallelConfigRequired

Decode parallelism pick. See PickedParallelConfig.

ExternalPluginEntry

One static external-plugin registration under scheduling.external_plugins. Rejects unknown fields.

plugin_id
stringRequired

Unique identifier. Must not collide with a builtin plugin id.

plugin_type
stringRequired

Pipeline stage the plugin participates in.

Allowed values: predict propose reconcile constrain
priority
integerRequired

Stage priority. Smaller number is more authoritative.

endpoint
stringRequired

Wire endpoint. Must start with grpc://host:port; inproc:// is rejected here.

auth_token
string

Bearer token validated by the registry. Populate from a mounted Secret.

protocol_version
stringDefaults to 1.0

Plugin protocol version. Must fall within the registry’s supported range.

version
stringDefaults to v1

Plugin’s own version string, surfaced in ListPlugins.

execution_interval_seconds
numberDefaults to 0.0

0.0 runs every tick; a positive value throttles to every N seconds. Must be 0 or greater.

hold_policy
stringDefaults to HOLD_LAST

Behavior when throttled. HOLD_LAST reuses the cached result; ACCEPT_WHEN_IDLE treats the plugin as no-opinion when not due. Accepts the name (case-insensitive) or its integer value.

Allowed values: HOLD_LAST ACCEPT_WHEN_IDLE
needs
[]stringDefaults to []

Capability list consumed by the type-aware merge.

requires_produced_fields
[]stringDefaults to []

Dot-paths into the pipeline context (for example predictions, observations.traffic) that must be set for the plugin to fire on a tick. Empty means no gating.

observation_window_seconds
numberDefaults to 0.0

Aggregation window for windowed observation types in needs. 0.0 uses scale_interval freshness; a positive value aggregates over the last N seconds and must be an integer multiple of scale_interval_seconds.

InProcessPluginSpec

One in-process plugin under plugin_registration.in_process_plugins. Rejects unknown fields.

module
stringRequired

Python module path containing the plugin class.

class
stringRequired

Plugin class name within module.

plugin_id
stringRequired

Unique plugin identifier.

plugin_type
stringRequired
Allowed values: predict propose reconcile constrain
priority
integerRequired

Stage priority. Smaller number is more authoritative.

execution_interval_seconds
numberDefaults to 0.0

0.0 runs every tick; a positive value throttles to every N seconds.

hold_policy
stringDefaults to ACCEPT_WHEN_IDLE

Behavior when throttled.

Allowed values: ACCEPT_WHEN_IDLE HOLD_LAST
needs
[]stringDefaults to []

Capability list consumed by the type-aware merge.

requires_produced_fields
[]stringDefaults to []

Dot-paths into the pipeline context that must be set for the plugin to fire on a tick.

observation_window_seconds
numberDefaults to 0.0

Aggregation window for windowed observation types in needs. Must be 0.0 or a positive integer multiple of scale_interval_seconds.

kwargs
objectDefaults to {}

Keyword arguments passed to the plugin class constructor.

Environment variables

The Planner reads these environment variables. The Prometheus and namespace variables set the defaults for the config fields noted above; the rest control runtime behavior for specific environments.

VariableEffectDefault
DYN_NAMESPACEDefault for namespace. Operator injects {k8s_namespace}-{dgd_name}.dynamo
PROMETHEUS_ENDPOINTDefault for metric_pulling_prometheus_endpoint.in-cluster URL
PROMETHEUS_TOKENDefault for metric_pulling_prometheus_token.unset
PROMETHEUS_TOKEN_FILEDefault for metric_pulling_prometheus_token_file.unset
PROMETHEUS_SSL_VERIFYDefault for metric_pulling_prometheus_ssl_verify (1/true/yes).false
PROMETHEUS_EXTRA_QUERY_PARAMSDefault for metric_pulling_prometheus_extra_query_params (URL query string).unset
PROMETHEUS_CA_BUNDLEDefault for metric_pulling_prometheus_ca_bundle.unset
DYN_PLANNER_PROMETHEUS_REQUEST_TIMEOUT_SECONDSDefault for metric_pulling_prometheus_request_timeout_seconds.10.0
PLANNER_PROMETHEUS_PORTDefault for metric_reporting_prometheus_port.0
DYN_PARENT_DGD_K8S_NAMEParent DGD name for the GlobalPlanner connector (environment: global-planner).required
POD_NAMESPACEKubernetes namespace for the GlobalPlanner connector.required
SCALING_CHECK_INTERVALPoll interval (seconds) for the virtual environment connector (environment: virtual).10
SCALING_MAX_WAIT_TIMEMaximum wait (seconds) for a scaling action in the virtual environment.1800
DYNAMO_PLANNER_TESTTest-only. Must be 1 to allow the virtual clock. Not for production.unset

Validation rules

The Planner enforces these cross-field rules at startup and rejects a config that violates any of them:

  • ttft_ms must be greater than 0.
  • report_interval_hours must be a positive finite number or null.
  • fpm_sample_bucket_size must be a perfect square.
  • global_planner_namespace is required when environment is global-planner.
  • Under optimization_target: load, prefill modes require prefill_scale_up_queue_tokens > prefill_scale_down_queue_tokens, and decode modes require decode_scale_up_kv_rate > decode_scale_down_kv_rate.
  • At least one scaling mode must be enabled. Under any optimization_target other than sla, the Planner forces load scaling on and throughput scaling off and ignores ttft_ms / itl_ms. The only exception is retune-only mode: retune set with both enable_load_scaling and enable_throughput_scaling explicitly false (see Retune).
  • When ais_perf_model is set, its roles must cover the deployment: prefill and decode for disagg, the matching role for prefill/decode, or aggregated for agg. Role keys must agree with worker_type. Unknown canonical fields and the retired aic_perf_model input are rejected.
  • scheduling.scale_interval_seconds must evenly divide load_adjustment_interval_seconds and, when throughput scaling is enabled, throughput_adjustment_interval_seconds.
  • When both scaling modes are enabled, load_adjustment_interval_seconds must be shorter than throughput_adjustment_interval_seconds.
  • retune has its own cross-field rules, listed with its fields in Retune. A live Planner rejects any config that sets retune.