Contents TandemLLM Docs
v0.9.2
Star58

Part VI, Reference

28Command-line reference

The tables in this part are generated from the code by manual/tools/gen_reference.py, which parses the argument parsers, the settings registry, the metric registrations and the ledger’s schema with Python’s ast module and never imports the project. The manual’s build runs it first, so the tables follow the code they were built from. A description is the first sentence of the flag’s own help text; where the code gives none, the generator carries a short one. A default is the code’s; where the served profile passes another value, the cell says “served:” and that value, as ops/start.sh builds it from ops/serve.env.

28.1 The engine’s server

python server/app.py [flags], or ops/start.sh, which builds the flags from serve.env. python server/app.py --help prints the full help texts.

Table 28.1 Every flag of the engine’s server, server/app.py, with the value the served profile passes where it differs
FlagDefaultWhat it does
--modelnonethe checkpoint directory of the target model.
--served-modelqwen3.8-27b-spark-engine; served: qwen38-spark-enginethe raw engine’s model name; with the conductor on it is a hidden alias of TandemLLM.
--host127.0.0.1; served: 0.0.0.0the address to bind.
--port8000the port to listen on.
--max-len8192; served: 262144context length. The KV buffer is allocated for all of it up front, so this is a memory decision as much as a capability one: 64 KiB a token of engine KV plus 20 KiB a token per drafter arm, 27.9 GB of KV and 53.4 GB of whole ...
--rep-penalty1deterministic repetition penalty on the target’s logits, before the argmax (1.0 = off, today’s output).
--presence-penalty0flat subtraction from tokens already in the history (0 = off).
--frequency-penalty0subtraction per occurrence, on tokens already in the history (0 = off).
--temperature0server default sampling temperature (0 = greedy, the exact path).
--top-p1server default for top_p.
--top-k0server default for top_k (0 is off).
--no-repeat-ngram0forbid the token that would complete an n-gram already seen (HF’s no_repeat_ngram_size; 0 = off, must be >= 2).
--pattern-stopnoneend a generation that repeats one short pattern forever, as MAX:MIN:COUNT (e.g. 64:1:8, a block of 1..64 tokens repeated 8 times ends the generation with finish_reason stop).
--arglooponthe tool-argument loop guard (server/argloop.py): on stops a held tool call whose arguments loop and tells the model on its next turn. One of: on, log, off.
--default-max-tokens8192; served: 32768what a request that does not send max_tokens gets.
--reasoning-formattagshow the reasoning block reaches the client: inside <think></think> in content (default, and what Open WebUI folds on), as OpenAI-style reasoning_content deltas, or both. One of: tags, reasoning_content, both.
--draftermtpthe drafter set. lenrouter, the served one, holds both DFlash2 widths beside the lookup drafter; none decodes one token a step. One of: mtp, router, merged, dflash2, lenrouter, none.
--treeoff (a switch)verify a draft TREE per step instead of a chain, where the drafter builds one; see docs/speculative-decoding.md.
--regeneratesample (QWEN38_REGENERATE): a regenerate (the same conversation again after it was answered, under a TandemLLM plan; or X-Tandem-Regenerate: 1) samples with a fresh seed; every other request keeps its own sampling (greedy by default). One of: sample, off.
--regenerate-temperature0.7 (QWEN38_REGEN_TEMPERATURE)a regenerate’s temperature (QWEN38_REGEN_TEMPERATURE).
--regenerate-top-p0.95 (QWEN38_REGEN_TOP_P)a regenerate’s top-p (QWEN38_REGEN_TOP_P).
--regenerate-top-k20 (QWEN38_REGEN_TOP_K)a regenerate’s top-k (QWEN38_REGEN_TOP_K).
--sampled-treenone; served: detlet a SAMPLED request keep the tree verify. One of: det, mixed.
--budget16nodes per tree, anchor included.
--df2-temp1the block drafter’s temperature for its own proposals.
--corpusnone (QWEN38_CORPUS)the lookup drafter’s corpus: a directory of token ids with a suffix array (tools/build_corpus.py).
--depth3the drafter’s depth for the older chain drafters.
--k0verify block size; 0 = the drafter’s depth.
--draft-headnonean optional separate head file for the drafter.
--nvfp4nonethe NVFP4 weight files to load, one per target (mlp, gdn, attn); empty means the checkpoint’s FP8.
--price-tablenone (QSE_PRICE_TABLE)FILE[:NAME], the routers’ verify/draft/rollback prices for this weight set (engine/prices.py); empty = the NVFP4 constants in the code.
--fp8-headnonee4m3 lm_head from tools/quant_head.py; halves the head’s 2.54 GB in both the verify pass and the block drafter’s top-k read.
--dflash2-blocks1chained 8-wide draft blocks; 1 proposes 7 tokens, 2 proposes 14.
--dflash2-pathgreedyhow the block drafter walks its lattice: the greedy path or Viterbi. One of: greedy, viterbi.
--dflash2-ckptnonethe narrow (block 8) DFlash2 drafter checkpoint.
--dflash2-ckpt16nonethe sixteen-wide drafter, for --drafter lenrouter.
--len-fixed0pin --drafter lenrouter to one block width (8 or 16). 0 lets the policy choose, which means --len-latch: one decision a request. 8 and 16 measure the fixed baselines through the same code.
--len-latchon (--no-len-latch turns it off)decide the block width ONCE a request, four wide blocks, up to four narrow probes, then no more switching.
--learn-coston (--no-learn-cost turns it off)the length router learns its verify and draft costs from the blocks it times, across requests (default). --no-learn-cost keeps the served price table; timings inside a request still size its blocks, so two runs can part at a near tie.
--len-explore32blocks between forced wide probes when nothing suggests one.
--deep0 (QWEN38_DEEP)with --drafter lenrouter --tree: after --deep-after wide blocks in a row commit their whole width, propose the lookup drafter’s long exact continuation of this request’s text as one chain of up to this many rows. 0 = off.
--deep-after2 (QWEN38_DEEP_AFTER)full wide blocks in a row before a deep chain (2 keeps it off new text).
--narrow-armonwith --drafter lenrouter: build the block-8 drafter arm (on, the served default) or run the block-16 arm alone. One of: on, off.
--drop-idleoff (--drop-idle turns it on); served: onrelease the arm that LOSES the latch for the rest of the request: no tap, no sync, and nothing of it in the state snapshot.
--relax-tau1Breaks the agreement rule: accept a drafted token whose probability is at least this fraction of the argmax’s. 1.0, the default, keeps the rule.
--relax-rank1Breaks the agreement rule: accept a drafted token among the target’s top r. 1, the default, keeps the rule.
--think-stallonwith --conductor shadow or on, run the reasoning-loop arms of the policy’s reasoning_loop task (a pattern repeated over 128+ tokens, the history-wide 16-gram repeat, novelty collapse); the monitor decides whether a hit closes the ...
--no-think-stallsets think_stall offnever run the reasoning-loop arms (the budget still applies).
--conductorraw; served: onthe second-level harness (server/conductor/monitor/). raw, the default (off is the same): nothing of it runs and the output is the raw engine’s. shadow: every rule runs and journals, nothing is done. on: each task acts in its ... One of: raw, off, shadow, on.
--conductor-policynonethe monitor’s policy file (default ops/supervisor.yaml), validated at start against ops/supervisor.schema.json.
--conductor-watch-s30with --conductor shadow or on, how often the stall watchdog’s watch looks for sessions whose client has gone.
--think-budget0default cap on reasoning tokens per request, 0 = uncapped.
--answer-reserveauto (QSE_ANSWER_RESERVE)tokens of the output limit kept for the answer when a client asks for a thinking budget in any shape (server/thinking.py): its reasoning closes early enough to leave them. auto = min(2048, a quarter of the limit), 0 = none ...
--reasoning-effortnone; served: mediumdefault reasoning_effort for the chat template. One of: none, off, low, medium, xhigh.
--cache-budget-gb2RAM budget for the state cache, in GiB (CACHE_GB).
--store-entry-gb1GiB one state-store snapshot may take (STORE_ENTRY_GB), whatever budget is free: 1 GiB is about 7k tokens.
--no-session-cacheoff (a switch)do not keep a conversation’s state after its turn.
--no-prefix-cacheoff (a switch)do not checkpoint a prefill at chunk boundaries.
--resident-gb2.5GiB for the resident prefix’s anchors (RESIDENT_GB), the recurrent state (146.8 MiB) at chunk boundaries of the prompt the KV buffer holds, so the next turn of a growing conversation resumes in place, KV not copied, at any length ...
--resident-stash-gb1GiB for the rows a short unrelated request between two turns may overwrite, copied aside and back (RESIDENT_STASH_GB; ~104 kB a row: 1 GiB holds a --resident-guest-max guest and its 512-row slack).
--resident-guest-max8192the longest request that is a guest (RESIDENT_GUEST_MAX): opencode’s title call is 1-3k tokens; a longer one replaces the resident prompt with its head pinned.
--resident-tail4the newest anchors never evicted (the next turn resumes near the end).
--resident-pin-gb4GiB for the head of the resident prompt a long unrelated request would otherwise cut (RESIDENT_PIN_GB): its KV rows and the anchors in it are copied aside, and a later request that shares more with that head than with the rows in ...
--resident-park-gb4GiB for one other session’s rows (RESIDENT_PARK_GB): when a request of another session (x-session-id) replaces the resident prompt, the rows past their shared head are copied aside with its newest anchors, and that session’s next ...
--end-anchoronthe resident prefix’s end anchor (END_ANCHOR): at the end of every generation the recurrent state at its last position (147 MiB, one per resident prompt), so the next request that starts with the prompt and every token the engine ... One of: on, off.
--compactioncontinue (QSE_COMPACTION)a client’s compaction request (QSE_COMPACTION, server/compaction.py): continue = served as the continuation of the conversation the engine holds for its session (the prefill reads only the instructions); client = as the client ... One of: continue, client.
--compaction-prepareon (QSE_COMPACTION_PREPARE)write an idle opencode session’s summary ahead, so its /compact is answered without the engine (QSE_COMPACTION_PREPARE); a request that waits stops it at the next chunk or block. One of: on, off.
--compaction-idle-s30 (QSE_COMPACTION_IDLE_S)seconds without a request before a summary is prepared.
--compaction-min-tokens32768 (QSE_COMPACTION_MIN_TOKENS)the shortest conversation a summary is prepared for.
--end-alignonthe end anchor for a copy whose whitespace is not the rows’ (END_ALIGN, server/endalign.py): a follow-up whose copy of an earlier generation differs from what the engine wrote in whitespace alone (a tool call’s trimmed parameter ... One of: on, off.
--mem-ceiling-gib70GiB the engine may hold between requests, allocated plus the allocator’s reserve (MEM_CEILING_GIB): a cache grows only while the engine stays under it less --reserve-slack-gib, and over it the caches are given back, cheapest ...
--mem-peak-gib77GiB the engine may hold during a prefill (MEM_PEAK_GIB): the ceiling plus the workspace of a 262,144-token prompt.
--reserve-slack-gib2GiB of free blocks the allocator may keep between requests (RESERVE_SLACK_GIB); over it they go back to the driver once a request has finished, never inside one.
--prompt-token-cache4millions of tokens of tokenised chat messages kept, so a growing conversation’s prompt is tokenised only where it is new (server/tokcache.py). 0 = tokenise every prompt whole.
--session-trimoffcut the engine back to the committed tokens before the session snapshot when the last verified block ran past them (end token, stop, budget) and its commit is still pending, so the put is not declined. One of: on, off.
--store-boundaries1chunk boundaries of one prefill the state store keeps: its longest ones under the per-entry cap. 0 = every boundary, where one cold prefill’s nested snapshots fill the budget and evict everything else.
--prefill-heartbeat-s5a streamed request whose prefill has run this long gets an SSE comment (’: prefill done/total’) after every chunk, at most once a second, so a client and every proxy between see the stream is alive.
--live-activityonthe live activity on /v1/dashboard/live (states, prefill progress, timeline, the last 20 stops) at QSE_LIVE_HZ events a second while busy. off = contract 1.1 with those fields null at one event a second: the kill switch, and the ... One of: on, off.
--max-prefill-rows8192with the prefix cache off, forward a long prompt in chunks of this many rows instead of one call; a 131k-token single forward exhausted the board. 0 = one call.
--prefix-chunk1024tokens between prefill checkpoints, and the forward size of EVERY prefill while the prefix cache is on, the two have to agree or a warm prefill is not the same arithmetic as a cold one.
--response-cacheoff (a switch)OPT-IN. Answer an identical (prompt, params) request from memory.
--response-cache-mb256the response cache’s budget in MiB.
--response-cache-ttl3600seconds a response cache entry is kept.
--suffix-store~/.qwen38-spark-engine/suffix (QWEN38_SUFFIX_STORE)directory for the persistent suffix store of what this engine has read and written, which the lookup drafter reads as a second corpus.
--suffix-store-readonlyoff (a switch)read the suffix store and never append to it: a fixed benchmark measured against a store of real traffic must not write itself into it.
--suffix-store-mb192cap on the store, in MiB of int32 token ids (192 MiB = 48 M tokens).
--disk-cacheoff; served: (a path)the disk tier: a directory on the NVMe for prompt-prefix state, prefixes prefilled more than once, a session’s first long request, under the caches in RAM, or off (the default).
--disk-cache-min-tokens4096the shortest prefix the disk tier writes an anchor for.
--conductor-defaultsbuiltin; served: shippedshipped, the live documents are stored as version 1 for every document the conductor’s directory has no version of; builtin, the minimal built-ins stay version 0. One of: builtin, shipped.
--session-spillona live conversation on the NVMe, under the disk tier’s directory: written whole at a planned stop and read back at the next start, written before another client’s request evicts it, read back at its next turn. One of: on, off.
--session-spill-gb64the session spill’s own budget on the NVMe (a 256k conversation is about 27 GB as it is in the engine, about 16 GB compressed); the disk tier’s free-space floor holds for both; settings.memory.session_spill overrides it live.
--session-spill-codeczstdnew spill blocks as byte planes compressed with zstd (exact under the agreement rule, 1.71x on a real entry; blocks on the disk are read either way). One of: zstd, off.
--disk-write-budget-gb200the engine’s NVMe writes a local day past which optional writes stop (the tier’s, and the spill’s but a drain and evictions of 32k+ tokens; past 1.5x only the drain); 0 = no budget; settings.memory.disk_writes.budget_gb overrides ...
--session-spill-min-tokens16384the shortest resident conversation an eviction writes to the NVMe (shorter ones are the RAM park’s).
--disk-cache-head-anchors4anchors a session’s first long request gets, at the grid lines below where its last user message starts (where the next session parts).
--suffix-store-scopeallall remembers prompts and answers, outputs only what the engine wrote. One of: all, outputs.
--request-timeout900; served: 3600wall-clock cap on one generation, checked between blocks; 0 disables.
--max-queue8requests allowed to wait for the engine before new ones get a 503 with Retry-After.
--queue-timeout120; served: 240how long a request waits for the engine before a 429.
--side-laneona short request, a client’s side request or a raw one, thinking off, within the two caps below, is served at the next safe point of the generation that holds the engine (on: between decode blocks and between prefill chunks ... One of: on, decode, off.
--side-lane-prompt-max2048the longest prompt the side lane serves, in tokens.
--side-lane-new-max64the most output tokens the side lane serves.
--parallel1 (QSE_PARALLEL)sequence slots: 1 (the default) is one sequence, as always.
--side-max-len65536 (QSE_SIDE_MAX_LEN)a side slot’s window in tokens; slot 0 keeps --max-len (262,144).
--parallel-floor-gb15 (QSE_PARALLEL_FLOOR_GB)admission: MemAvailable less the caches’ growth, the requests in flight and this request’s worst case must stay at or above this; a side slot is built only if it does with the slot’s bytes added.
--parallel-batchon (QSE_PARALLEL_BATCH)on: decoding slots verify their trees in one joint pass (lockstep rounds); off: they take turns, one verify each. One of: on, off.
--parallel-drafton (QSE_PARALLEL_DRAFT)with the joint verify on: the decoding slots’ draft calls in one packed pass over the drafter (on), or one after the other (off). One of: on, off.
--parallel-switch-ms0 (QSE_PARALLEL_SWITCH_MS)with side slots: the interpreter’s thread switch interval in ms (0 keeps Python’s 5 ms); a woken slot waits up to this long for the GIL.
--parallel-cutshare (QSE_PARALLEL_CUT)how a joint pass’s rows are shared: share (each slot cuts its tree to a fixed share before it submits: 16 at two slots, 10 at three, 8 at four) or joint (the round cuts every slot’s whole tree together, best nodes first). One of: share, joint.
--parallel-max-rows32rows of a joint pass at most (32: the row-invariant kernels’ range).
--batch-timeout-ms2a joint round runs without a missing slot once the GPU turn has been idle this long.
--turn-quantum-ms50the GPU turn goes to a waiting slot this far behind in GPU time.
--parallel-settleonsynchronize the device before the turn changes hands (the routers’ timings then hold only their own slot’s work). One of: on, off.
--side-precaptureoffcapture a side slot’s verify graphs at start (on, about a minute a slot) or at their first use (off: the build takes seconds; each width’s first lone round on a side slot pays its capture, a fraction of a second). One of: on, off.
--side-graphson (QSE_SIDE_GRAPHS)a side slot’s own verify graphs: on (captured as --side-precapture says; most of a slot’s constant bytes) or off (the slot verifies eager when it decodes alone and holds no graph pool; a joint pass is eager either way). One of: on, off.
--side-slot-const-gb0 (QSE_SIDE_SLOT_CONST_GB)a side slot’s bytes beyond its window’s, in the build’s estimate; 0 (the default) follows --side-graphs: 7.5 GiB with it on (6.9 to 7.5 GiB allocated measured for 8,192-token slots, most of it the verify graphs’ pools: 121 ...
--kv-pooloff (QSE_KV_POOL)on: every slot’s KV window (engine attention KV and the drafters’ context KV) is reserved as virtual addresses and its pages are committed as a conversation’s rows are written and given back when it ends, from one pool for every ... One of: on, off.
--kv-hard-floor-gb10 (QSE_KV_HARD_FLOOR_GB)with --kv-pool on: a commit never takes MemAvailable under this (GiB); the pool gives back caches and idle conversations first, else the request is not run (admission keeps requests out at --parallel-floor-gb).
--kv-margin-rows256 (QSE_KV_MARGIN_ROWS)with --kv-pool on: rows committed past every write (a masked tile’s over-read stays on mapped pages).
--visiononload the checkpoint’s vision tower (0.92 GB bf16) and accept image_url parts in chat requests; off refuses them with a 400. One of: on, off.
--image-max-mb20largest image a request may send or link, after base64 decoding.
--image-max-decode-pixels64000000largest canvas an image may declare, checked before its pixels are decoded; the processor then resizes to its own limits.
--image-max-pixels0the processor’s resize target cap in pixels (0: the checkpoint’s preprocessor_config.json, 16,777,216 for Qwen3.8 = 16,384 rows an image).
--image-backendtorchvision (QSE_IMAGE_BACKEND)the image processor’s backend, pinned so the patches do not depend on what is installed (the two differ by up to two 8-bit levels after a resize). torchvision (the default, what every served measurement ran) needs torchvision ... One of: torchvision, pil.
--max-images16images one request may send.
--max-image-rows65536prompt rows all of a request’s images may take together (one row per 2x2 block of 16-pixel patches; a 1024x1024 image is 1024 rows).
--image-httpsonfetch https:// image URLs (off: data: URLs only). One of: on, off.
--image-https-privateofflet https image URLs reach loopback, private and link-local addresses (off: public hosts only). One of: on, off.
--image-fetch-timeout15seconds for a whole https image download, redirects included.
--image-cache-mb512encoded images kept on the device by content, so a conversation that sends an image again does not encode it again.
--image-act-gb6admission: an image whose encode would need more than this (the tower’s byte math, engine/vision.py) is refused with a 400.
--usage-defaulton (QSE_USAGE_DEFAULT)a streamed request that sends no stream_options gets usage, timings and metrics on its finish chunk (on, the default: Open WebUI asks for include_usage only when a model’s Usage capability is ticked), or nothing, as before (off). ... One of: on, off.
--usage-ledgeroff; served: (a path)the SQLite usage ledger’s path, or off (the default).
--conductor-configoff; served: (a path)the conductor’s config directory (versioned profiles, router, roles, packages and its journal, server/conductor/), or off (the default).
--backendsoffthe proxy’s config database (proxy/, docs/proxy.md), or off (the default).
--host-collectoronthe System view’s hosts (proxy/hostcollect.py): this machine’s memory, GPU, CPU, disks and network, and the process behind each backend on it. One of: on, off.
--usage-retention-days400days the usage ledger keeps its rows (at least 400).
--trust-loopbackon (--no-trust-loopback turns it off)a request from loopback with no X-Forwarded-For / X-Real-IP header (the box’s own watchdog, row3, gate, soak) needs no token for /metrics, the full /health and the cache routes once an admin password or metrics token is set.
--dashboard-loginoff (QSE_DASHBOARD_LOGIN)on, with an admin password (QSE_ADMIN_TOKEN) set: /v1/dashboard/* needs the admin token or a session too (the page has no sign-in screen yet). off, the default: the dashboard’s read API answers without a token. One of: on, off.
--dashboard-dirnonewhere the dashboard’s built files are (default: dashboard/dist in this repository); /dashboard/ serves them, or a placeholder when missing.
--setupoff (a switch)setup mode (docs/setup.md, ops/start.sh --setup): no model of Qwen’s is loaded; the dashboard, /v1/setup/* and Wren, the setup guide’s assistant, alone.
--fake-engineoff (a switch)the e2e: no weights, no GPU, a deterministic CPU token source (server/fake_engine.py) behind the real handler, auth, ledger, metrics and logs.
--fake-tps200with --fake-engine: tokens a second it writes.
--fake-prefill-tps0with --fake-engine: the prefill rate of a FAKE_SLOW_PREFILL prompt (0 = 2,000 tokens a second).
--structured-outputson (--no-structured-outputs turns it off)serve response_format json_object / json_schema and structured_outputs (regex, choice, json) as masks over the target’s rows, exact under speculation.
--log-contentoff (a switch)let exception messages that quote a request into the log.
--log-request-keysoff (a switch)one [body] line per request with the parameter names and the scalar values of the non-content ones (model, stream, max_tokens, temperature,...); never messages, prompt, tools or stop strings.
--verboseoff (a switch); served: onmore log lines.

28.2 The dashboard and proxy

tandem-dash serve and python -m proxy take the same flags; tandem-dash check, secrets and backends take them too and add their own action (Table 4.1).

Table 28.2 tandem-dash serve and python -m proxy
FlagDefaultWhat it does
--config-db~/.tandemllm/config.sqlite3 (TANDEM_CONFIG_DB)the config database (created when missing).
--env-filenoneKEY=VALUE lines read before the start; the process environment wins.
--host127.0.0.1 (TANDEM_HOST)the address to bind.
--port8080 (TANDEM_PORT)the port to listen on.
--usage-ledger~/.tandemllm/ledger.sqlite3 (TANDEM_USAGE_LEDGER)the usage ledger (one row per request, no text); ’off’ for none.
--usage-retention-days400days the usage ledger keeps its rows (at least 400).
--dashboard-loginoff (QSE_DASHBOARD_LOGIN) (TANDEM_DASHBOARD_LOGIN)on, with TANDEM_ADMIN_TOKEN (the admin password) set: the dashboard API needs it or a session too; with no password set every route is open. One of: on, off.
--dashboard-dirnonedefault: dashboard/dist.
--trust-loopbackona request from this machine without proxy headers counts as the admin. One of: on, off.
--no-keychainoff (a switch)do not ask the OS keychain for the master key.
--conductor-config~/.tandemllm/conductor (TANDEM_CONDUCTOR)the conductor’s documents (profiles, router, packages) for the harness in front of the backends; ’off’ relays every backend as does.
--conductor-defaultsshippedwhat a new conductor directory starts with. One of: shipped, builtin.
--verboseoff (a switch)more log lines.
Table 28.3 tandem-dash launch
FlagDefaultWhat it does
ENGINEthe engine to start: vllm or sglang.
--modelrequiredthe model id or path the engine serves.
--portnonethe engine’s port.
--host127.0.0.1the engine’s bind address.
--idnonethe backend id (default: the engine’s name and port, e.g. vllm8100).
--labelnonethe backend’s label in the dashboard.
--config-db~/.tandemllm/config.sqlite3 (TANDEM_CONFIG_DB)the proxy’s config database the backend is registered in.
--collect-urlnone (TANDEM_COLLECT_BASE)the proxy address the plugin posts to; default: this machine’s proxy on its port.
--engine-cmdnonethe engine’s command instead of vllm serve / sglang serve.
--pythonnonethe Python of the engine’s environment, for the plugin check (default: the one behind the engine’s command).
--no-registeroff (a switch)do not create or update the backend.
--dry-runoff (a switch)print, start nothing.
Table 28.4 tandem-dash hostcollect
FlagDefaultWhat it does
--host127.0.0.1the address to bind; beyond loopback it needs a token.
--port9108the collector’s port.
--token-filenonea file whose first line is the bearer token; else TANDEM_COLLECTOR_TOKEN.
--watchnoneports to report always, as id:port,id:port (a request may add more).
--path[]a path whose filesystem to report (repeatable).

28.3 The service scripts

Table 28.5 The scripts in ops/ and the installed control script.
commandwhat it does
bin/tandem start|stop|restart|status|smoke|logsthe installed engine’s control script (Chapter 3)
ops/start.shstarts the engine from serve.env, waits for /health, drops the weights’ page cache, loads the roles
ops/stop.sh [seconds]SIGTERM, the drain, then a kill only after the wait
ops/watchdog.shone health check, for cron every minute
ops/hold.sh <minutes> <command>a command with the board to itself, then the service back
ops/gate.sh <label> [--profile F]the release gate
ops/make-secrets.sh [--admin] [--rotate]the metrics token; --admin adds the admin password
ops/roles.sh load|up|down|settleroles beside the engine, through the residency planner
. ops/engines.sh; engine_pidsevery engine process on the board

28.4 Measurement and maintenance tools

The tools/ directory holds about 180 scripts: kernels, quantisers, probes, checks and benches. The ones this manual refers to are listed here; each prints its own --help.

Table 28.6 The tools this manual refers to.
toolwhat it does
tools/row3.pythe benchmark row, N runs through one server, with --compare
tools/block_ab.pythe in-process A/B for changes that keep the bits
tools/forced_bench.pythe teacher-forced bench
tools/verify_spec.pythe agreement gate with its near-tie rule
tools/flagoff_identity.pythe identity gate with the new flags off
tools/api_text_check.py13 plain requests against the current release
tools/client_smoke.pythe request shapes real clients send
tools/verify_curve.pythe verify prices StairCut cuts on
tools/quant_nvfp4.py, quant_head.pythe quantisers
tools/quality_gate.pythe quality gate
tools/calib_corpus.py, build_corpus.pythe calibration text and the lookup corpus
tools/mem_audit.pythe memory a configuration holds
tools/disk_cache_live.py, disk_restore_check.pythe disk tier’s live and bit-exact checks
tools/session_spill_check.pythe session spill’s bit-exact check
tools/lane_check.pythe side lane on the real engine
tools/tandem_eval.pythe conductor’s evaluation suites
tools/conductor_policy.pythe monitor’s policy schema and its check
tools/shadow_ab.py, shadow_measure.pythe shadow reader’s cost and read rate
tools/voice_replay.pya recorded session’s lines through the voice
tools/proxy_bench.py, proxy_gate.pythe proxy’s overhead and its decode check
tools/parallel_load.pyagent-like sessions over several backends
tools/package_check.shthe wheel builds and installs without torch
manual/tools/gen_reference.pythis part’s tables