Skip to content

fix(terminal): make the foreground-timeout and disk-warning caps config keys - #575

Merged
Kyzcreig merged 1 commit into
mainfrom
fix/terminal-timeout-config-not-env
Aug 11, 2026
Merged

Kyzcreig merged 1 commit into
mainfrom
fix/terminal-timeout-config-not-env

Conversation

@Kyzcreig

Copy link
Copy Markdown
Collaborator

Two behavioral limits were env-var-only

TERMINAL_MAX_FOREGROUND_TIMEOUT and TERMINAL_DISK_WARNING_GB could only be set via environment variables. AGENTS.md is explicit:

New HERMES_* env vars for non-secret config… .env is for secrets only. All behavioral settings — timeouts, thresholds, feature flags — go in config.yaml.

Every other terminal.* knob already follows that rule through TERMINAL_CONFIG_ENV_MAP. These two were missed.

Adds terminal.max_foreground_timeout (default 600) and terminal.disk_warning_gb (default 500.0) — the same values as the historical env defaults, so nothing changes for anyone who doesn't set them. The env vars keep working; the map bridges config → env for child processes.

The non-obvious half — why a one-line map entry is NOT enough

FOREGROUND_MAX_TIMEOUT is a module constant evaluated at import time. The config→env bridge (_ensure_terminal_env_bridged) runs on first tool use — after import.

So adding the key to the map alone produces a knob that parses, validates, appears in hermes config… and does nothing. Enforcement would keep comparing against the pre-bridge value.

Enforcement now calls _foreground_max_timeout() / _disk_warning_gb(), which re-read the env after the bridge runs. The import-time constants stay as the fallback.

TERMINAL_SCHEMA is also a module constant, so the cap quoted in its timeout description is still the import-time number. That's cosmetic and deliberately left — enforcement is what matters, and the docstring says so, so nobody "fixes" it by reintroducing the frozen read.

Tests — 7, RED-proven

Reverting the enforcement site to the frozen constant (the naive map-entry-only fix) turns the source-contract test RED and names the problem. That test exists because an arithmetic assertion passes either way in a default environment, where the constant and the accessor hold the same value.

E2E through the real bridge, real config.yaml in a temp HERMES_HOME:

before bridge: 600  500.0
after  bridge: 2400 12.5

Baseline

tests/hermes_cli/ + tests/tools/  -k "terminal or config"

  branch     16 failed, 1120 passed
  fork/main  16 failed, 1113 passed   ← identical failure set

Zero new failures. The 16 are pre-existing on main and untouched by this diff; the +7 are this PR's tests.

…ig keys

`TERMINAL_MAX_FOREGROUND_TIMEOUT` and `TERMINAL_DISK_WARNING_GB` were
env-var-ONLY. Both are behavioral limits, and AGENTS.md is explicit that .env
is for secrets while behavioral settings belong in config.yaml. Every other
`terminal.*` knob already follows that rule via TERMINAL_CONFIG_ENV_MAP.

Adds `terminal.max_foreground_timeout` (default 600) and
`terminal.disk_warning_gb` (default 500.0) — same values as the historical env
defaults, so no behavior changes for anyone who does not set them. The env vars
keep working; the map bridges config -> env for child processes exactly as it
does for backend, cwd, timeout, and the rest.

THE NON-OBVIOUS HALF — why the one-line map entry is not enough

`FOREGROUND_MAX_TIMEOUT` is a module constant evaluated at IMPORT time, but the
config->env bridge (`_ensure_terminal_env_bridged`) runs on FIRST TOOL USE —
after import. So adding the key to the map alone produces a knob that parses,
validates, shows up in `hermes config`, and does nothing: enforcement would keep
comparing against the pre-bridge value.

The enforcement path now calls `_foreground_max_timeout()` / `_disk_warning_gb()`,
which re-read the env after the bridge has run. The import-time constants remain
as the fallback default.

`TERMINAL_SCHEMA` is a module constant, so the cap quoted in its `timeout`
description is still the import-time number. That is cosmetic and deliberately
left alone — enforcement is what matters, and it is correct. The docstring says
so, so nobody "fixes" it by reintroducing the frozen read.

TESTS (7, RED-proven)
Reverting the enforcement site to the frozen constant — i.e. the naive
map-entry-only fix — turns the source-contract test RED and names the problem.
That test exists because an arithmetic assertion passes either way in a default
environment, where the constant and the accessor hold the same value.

E2E through the real bridge with a real config.yaml in a temp HERMES_HOME:

    before bridge: 600  500.0
    after  bridge: 2400 12.5

BASELINE
tests/hermes_cli/ + tests/tools/ -k "terminal or config":
  branch   16 failed, 1120 passed
  fork/main 16 failed, 1113 passed   <- identical failure set
Zero new failures; the 16 are pre-existing on main and untouched by this diff.
@Kyzcreig Kyzcreig added the ci-reviewed CI-sensitive changes reviewed by maintainer label Aug 11, 2026
@Kyzcreig
Kyzcreig enabled auto-merge August 11, 2026 07:13
@Kyzcreig
Kyzcreig added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit da9b1c2 Aug 11, 2026
45 checks passed
@Kyzcreig
Kyzcreig deleted the fix/terminal-timeout-config-not-env branch August 11, 2026 07:32
Kyzcreig added a commit that referenced this pull request Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-reviewed CI-sensitive changes reviewed by maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant