Skip to content

Environment variables (developer)

Developer-only switches: diagnostics, profiling, experiments and checks. They are not part of the user interface, their names and meaning can change between releases, and user pages do not link here. The variables users set — the twins of run_flextool flags and the process / GUI settings — are on the user page Environment variables. Test-suite switches are in Testing.

Every variable FlexTool reads is registered in flextool/run_options.py: the twin of a flag in OPTIONS, every other one in ENV_KNOBS with its audience (user, dev, test) and its page. Developer variables keep their names (no FLEXTOOL_DEV_* prefix); the registry and this page mark them developer-only. tests/test_env_knob_registry.py fails when FlexTool reads a variable that is not registered, when a registered variable is missing from its page, or when a page lists one that is no longer read. A new variable therefore needs an ENV_KNOBS entry and a row on its page.

How options are resolved (one resolver, flag > environment variable > database > default, nothing writes the environment) is in architecture.md, "Runtime options".

For polar-high's own variables (POLAR_HIGH_WRITE_MPS_PROFILE, ...), see the polar-high environment-variables page.

Solve acceptance

engine/solve/_acceptance.py decides whether a solve that HiGHS did not certify optimal is accepted.

Variable Default Set to What it does
FLEXTOOL_ACCEPT_NEAR_OPTIMAL on 0 0 rejects every solver status other than optimal (the old hard failure), a MIP stopped by a limit included, e.g. for strict test runs. On by default: an interior-point solve stopped without crossover (status Unknown) is accepted when the checks below pass.
FLEXTOOL_ACCEPT_PD_GAP 1e-2 positive float Largest relative primal-dual gap of an accepted near-optimal solve.
FLEXTOOL_ACCEPT_PRIMAL_REL max(1e-6, 10 × primal_feasibility_tolerance) positive float Largest relative primal infeasibility of an accepted near-optimal solve. Unset, it follows the tolerance the solve ran with; a set value replaces that derived ceiling (tighter or looser).
FLEXTOOL_ACCEPT_PRIMAL_ABS_MARGIN 10 positive float Absolute primal infeasibility allowed, as a multiple of HiGHS' primal feasibility tolerance (HiGHS checks feasibility on the scaled LP, so the unscaled slack can exceed it).

Benders

Read by engine/solve/_benders.py. A malformed value is ignored with a warning.

Variable Default Set to What it does
FLEXTOOL_BENDERS_IN_OUT_WEIGHT the solve's benders_in_out_weight (0) float in [0, 1) Developer override of the in-out stabilization weight λ (weight of the interior centre in the separation point). 0 is off. No flag: it changes convergence, so production runs set it in the database.
FLEXTOOL_BENDERS_TRUST_REGION_RADIUS unset (off) positive float Trust-region stabilizer: absolute box half-width on the coupling flows (normalised units). Not combined with in-out.
FLEXTOOL_BENDERS_MAX_STALL 8 positive integer Iterations without progress before the stall guard stops the loop. The guard cannot be turned off.
FLEXTOOL_BENDERS_CUT_COMPACT_AT unset / 0 (off) positive integer Master cut count at which the master is compacted to its binding cuts.
FLEXTOOL_BENDERS_CUT_POLICY slack slack / dominance Compaction policy: drop cuts slack at the current optimum, or keep per recourse column the oldest maximum over the last trial points.
FLEXTOOL_BENDERS_CUT_WINDOW 10 positive integer Trial-point window of the dominance policy.
FLEXTOOL_BENDERS_REGION_DUALS basic basic / interior Duals for the cut slopes: vertex duals with crossover, or barrier duals without crossover (a central point of a degenerate dual face; no warm start).
FLEXTOOL_BENDERS_VERBOSE unset any value Show the HiGHS log of every master and region solve (by default they are silent and the per-iteration bound log shows progress).
FLEXTOOL_BENDERS_PIN_DIAGNOSTIC unset parquet path Pin diagnostic: instead of iterating, evaluate the decomposition once at the monolith's coupling flows (columns p, source, sink, d, t, value) and report whether a region's recourse blows up.
FLEXTOOL_BENDERS_PIN_MONOLITH_OBJ unset float (real units) Monolith objective for the pin diagnostic's exactness check (Σ region cost + master ≈ monolith).
FLEXTOOL_BENDERS_PIN_BLOWUP_MULT 100 float Pin diagnostic: a region whose cost exceeds this multiple of its stand-alone cost counts as blown up.

Checks and modes

Variable Default Set to What it does
FLEXTOOL_AUTOSCALE_STRICT unset (off) 1 A variable, constraint or parameter missing from the autoscale registries raises instead of the solve silently falling back to an unscaled LP. Set it in tests that exercise autoscale (CLAUDE.md invariant 1).
FLEXTOOL_AXIS_ENUMS unset (off) 1 Experimental axis-Enum mode for the whole run (axes typed as polars Enums instead of Utf8). Development and tests only.
FLEXTOOL_FORCE_ROW_SCALING unset 1 / true / yes / on Turn on the legacy node / group balance row scaling (p_use_row_scaling=1); every solve has it off otherwise. Used by the un-scaling benchmark.
FLEXTOOL_SKIP_SOLVER_PROBE unset 1 Skip the start-up probe of commercial solver licences (avoids the FICO Xpress Community licence warning). The test conftest sets it.
FLEXTOOL_NATIVE_SCENARIO unset scenario name Scenario of run_chain when neither the work folder name (work_<scenario>) nor an argument gives it.
FLEXTOOL_AUDIT_SOURCES unset (off) 1 Append every Provider entry with a source tag (entries injected between solves) to <work_folder>/audit_sources.log, per sub-solve.
FLEXTOOL_LEVEL_RELEASE_AUDIT unset (off) 1 Record solves whose HiGHS instance is still alive after its level is finished (memory-release audit).
FLEXTOOL_DUMP_CSVS unset (off) 1 With --csv-dump, also write the eight largest debug CSVs (p_flow_max, pdtProcess*, pdtNode*, ptNode_inflow), which are not read by any output step.
FLEXTOOL_COLD_KEEP_PROVIDER unset (off) 1 Under --save-memory, keep the data provider between cold solves instead of rebuilding it (less database reading, higher steady memory).
FLEXTOOL_RSS_BUDGET_MB unset (no eviction) MB RSS above which the data provider evicts cached frames (subject to their lifetime).
FLEXTOOL_WARM_AB_MARGIN 0.10 float Warm-start first-transfer test: the basis is kept when the warm solve takes at most 1 + margin times the cold solve; a negative value forces the "slower" verdict (tests).
FLEXTOOL_DISABLE_AUTOSCALE_CACHE unset 1 Recompute the autoscale plan in every roll instead of reusing it (A/B check).
FLEXTOOL_DISABLE_OUTPUT_HOIST unset 1 Fetch the solution arrays once per output instead of once per solve (A/B check).

