# NousResearch/hermes-agent · Packaged installs failing to locate bundled TUI assets

## Open now

- 0 issues, 1 PR open on GitHub.
- PR #19525: fix(package): include TUI runtime assets in manifest

Most members concern the TUI (--tui / Chat tab) on packaged installs such as pip, pipx, and Homebrew, where a ui-tui workspace check or missing runtime assets in the package is reported alongside proposed changes to try the bundled TUI first, adjust manifests, or give clearer messages. One bug report (a bare FileNotFoundError) has too little detail to confirm it belongs to this theme.

## TL;DR

- 16 member(s): 0 open issue(s), 5 closed issue(s), 1 open PR(s), 1 merged PR(s), 9 PR(s) closed without merging.
- A fix was merged to main in PR #67116. Verify it addresses your case.
- **Recommended:** read PR #67116 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `partially_resolved` · deciding PR(s): `pr-67116`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.11`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #19514: \[Bug\]: MANIFEST.in missing ui-tui/ and scripts/ — hermes --tui crashes after pip install
- #24544: \[Bug\]: Homebrew / packaged installs advertise --tui but crash because ui-tui is not included in the installed package
- #30957: \[Bug\]: FileNotFoundError:  No such file or directory:
- #56665: Chat tab fails with "Chat unavailable: 1" on pip/pipx install — ui-tui workspace check runs before bundled-wheel fallback
- #57031: \[Bug\]: Installs from homebrew / linuxbrew cannot run TUI

## Prior & competing PRs

- **#24646: fix(cli): exit with clear message when ui-tui/ is missing in packaged installs**. closed without merge · fix tier `suggested`
  - maintainer direction: category `uncategorized`; implication `needs_llm`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#56669: fix(cli): check bundled TUI before workspace validation for pip/pipx installs**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#56672`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#56855: fix(dashboard): prefer bundled TUI for wheel chat**. closed without merge · fix tier `suggested`
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#56672`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#67116: fix(cli): try bundled TUI before requiring ui-tui workspace**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `contributors/emails/[redacted:email]`, `hermes_cli/main.py`, `tests/hermes_cli/test_tui_npm_install.py`
  - fix hunks:
  - `contributors/emails/[redacted:email]`

    ```diff
    @@ -0,0 +1,2 @@
    +lucaskvasirr
    +# PR #56672 salvage (fix(cli): try bundled TUI before requiring ui-tui workspace; #56665)
    ```
  - `hermes_cli/main.py`

    ```diff
    @@ -1766,10 +1766,14 @@ def _node_bin(bin: str) -> str:
             )
             sys.exit(1)
     
    -    if not ext_dir:
    -        _ensure_tui_workspace(tui_dir)
    -
         # 1. Prebuilt bundle (nix / packaged release): just run it.
    +    #
    +    # This must run BEFORE _ensure_tui_workspace() below. A pip/pipx install
    +    # ships hermes_cli/tui_dist/entry.js in the wheel but never ships ui-tui/
    +    # at all (that directory only exists in a git checkout) — so requiring
    +    # the workspace to exist first made every pip/pipx dashboard Chat tab
    +    # connection hard-exit before it ever got a chance to try the bundled
    +    # entry.js it already has. See #56665.
         if not tui_dev:
             if ext_dir:
                 p = Path(ext_dir)
    ```

    ```diff
    @@ -1783,6 +1787,11 @@ def _node_bin(bin: str) -> str:
                 node = _node_bin("node")
                 return [node, "--expose-gc", str(bundled)], bundled.parent
     
    +    # No prebuilt bundle available (or --dev, which never uses one) — we're
    +    # about to npm install/build from source, so the workspace must exist.
    +    if not ext_dir:
    +        _ensure_tui_workspace(tui_dir)
    +
         # 2. Normal flow: npm install if needed, always esbuild, then node dist/entry.js.
         #    --dev flow: npm install if needed, then tsx src/entry.tsx.
         #    Existing desktop behaviour runs npm from the workspace root.  Termux
    ```
  - `tests/hermes_cli/test_tui_npm_install.py`

    ```diff
    @@ -361,6 +361,79 @@ def fake_run(*args, **kwargs):
         _assert_utf8_replace_capture(calls[0][1])
     
     
    +def test_make_tui_argv_uses_bundled_tui_when_workspace_missing(
    +    tmp_path: Path, main_mod, monkeypatch
    +) -> None:
    +    """pip/pipx install regression (#56665): the wheel ships
    +    hermes_cli/tui_dist/entry.js but never ships ui-tui/ (that directory only
    +    exists in a git checkout). Before this fix, _make_tui_argv called
    +    _ensure_tui_workspace() unconditionally before checking for the bundled
    +    entry.js, so every pip/pipx dashboard Chat tab connection hard-exited
    +    with `sys.exit(1)` — surfaced to the user as the unhelpful "Chat
    +    unavailable: 1" — despite having a perfectly runnable bundled TUI on
    +    disk. The bundled-wheel shortcut must be tried first and succeed without
    +    ever touching the (missing) ui-tui workspace or git.
    +    """
    +    monkeypatch.delenv("HERMES_TUI_DIR", raising=False)
    +    monkeypatch.setattr(main_mod, "_ensure_tui_node", lambda: None)
    +
    +    bundled_entry = tmp_path / "bundled" / "entry.js"
    +    bundled_entry.parent.mkdir(parents=True)
    +    bundled_entry.write_text("// bundled TUI")
    +    monkeypatch.setattr(main_mod, "_find_bundled_tui", lambda: bundled_entry)
    +
    +    def which(name: str) -> str | None:
    +        if name == "node":
    +            return "/usr/bin/node"
    +        raise AssertionError(f"unexpected shutil.which({name!r}) call — bundled path must not need npm/git")
    +
    +    monkeypatch.setattr(main_mod.shutil, "which", which)
    +
    +    def fail_run(*_args, **_kwargs):
    +        raise AssertionError("bundled TUI path must not spawn any subprocess (no npm install/build, no git restore)")
    +
    +    monkeypatch.setattr(main_mod.subprocess, "run", fail_run)
    +
    +    # ui-tui/ deliberately does not exist under tmp_path, and there is no
    +    # .git either — this mirrors a pip/pipx install exactly.
    +    tui_dir = tmp_path / "ui-tui"
    +    assert not tui_dir.exists()
    +
    +    argv, cwd = main_mod._make_tui_argv(tui_dir, tui_dev=False)
    +
    +    assert argv == ["/usr/bin/node", "--expose-gc", str(bundled_entry)]
    +    assert cwd == bundled_entry.parent
    +
    +
    +def test_make_tui_argv_dev_mode_still_requires_workspace_even_with_bundle(
    +    tmp_path: Path, main_mod, monkeypatch, capsys
    +) -> None:
    +    """--dev never uses the prebuilt bundle (there's no source to hot-reload
    +    from a bundled entry.js), so it must still hit the workspace guard when
    +    ui-tui/ is missing — the bundled-first reordering must not weaken --dev.
    +    """
    +    monkeypatch.delenv("HERMES_TUI_DIR", raising=False)
    +    monkeypatch.setattr(main_mod, "_ensure_tui_node", lambda: None)
    +
    +    bundled_entry = tmp_path / "bundled" / "entry.js"
    +    bundled_entry.parent.mkdir(parents=True)
    +    bundled_entry.write_text("// bundled TUI")
    +    monkeypatch.setattr(main_mod, "_find_bundled_tui", lambda: bundled_entry)
    +
    +    def which(name: str) -> str | None:
    +        if name == "git":
    +            return "/usr/bin/git"
    +        raise AssertionError("node/npm lookup must not run when ui-tui is missing")
    +
    +    monkeypatch.setattr(main_mod.shutil, "which", which)
    +
    +    with pytest.raises(SystemExit) as exc:
    +        main_mod._make_tui_argv(tmp_path / "ui-tui", tui_dev=True)
    +
    +    assert exc.value.code == 1
    +    assert "TUI workspace is missing" in capsys.readouterr().err
    +
    +
     def test_make_tui_argv_exits_with_recovery_hint_when_workspace_unrecoverable(
         tmp_path: Path, main_mod, monkeypatch, capsys
     ) -> None:
    ```
