fix(install): use --extra all not --all-extras; drop lazy-covered extras from [all]#24515
Conversation
… extras from [all]
Two coupled fixes for the Windows install hang where uv sync built
python-olm from sdist and failed on missing make.
# Root cause: --all-extras vs --extra all (credit: ethernet)
`uv sync --all-extras` installs every key in [project.optional-
dependencies], bypassing the curated [all] extra entirely. So even
when [all] excluded [matrix], [rl], [yc-bench], etc., the installer
pulled them anyway because they were still defined as extras. On
Windows that meant python-olm (no wheel, needs make to build from
sdist) and the install died there.
The right flag is `--extra all` — install just the [all] extra's
contents, respecting curation. Empirically verified via dry-run:
--all-extras: pulls python-olm, mautrix, ctranslate2, onnxruntime,
atroposlib, tinker, wandb, modal, daytona, vercel,
python-telegram-bot, discord.py, slack-bolt,
dingtalk-stream, lark-oapi, anthropic, boto3,
edge-tts, elevenlabs, exa-py, fal-client, faster-
whisper, firecrawl-py, honcho-ai, parallel-web
--extra all: pulls none of those — just [all]'s curated set
Dockerfile already uses `--extra all` (with comment explaining the
gotcha) — knowledge existed; the gap was install.sh / install.ps1 /
setup-hermes.sh.
Sites fixed: scripts/install.sh L1118, scripts/install.ps1 L809,
setup-hermes.sh L245.
# Companion fix: drop lazy-covered extras from [all]
`tools/lazy_deps.py` already covers anthropic, bedrock, exa,
firecrawl, parallel-web, fal, edge-tts, elevenlabs, modal, daytona,
vercel, all messaging platforms (telegram/discord/slack/matrix/
dingtalk/feishu), honcho, and faster-whisper. They were ALSO in
[all], which defeats the whole point of lazy-install — fresh
installs eager-pulled them and inherited whatever was broken
upstream (the matrix → python-olm → no Windows wheel chain being
the proximate symptom).
[all] now contains only what genuinely can't be lazy-installed:
cron, cli, dev, pty, mcp, homeassistant, sms, acp, google, web,
youtube. Same trim applied to [termux-all]. New regression test
asserts the contract: every extra in LAZY_DEPS must NOT also appear
in [all].
# Companion fix: surface uv progress + errors
setup-hermes.sh's hash-verified path swallowed uv's stderr to a
tempfile, identical to the install.sh bug fixed in PR #24504. Same
fix applied: stream stderr through directly so users see live
progress instead of staring at a frozen prompt.
# Files
- pyproject.toml: trim [all] and [termux-all] to non-lazy extras only.
- scripts/install.sh: --all-extras → --extra all; trim _ALL_EXTRAS /
_PYPI_EXTRAS to match.
- scripts/install.ps1: --all-extras → --extra all; trim $allExtras /
$pypiExtras to match.
- setup-hermes.sh: --all-extras → --extra all; stream stderr.
- tests/test_project_metadata.py: invert matrix-in-[all] assertion;
add lazy-coverage contract test.
- uv.lock: regenerated.
# Validation
5/5 metadata tests pass. 37/37 in update_autostash + tool_token_
estimation. `uv lock --check` passes. Empirical dry-run confirms
`--extra all` excludes python-olm + RL chain on the new lockfile.
🔎 Lint report:
|
ethernet's review point: the previous patch left two hand-mirrored
copies of [all]'s contents (in install.sh's $_ALL_EXTRAS and
install.ps1's $allExtras). That guarantees future drift the next
time pyproject.toml's [all] changes.
Now both scripts parse pyproject.toml at install time using stdlib
tomllib (Python 3.11+, which the bootstrap step already requires).
Single source of truth. The only purpose of the parsed list is to
build the 'Tier 2: [all] minus broken extras' fallback spec — so we
parse, filter against $brokenExtras, and rebuild the .[a,b,c] spec.
Also: removed redundant fallback tiers.
Before: Tier 1 [all]
Tier 2 [all] minus broken
Tier 3 PyPI-only extras (no git deps)
Tier 4 [web,mcp,cron,cli,messaging,dev]
Tier 5 .
After: Tier 1 [all]
Tier 2 [all] minus broken
Tier 3 .
Tier 3 (PyPI-only) and Tier 4 (dashboard+core) used to dodge the [rl]
git+sdist deps and the [matrix] python-olm build. Both are no longer
in [all] post-2026-05-12 lazy-install migration, so the carve-out
tiers had no remaining content. Tier 4 also referenced [messaging],
which is now lazy-installed — the hardcoded fallback was actually
inconsistent with the new policy.
Defensive fallback: if tomllib parse fails (corrupted pyproject,
unexpected schema), Tier 2 collapses to '.[all]' (same as Tier 1) so
the broken-extras path becomes a no-op rather than crashing.
Matrix is the one messaging platform that has no working install path on Windows: [matrix] -> mautrix[encryption] -> python-olm, which has Linux-only wheels and needs make + libolm to build from sdist. The [all] cleanup in this PR keeps mautrix out of fresh installs, but a user who picked Matrix in 'hermes setup gateway' would still walk into the same sdist build failure when the wizard tried to install the extra. Hide the option at the picker so users never get the chance to try. The gate lives in _all_platforms() — single source of truth for the setup wizard, the curses gateway-config menu, and any future picker. Adapter loading at runtime is intentionally NOT gated: users who already have MATRIX_* env vars set (e.g. config copied from a Linux install) keep working if they somehow have python-olm available. This is the lowest-friction fix — picker visibility only. Tests cover linux/darwin/win32 and verify other platforms aren't collateral damage.
There was a problem hiding this comment.
Pull request overview
This PR fixes Windows install failures/hangs caused by using uv sync --all-extras (which installs every optional-dependency group and bypasses the curated [all] extra), and aligns the [all] / termux-all extras with the project’s lazy-install boundary.
Changes:
- Switch installer paths (
install.sh,install.ps1,setup-hermes.sh) fromuv sync --all-extras --lockedtouv sync --extra all --locked, and simplify tier logic by parsing[all]frompyproject.tomlat runtime. - Update
pyproject.tomlso[all]/termux-allexclude extras covered by lazy-install (e.g. matrix, slack, messaging backends), and regenerateuv.lock. - Add/adjust tests to enforce packaging metadata contracts and add Windows-specific Matrix gating in the CLI platform picker.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/install.sh |
Uses --extra all and parses [all] for tiered fallbacks to avoid drift and Windows sdist builds. |
scripts/install.ps1 |
Same --extra all fix + tier list parsing to avoid hand-mirrored extras. |
setup-hermes.sh |
Uses --extra all and streams uv output for visibility. |
pyproject.toml |
Trims [all] / [termux-all] to respect lazy-install boundaries; updates policy comments. |
uv.lock |
Regenerated to reflect new [all] / [termux-all] composition. |
tests/test_project_metadata.py |
Updates matrix-in-all assertion; adds a “lazy-covered extras excluded from all” contract test. |
hermes_cli/gateway.py |
Adds Windows-specific platform gating to hide Matrix in _all_platforms(). |
tests/hermes_cli/test_gateway_platform_gating.py |
New regression tests for the Windows Matrix gating behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_lazy_installable_extras_excluded_from_all(): | ||
| """Policy (2026-05-12): every extra that has a `LAZY_DEPS` entry | ||
| in `tools/lazy_deps.py` must be excluded from [all]. | ||
|
|
||
| The lazy-install system exists so one quarantined PyPI release | ||
| (e.g. mistralai 2.4.6) can't break every fresh install. Putting a | ||
| backend in BOTH [all] and LAZY_DEPS defeats that — fresh installs | ||
| eager-install it and inherit whatever's broken upstream. | ||
|
|
||
| If you're tempted to add an opt-in backend to [all] for "convenience," | ||
| add it to `LAZY_DEPS` instead so it installs at first use. | ||
| """ | ||
| optional_dependencies = _load_optional_dependencies() | ||
|
|
||
| # Hard-coded mirror of the extras that are in LAZY_DEPS as of | ||
| # 2026-05-12. This list intentionally duplicates rather than | ||
| # imports tools/lazy_deps.py so the test stays a contract — if | ||
| # someone adds a new lazy-install backend, they have to update | ||
| # this list AND verify [all] doesn't contain it. |
| # Best-effort "install all" profile for Termux. Same policy as [all]: | ||
| # only includes extras that aren't covered by `tools/lazy_deps.py`. | ||
| # Backends like telegram/slack/dingtalk/feishu/honcho lazy-install at | ||
| # first use, so they're no longer eager-installed here. |
| # Policy (2026-05-12): `[all]` includes only extras that genuinely | ||
| # CAN'T be lazy-installed via `tools/lazy_deps.py` — i.e. things every | ||
| # session can use, things needed before the agent loop is alive | ||
| # (terminal/CLI), and skill deps that packagers (Nix, AUR, Homebrew) | ||
| # need in the wheel. Anything an opt-in backend (provider, search, | ||
| # TTS, image, memory, messaging platform, terminal sandbox) needs | ||
| # MUST live exclusively in `LAZY_DEPS` and resolve at first use — | ||
| # otherwise one quarantined PyPI release breaks every fresh install. |
|
I use the nixos module and matrix with encryption, afer flake update I got this and found my matrix would not connect anymore. I changed flake input to the rev prior to this merge - back to normal. Is there something I need to configure? 2026/05/20 services.hermes-agent = {
extraDependencyGroups = [ "matrix" ];
}; |
…ertions Addresses Copilot review feedback on NousResearch#24601: The original commit used `pytest.importorskip("botocore")` so the three TestResolveBedrocRegion tests would not error when botocore is absent from a fresh `.[all,dev]` install (after `[bedrock]` left `[all]` in NousResearch#24515). Copilot pointed out that this means the CI baseline — where botocore is intentionally absent — no longer asserts the critical `resolve_bedrock_region` fallback behaviour at all; the tests just silently skip. Switch to the same `patch.dict("sys.modules", {"botocore": MagicMock(), "botocore.session": MagicMock()})` pattern already used elsewhere in this file (TestResolveAwsAuthEnvVar, TestHasAwsCredentials). The stub makes `import botocore.session` succeed even without the real package, so the assertions are exercised on every CI install profile, including the baseline that triggered this PR. Verified locally: 112 passed / 6 skipped (the skipped tests are for genuine botocore.exceptions imports, not the region-resolution path). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… extras from [all] (NousResearch#24515) * fix(install): use `--extra all` not `--all-extras`; drop lazy-covered extras from [all] Two coupled fixes for the Windows install hang where uv sync built python-olm from sdist and failed on missing make. # Root cause: --all-extras vs --extra all (credit: ethernet) `uv sync --all-extras` installs every key in [project.optional- dependencies], bypassing the curated [all] extra entirely. So even when [all] excluded [matrix], [rl], [yc-bench], etc., the installer pulled them anyway because they were still defined as extras. On Windows that meant python-olm (no wheel, needs make to build from sdist) and the install died there. The right flag is `--extra all` — install just the [all] extra's contents, respecting curation. Empirically verified via dry-run: --all-extras: pulls python-olm, mautrix, ctranslate2, onnxruntime, atroposlib, tinker, wandb, modal, daytona, vercel, python-telegram-bot, discord.py, slack-bolt, dingtalk-stream, lark-oapi, anthropic, boto3, edge-tts, elevenlabs, exa-py, fal-client, faster- whisper, firecrawl-py, honcho-ai, parallel-web --extra all: pulls none of those — just [all]'s curated set Dockerfile already uses `--extra all` (with comment explaining the gotcha) — knowledge existed; the gap was install.sh / install.ps1 / setup-hermes.sh. Sites fixed: scripts/install.sh L1118, scripts/install.ps1 L809, setup-hermes.sh L245. # Companion fix: drop lazy-covered extras from [all] `tools/lazy_deps.py` already covers anthropic, bedrock, exa, firecrawl, parallel-web, fal, edge-tts, elevenlabs, modal, daytona, vercel, all messaging platforms (telegram/discord/slack/matrix/ dingtalk/feishu), honcho, and faster-whisper. They were ALSO in [all], which defeats the whole point of lazy-install — fresh installs eager-pulled them and inherited whatever was broken upstream (the matrix → python-olm → no Windows wheel chain being the proximate symptom). [all] now contains only what genuinely can't be lazy-installed: cron, cli, dev, pty, mcp, homeassistant, sms, acp, google, web, youtube. Same trim applied to [termux-all]. New regression test asserts the contract: every extra in LAZY_DEPS must NOT also appear in [all]. # Companion fix: surface uv progress + errors setup-hermes.sh's hash-verified path swallowed uv's stderr to a tempfile, identical to the install.sh bug fixed in PR NousResearch#24504. Same fix applied: stream stderr through directly so users see live progress instead of staring at a frozen prompt. # Files - pyproject.toml: trim [all] and [termux-all] to non-lazy extras only. - scripts/install.sh: --all-extras → --extra all; trim _ALL_EXTRAS / _PYPI_EXTRAS to match. - scripts/install.ps1: --all-extras → --extra all; trim $allExtras / $pypiExtras to match. - setup-hermes.sh: --all-extras → --extra all; stream stderr. - tests/test_project_metadata.py: invert matrix-in-[all] assertion; add lazy-coverage contract test. - uv.lock: regenerated. # Validation 5/5 metadata tests pass. 37/37 in update_autostash + tool_token_ estimation. `uv lock --check` passes. Empirical dry-run confirms `--extra all` excludes python-olm + RL chain on the new lockfile. * fix(install): parse [all] from pyproject.toml instead of mirroring it ethernet's review point: the previous patch left two hand-mirrored copies of [all]'s contents (in install.sh's $_ALL_EXTRAS and install.ps1's $allExtras). That guarantees future drift the next time pyproject.toml's [all] changes. Now both scripts parse pyproject.toml at install time using stdlib tomllib (Python 3.11+, which the bootstrap step already requires). Single source of truth. The only purpose of the parsed list is to build the 'Tier 2: [all] minus broken extras' fallback spec — so we parse, filter against $brokenExtras, and rebuild the .[a,b,c] spec. Also: removed redundant fallback tiers. Before: Tier 1 [all] Tier 2 [all] minus broken Tier 3 PyPI-only extras (no git deps) Tier 4 [web,mcp,cron,cli,messaging,dev] Tier 5 . After: Tier 1 [all] Tier 2 [all] minus broken Tier 3 . Tier 3 (PyPI-only) and Tier 4 (dashboard+core) used to dodge the [rl] git+sdist deps and the [matrix] python-olm build. Both are no longer in [all] post-2026-05-12 lazy-install migration, so the carve-out tiers had no remaining content. Tier 4 also referenced [messaging], which is now lazy-installed — the hardcoded fallback was actually inconsistent with the new policy. Defensive fallback: if tomllib parse fails (corrupted pyproject, unexpected schema), Tier 2 collapses to '.[all]' (same as Tier 1) so the broken-extras path becomes a no-op rather than crashing. * fix(gateway): hide Matrix from setup picker on Windows Matrix is the one messaging platform that has no working install path on Windows: [matrix] -> mautrix[encryption] -> python-olm, which has Linux-only wheels and needs make + libolm to build from sdist. The [all] cleanup in this PR keeps mautrix out of fresh installs, but a user who picked Matrix in 'hermes setup gateway' would still walk into the same sdist build failure when the wizard tried to install the extra. Hide the option at the picker so users never get the chance to try. The gate lives in _all_platforms() — single source of truth for the setup wizard, the curses gateway-config menu, and any future picker. Adapter loading at runtime is intentionally NOT gated: users who already have MATRIX_* env vars set (e.g. config copied from a Linux install) keep working if they somehow have python-olm available. This is the lowest-friction fix — picker visibility only. Tests cover linux/darwin/win32 and verify other platforms aren't collateral damage.
… extras from [all] (NousResearch#24515) * fix(install): use `--extra all` not `--all-extras`; drop lazy-covered extras from [all] Two coupled fixes for the Windows install hang where uv sync built python-olm from sdist and failed on missing make. # Root cause: --all-extras vs --extra all (credit: ethernet) `uv sync --all-extras` installs every key in [project.optional- dependencies], bypassing the curated [all] extra entirely. So even when [all] excluded [matrix], [rl], [yc-bench], etc., the installer pulled them anyway because they were still defined as extras. On Windows that meant python-olm (no wheel, needs make to build from sdist) and the install died there. The right flag is `--extra all` — install just the [all] extra's contents, respecting curation. Empirically verified via dry-run: --all-extras: pulls python-olm, mautrix, ctranslate2, onnxruntime, atroposlib, tinker, wandb, modal, daytona, vercel, python-telegram-bot, discord.py, slack-bolt, dingtalk-stream, lark-oapi, anthropic, boto3, edge-tts, elevenlabs, exa-py, fal-client, faster- whisper, firecrawl-py, honcho-ai, parallel-web --extra all: pulls none of those — just [all]'s curated set Dockerfile already uses `--extra all` (with comment explaining the gotcha) — knowledge existed; the gap was install.sh / install.ps1 / setup-hermes.sh. Sites fixed: scripts/install.sh L1118, scripts/install.ps1 L809, setup-hermes.sh L245. # Companion fix: drop lazy-covered extras from [all] `tools/lazy_deps.py` already covers anthropic, bedrock, exa, firecrawl, parallel-web, fal, edge-tts, elevenlabs, modal, daytona, vercel, all messaging platforms (telegram/discord/slack/matrix/ dingtalk/feishu), honcho, and faster-whisper. They were ALSO in [all], which defeats the whole point of lazy-install — fresh installs eager-pulled them and inherited whatever was broken upstream (the matrix → python-olm → no Windows wheel chain being the proximate symptom). [all] now contains only what genuinely can't be lazy-installed: cron, cli, dev, pty, mcp, homeassistant, sms, acp, google, web, youtube. Same trim applied to [termux-all]. New regression test asserts the contract: every extra in LAZY_DEPS must NOT also appear in [all]. # Companion fix: surface uv progress + errors setup-hermes.sh's hash-verified path swallowed uv's stderr to a tempfile, identical to the install.sh bug fixed in PR NousResearch#24504. Same fix applied: stream stderr through directly so users see live progress instead of staring at a frozen prompt. # Files - pyproject.toml: trim [all] and [termux-all] to non-lazy extras only. - scripts/install.sh: --all-extras → --extra all; trim _ALL_EXTRAS / _PYPI_EXTRAS to match. - scripts/install.ps1: --all-extras → --extra all; trim $allExtras / $pypiExtras to match. - setup-hermes.sh: --all-extras → --extra all; stream stderr. - tests/test_project_metadata.py: invert matrix-in-[all] assertion; add lazy-coverage contract test. - uv.lock: regenerated. # Validation 5/5 metadata tests pass. 37/37 in update_autostash + tool_token_ estimation. `uv lock --check` passes. Empirical dry-run confirms `--extra all` excludes python-olm + RL chain on the new lockfile. * fix(install): parse [all] from pyproject.toml instead of mirroring it ethernet's review point: the previous patch left two hand-mirrored copies of [all]'s contents (in install.sh's $_ALL_EXTRAS and install.ps1's $allExtras). That guarantees future drift the next time pyproject.toml's [all] changes. Now both scripts parse pyproject.toml at install time using stdlib tomllib (Python 3.11+, which the bootstrap step already requires). Single source of truth. The only purpose of the parsed list is to build the 'Tier 2: [all] minus broken extras' fallback spec — so we parse, filter against $brokenExtras, and rebuild the .[a,b,c] spec. Also: removed redundant fallback tiers. Before: Tier 1 [all] Tier 2 [all] minus broken Tier 3 PyPI-only extras (no git deps) Tier 4 [web,mcp,cron,cli,messaging,dev] Tier 5 . After: Tier 1 [all] Tier 2 [all] minus broken Tier 3 . Tier 3 (PyPI-only) and Tier 4 (dashboard+core) used to dodge the [rl] git+sdist deps and the [matrix] python-olm build. Both are no longer in [all] post-2026-05-12 lazy-install migration, so the carve-out tiers had no remaining content. Tier 4 also referenced [messaging], which is now lazy-installed — the hardcoded fallback was actually inconsistent with the new policy. Defensive fallback: if tomllib parse fails (corrupted pyproject, unexpected schema), Tier 2 collapses to '.[all]' (same as Tier 1) so the broken-extras path becomes a no-op rather than crashing. * fix(gateway): hide Matrix from setup picker on Windows Matrix is the one messaging platform that has no working install path on Windows: [matrix] -> mautrix[encryption] -> python-olm, which has Linux-only wheels and needs make + libolm to build from sdist. The [all] cleanup in this PR keeps mautrix out of fresh installs, but a user who picked Matrix in 'hermes setup gateway' would still walk into the same sdist build failure when the wizard tried to install the extra. Hide the option at the picker so users never get the chance to try. The gate lives in _all_platforms() — single source of truth for the setup wizard, the curses gateway-config menu, and any future picker. Adapter loading at runtime is intentionally NOT gated: users who already have MATRIX_* env vars set (e.g. config copied from a Linux install) keep working if they somehow have python-olm available. This is the lowest-friction fix — picker visibility only. Tests cover linux/darwin/win32 and verify other platforms aren't collateral damage.
… extras from [all] (NousResearch#24515) * fix(install): use `--extra all` not `--all-extras`; drop lazy-covered extras from [all] Two coupled fixes for the Windows install hang where uv sync built python-olm from sdist and failed on missing make. # Root cause: --all-extras vs --extra all (credit: ethernet) `uv sync --all-extras` installs every key in [project.optional- dependencies], bypassing the curated [all] extra entirely. So even when [all] excluded [matrix], [rl], [yc-bench], etc., the installer pulled them anyway because they were still defined as extras. On Windows that meant python-olm (no wheel, needs make to build from sdist) and the install died there. The right flag is `--extra all` — install just the [all] extra's contents, respecting curation. Empirically verified via dry-run: --all-extras: pulls python-olm, mautrix, ctranslate2, onnxruntime, atroposlib, tinker, wandb, modal, daytona, vercel, python-telegram-bot, discord.py, slack-bolt, dingtalk-stream, lark-oapi, anthropic, boto3, edge-tts, elevenlabs, exa-py, fal-client, faster- whisper, firecrawl-py, honcho-ai, parallel-web --extra all: pulls none of those — just [all]'s curated set Dockerfile already uses `--extra all` (with comment explaining the gotcha) — knowledge existed; the gap was install.sh / install.ps1 / setup-hermes.sh. Sites fixed: scripts/install.sh L1118, scripts/install.ps1 L809, setup-hermes.sh L245. # Companion fix: drop lazy-covered extras from [all] `tools/lazy_deps.py` already covers anthropic, bedrock, exa, firecrawl, parallel-web, fal, edge-tts, elevenlabs, modal, daytona, vercel, all messaging platforms (telegram/discord/slack/matrix/ dingtalk/feishu), honcho, and faster-whisper. They were ALSO in [all], which defeats the whole point of lazy-install — fresh installs eager-pulled them and inherited whatever was broken upstream (the matrix → python-olm → no Windows wheel chain being the proximate symptom). [all] now contains only what genuinely can't be lazy-installed: cron, cli, dev, pty, mcp, homeassistant, sms, acp, google, web, youtube. Same trim applied to [termux-all]. New regression test asserts the contract: every extra in LAZY_DEPS must NOT also appear in [all]. # Companion fix: surface uv progress + errors setup-hermes.sh's hash-verified path swallowed uv's stderr to a tempfile, identical to the install.sh bug fixed in PR NousResearch#24504. Same fix applied: stream stderr through directly so users see live progress instead of staring at a frozen prompt. # Files - pyproject.toml: trim [all] and [termux-all] to non-lazy extras only. - scripts/install.sh: --all-extras → --extra all; trim _ALL_EXTRAS / _PYPI_EXTRAS to match. - scripts/install.ps1: --all-extras → --extra all; trim $allExtras / $pypiExtras to match. - setup-hermes.sh: --all-extras → --extra all; stream stderr. - tests/test_project_metadata.py: invert matrix-in-[all] assertion; add lazy-coverage contract test. - uv.lock: regenerated. # Validation 5/5 metadata tests pass. 37/37 in update_autostash + tool_token_ estimation. `uv lock --check` passes. Empirical dry-run confirms `--extra all` excludes python-olm + RL chain on the new lockfile. * fix(install): parse [all] from pyproject.toml instead of mirroring it ethernet's review point: the previous patch left two hand-mirrored copies of [all]'s contents (in install.sh's $_ALL_EXTRAS and install.ps1's $allExtras). That guarantees future drift the next time pyproject.toml's [all] changes. Now both scripts parse pyproject.toml at install time using stdlib tomllib (Python 3.11+, which the bootstrap step already requires). Single source of truth. The only purpose of the parsed list is to build the 'Tier 2: [all] minus broken extras' fallback spec — so we parse, filter against $brokenExtras, and rebuild the .[a,b,c] spec. Also: removed redundant fallback tiers. Before: Tier 1 [all] Tier 2 [all] minus broken Tier 3 PyPI-only extras (no git deps) Tier 4 [web,mcp,cron,cli,messaging,dev] Tier 5 . After: Tier 1 [all] Tier 2 [all] minus broken Tier 3 . Tier 3 (PyPI-only) and Tier 4 (dashboard+core) used to dodge the [rl] git+sdist deps and the [matrix] python-olm build. Both are no longer in [all] post-2026-05-12 lazy-install migration, so the carve-out tiers had no remaining content. Tier 4 also referenced [messaging], which is now lazy-installed — the hardcoded fallback was actually inconsistent with the new policy. Defensive fallback: if tomllib parse fails (corrupted pyproject, unexpected schema), Tier 2 collapses to '.[all]' (same as Tier 1) so the broken-extras path becomes a no-op rather than crashing. * fix(gateway): hide Matrix from setup picker on Windows Matrix is the one messaging platform that has no working install path on Windows: [matrix] -> mautrix[encryption] -> python-olm, which has Linux-only wheels and needs make + libolm to build from sdist. The [all] cleanup in this PR keeps mautrix out of fresh installs, but a user who picked Matrix in 'hermes setup gateway' would still walk into the same sdist build failure when the wizard tried to install the extra. Hide the option at the picker so users never get the chance to try. The gate lives in _all_platforms() — single source of truth for the setup wizard, the curses gateway-config menu, and any future picker. Adapter loading at runtime is intentionally NOT gated: users who already have MATRIX_* env vars set (e.g. config copied from a Linux install) keep working if they somehow have python-olm available. This is the lowest-friction fix — picker visibility only. Tests cover linux/darwin/win32 and verify other platforms aren't collateral damage.
Summary
Windows installs no longer try to build python-olm from sdist.
hermes-agent[all]now respects the lazy-install boundary instead of fighting it.Two coupled bugs caused the Windows install hang Ryan reported (python-olm fails on
makebecause Windows has no make and python-olm has no Windows wheel):Wrong uv flag (credit: @ethernet8023 — "rather than
--all-extras, don't we actually want--extras all?").uv sync --all-extrasinstalls every key in[project.optional-dependencies], bypassing the curated[all]extra entirely. That's why the matrix Linux marker on[all]didn't help — the installer wasn't honoring[all]at all.[all]andLAZY_DEPSoverlapped. Backends that already lazy-install viatools/lazy_deps.py(anthropic, exa, firecrawl, fal, modal, matrix, slack, etc.) were ALSO in[all]. So fresh installs eager-pulled them and inherited any upstream breakage — the whole point of the lazy-install migration was to avoid that.Changes
scripts/install.sh,scripts/install.ps1,setup-hermes.shuv sync --all-extras --locked→uv sync --extra all --locked_ALL_EXTRAS/$allExtras/_PYPI_EXTRAS/$pypiExtrastier lists to match the new[all].setup-hermes.shnow also streams uv's stderr through (same fix as PR fix(install): surface uv install + uv.lock sync errors instead of silently hanging #24504 for install.sh).Dockerfilealready used--extra allwith a comment explaining the gotcha — knowledge existed in the codebase; the gap was the install scripts.pyproject.toml[all]is now:cron, cli, dev, pty, mcp, homeassistant, sms, acp, google, web, youtube— only extras that genuinely can't be lazy-installed.tools/lazy_deps.py):anthropic, bedrock, exa, firecrawl, parallel-web, fal, edge-tts, tts-premium, voice, modal, daytona, vercel, messaging, matrix, slack, honcho, dingtalk, feishu.[termux-all].pip install hermes-agent[<extra>]; nothing was removed from[project.optional-dependencies].tests/test_project_metadata.pytest_lazy_installable_extras_excluded_from_all— contract test asserting every extra in LAZY_DEPS is excluded from [all].uv.lockregenerated.Validation
--extra allskips matrix + python-olm entirely.--all-extraspulls every backend regardless of [all] curation. One quarantined PyPI release breaks every install.--extra allhonors curation. Quarantined backends (e.g. mistralai 2026-05-12) only hit users who explicitly install them.--all-extraspulls 25+ lazy-covered packages: python-olm, mautrix, ctranslate2, onnxruntime, atroposlib (git+https), tinker (git+https), wandb, all messaging adapters, all TTS/STT, all search backends.--extra allpulls zero of them. Verified with the new lockfile.uv lock --checkNotes
This is the actual root cause of the screenshots you saw earlier today. PR #24504 fixed the visibility of the failure (live progress + actual error output), but the install was still doomed because
--all-extrasignored every guard[all]was supposed to provide. Combined, the two PRs mean: (a) Windows installs succeed, (b) when they don't, users see why instead of staring at a frozen prompt.