Memory and timing diagnostics

All off by default, with no overhead when unset.

Variable Default Set to What it does
FLEXTOOL_MEMORY_DIAGNOSTICS unset (off) 1 Per-checkpoint memory recorder with tracemalloc; writes solve_data/memory_diagnostics.csv. --debug sets it.
FLEXTOOL_MEMORY_VERBOSE unset (off) 1 Print every phase in the [mem] table, not only the main ones. --debug sets it.
FLEXTOOL_MEM_SAMPLER unset (off) 1 / true / yes Background thread that samples RSS at a fixed interval; catches peaks between checkpoints.
FLEXTOOL_MEM_SAMPLER_LOG /tmp/flextool_mem_sampler_<pid>.log path Sampler output.
FLEXTOOL_MEM_SAMPLER_INTERVAL_MS 100 (20–10000) milliseconds Sampler interval.
FLEXTOOL_PHASE_TIMING unset (off) 1 Per-iteration rows (preprocessing / lp_build / solve / handoff, warm_used) in timings.csv. warm_used is a flag in the seconds column (1 = warm start used), not a time. Always-on rows: read_input, preprocessing_global, roll_setup, all_solves, write_outputs/*, total.
FLEXTOOL_PHASE_PROFILE unset (off) 1 One epoch-stamped RSS line per orchestration phase on stderr (aligns with the sampler log).
FLEXTOOL_PYRAMID_PROFILE unset (off) 1 One [pyramid profile] RSS line per preprocessing emit on stderr.
FLEXTOOL_AUTOSCALE_PROFILE unset (off) 1 RSS markers around the autoscale steps.
FLEXTOOL_BUILD_PROFILE unset (off) 1 One RSS line per model-build step on stderr.
FLEXTOOL_LOADFLEX_PROFILE unset (off) 1 One RSS line per data-load step on stderr.
POLAR_HIGH_LAYER2_PROFILE unset (off) 1 One [layer2-bucket profile] line per term of the autoscale Layer 2 coefficient walk. Read by FlexTool's engine/autoscale/_layer2.py, not by polar-high.
POLAR_HIGH_RANGES_MAX_FAMILY_ROWS 1000000 integer Only with a polar-high that has no bounded coefficient walk: constraint families with more rows are skipped in Layer 2 bucketing. Read by FlexTool's _layer2.py.

Example — find a transient RSS peak the per-phase recorder misses:

FLEXTOOL_MEM_SAMPLER=1 FLEXTOOL_MEM_SAMPLER_INTERVAL_MS=50 \
    python run_flextool.py input.sqlite output_info.sqlite --scenario-name base

Run record

Each run writes _run_status.json and _run.log into its output_parquet/<run>/ folder. _run.log is written by the process that holds the run's output pipe, when there is one.

Variable Default Set to What it does
FLEXTOOL_RUN_LOG_OWNER unset 1 Set by the GUI and flextool-run in the environment of the engine run they start (only that direct child; the engine removes it, so no run it starts sees it). It tells the engine that its parent writes _run.log from the output pipe, with the native solver lines and crash dumps: the engine prints one marker line for the parent instead of copying its own console output into the log. Not for use by hand.
FLEXTOOL_RUN_STOP_FILE unset a file path Set by the GUI in the environment of a calibration or representative-period job, and inherited by every flextool-run supervisor that job starts. When the file appears (the GUI writes the reason into it when the job is stopped), the supervisor kills its engine and records the run as killed with that reason; a supervisor that finds it before its engine starts runs nothing. The supervisor leaves it out of the engine's environment. Not for use by hand.

User folders

FlexTool keeps its per-user files (the AI assistant's settings, saved chats, usage ledger, key file and caches) in the platform's user config and cache folders, found with platformdirs.

Variable Default Set to What it does
FLEXTOOL_USER_HOME unset (the platform's folders) folder FlexTool's user config folder becomes <folder>/config and its user cache folder <folder>/cache. The test suite sets it for every test process and every process a test starts (tests/user_dirs_guard.py), so no test reads or writes the real user folders.

Process level

Set when flextool is imported, with setdefault semantics: a value already in the environment wins.

Variable FlexTool sets What it does
POLARS_ENGINE_AFFINITY in-memory polars' engine choice. FlexTool's results are verified only on the in-memory engine; the streaming engine changes row order and summation order.
_RJEM_MALLOC_CONF dirty_decay_ms:1000,muzzy_decay_ms:0 Settings of polars' jemalloc allocator: return freed pages to the system, which roughly halves peak memory on long runs. When polars was imported before flextool, FlexTool sets the decay at run time instead.