- **#19525: fix(package): include TUI runtime assets in manifest**. open
  - maintainer direction: category `uncategorized`; implication `needs_llm`
  - files: `MANIFEST.in`, `tests/test_packaging_metadata.py`
- **#19995: fix(packaging): include TUI runtime assets**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `3215ef160938c71ff61bab279b30545c0cc14a14`, `b2bf658442f413a9a1d24b011589e5e38544947e`, `#19514`, `#19525`
- **#56672: fix(cli): try bundled TUI before requiring ui-tui workspace**. closed without merge
  - maintainer direction: category `superseded_by_pr`; implication `superseded`; refs `#67116`, `#56665`
- **#57047: fix(cli): skip TUI workspace check for managed installs (Homebrew/NixOS)**. closed without merge
  - maintainer direction: category `wontfix_bydesign`; implication `wontfix`; refs `#57031`
- **#57064: fix(tui): prefer bundled TUI on packaged installs; give install-method-specific recovery (#57031)**. closed without merge
  - maintainer direction: category `wontfix_bydesign`; implication `wontfix`; refs `#57031`
- **#57087: fix(tui): prefer bundled dist before workspace check**. closed without merge
  - maintainer direction: category `wontfix_bydesign`; implication `wontfix`; refs `#57031`
- **#57136: fix(cli): skip TUI workspace check when bundled TUI exists (#57031)**. closed without merge
  - maintainer direction: category `wontfix_bydesign`; implication `wontfix`; refs `#57031`

## Fix status

- Merged to main in PR #67116 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-07-18`.
- Subsystem: `dashboard`
