Skip to content

perf(termux): fast-path cli version + defer bare-prompt agent startup#30609

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-5b3daa3d
May 22, 2026
Merged

perf(termux): fast-path cli version + defer bare-prompt agent startup#30609
teknium1 merged 2 commits into
mainfrom
hermes/hermes-5b3daa3d

Conversation

@teknium1

@teknium1 teknium1 commented May 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Termux non-TUI bare hermes reaches the prompt in ~0.8s instead of ~2.9s, and hermes --version is fully pre-import on Termux. Plugin/MCP/shell-hook discovery, tool callbacks, the tirith check, and the tool registry build now defer to the first agent turn on bare interactive startup. Cherry-picks PR #30521 by @adybag14-cyber unchanged.

Infographic

PR #30609 — Termux cold-start salvage

Changes

  • hermes_cli/main.py: ultrafast --version path before config/logging/argparse imports; bare Termux hermes sets HERMES_DEFER_AGENT_STARTUP=1/HERMES_FAST_STARTUP_BANNER=1/compact=True and skips _prepare_agent_startup so the prompt comes up first.
  • cli.py:
    • Lazy-imports AIAgent, get_tool_definitions, get_toolset_for_tool, toolsets helpers, cron, terminal/browser cleanup, sudo/approval/secret callbacks, skill_commands/skill_bundles scan.
    • Defers _install_tool_callbacks() and _ensure_tirith_security() to first _init_agent() when the env var is set.
    • _show_status() reports "tools deferred" on the bare prompt path instead of pulling the full registry.
  • tests/hermes_cli/test_tui_resume_flow.py: 2 new tests covering the ultrafast version path and bare-prompt deferral.

Validation

Before After
import cli (Linux x86_64, warm) ~1.36s ~0.70s
Termux bare prompt (reporter, RedMagic 10 Pro) ~2.9s ~0.81s avg
Termux --version worst-core ~0.04s
Targeted tests (tui_resume_flow, startup_plugin_gating) 78/78 pass

Original PR: #30521 — closed with credit on merge. Original Discord issue: filed by @likiuslnik.

@github-actions

github-actions Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-5b3daa3d vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 8991 on HEAD, 9067 on base (✅ -76)

🆕 New issues (10):

Rule Count
unresolved-attribute 5
invalid-assignment 4
invalid-argument-type 1
First entries
cli.py:14711: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `suppress_status_output` on type `Any | None`
cli.py:14717: [unresolved-attribute] unresolved-attribute: Attribute `run_conversation` is not defined on `None` in union `Any | None`
cli.py:14729: [unresolved-attribute] unresolved-attribute: Attribute `session_id` is not defined on `None` in union `Any | None`
cli.py:14710: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `quiet_mode` on type `Any | None`
cli.py:14175: [unresolved-attribute] unresolved-attribute: Attribute `interrupt` is not defined on `None` in union `Any | None`
cli.py:11539: [unresolved-attribute] unresolved-attribute: Attribute `_interrupt_requested` is not defined on `None` in union `Any | None`
cli.py:14715: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `stream_delta_callback` on type `Any | None`
cli.py:14716: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `tool_gen_callback` on type `Any | None`
cli.py:8142: [invalid-argument-type] invalid-argument-type: Argument to function `build_welcome_banner` is incorrect: Expected `int`, found `None | Any`
cli.py:11540: [unresolved-attribute] unresolved-attribute: Attribute `_active_children` is not defined on `None` in union `Any | None`

✅ Fixed issues (48):

Rule Count
invalid-argument-type 20
unresolved-attribute 17
invalid-assignment 11
First entries
cli.py:4585: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `Unknown | None | str | list[str | Unknown]`
cli.py:8360: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `dict[str, Any]`, found `Any | list[Unknown] | list[Any & Top[dict[Unknown, Unknown]]]`
cli.py:6503: [invalid-assignment] invalid-assignment: Object of type `datetime` is not assignable to attribute `session_start` on type `AIAgent & ~AlwaysFalsy`
cli.py:14497: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent.run_conversation` is incorrect: Expected `str`, found `Any | list[dict[str, Any]] | str`
cli.py:9836: [unresolved-attribute] unresolved-attribute: Unresolved attribute `tools` on type `AIAgent`
cli.py:8358: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `Any | None`
cli.py:9306: [unresolved-attribute] unresolved-attribute: Object of type `AIAgent & ~AlwaysFalsy` has no attribute `compression_enabled`
cli.py:14496: [unresolved-attribute] unresolved-attribute: Attribute `run_conversation` is not defined on `None` in union `AIAgent | None`
cli.py:8363: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_print_fn` on type `AIAgent`
cli.py:6502: [invalid-assignment] invalid-assignment: Object of type `str` is not assignable to attribute `session_id` on type `AIAgent & ~AlwaysFalsy`
cli.py:9837: [invalid-argument-type] invalid-argument-type: Argument to function `get_tool_definitions` is incorrect: Expected `list[str]`, found `object`
cli.py:14508: [unresolved-attribute] unresolved-attribute: Object of type `AIAgent | None` has no attribute `session_id`
cli.py:8351: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `str | None`
cli.py:11231: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent.run_conversation` is incorrect: Expected `str | None`, found `(Unknown & ~str) | list[dict[str, Any]] | str | None`
cli.py:14489: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `quiet_mode` on type `AIAgent | None`
cli.py:8352: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `dict[str, Any]`, found `Unknown | None`
cli.py:14490: [invalid-assignment] invalid-assignment: Object of type `Literal[True]` is not assignable to attribute `suppress_status_output` on type `AIAgent | None`
cli.py:4593: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `str`, found `(str & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | None`
cli.py:14178: [unresolved-attribute] unresolved-attribute: Object of type `AIAgent & ~AlwaysFalsy` has no attribute `session_id`
cli.py:9348: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent._compress_context` is incorrect: Expected `str`, found `None`
cli.py:9841: [unresolved-attribute] unresolved-attribute: Unresolved attribute `valid_tool_names` on type `AIAgent`
cli.py:11227: [invalid-argument-type] invalid-argument-type: Argument to bound method `AIAgent.run_conversation` is incorrect: Expected `str`, found `Unknown | list[dict[str, Any]] | str`
cli.py:14494: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `stream_delta_callback` on type `AIAgent | None`
cli.py:4594: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `list[dict[str, Any]]`, found `(list[dict[str, Any]] & ~AlwaysFalsy) | None`
cli.py:8355: [invalid-argument-type] invalid-argument-type: Argument to `AIAgent.__init__` is incorrect: Expected `list[str]`, found `Any | None`
... and 23 more

Unchanged: 4760 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@teknium1 teknium1 force-pushed the hermes/hermes-5b3daa3d branch from 8b74ec6 to 13e5f4f Compare May 22, 2026 21:24
@github-actions

Copy link
Copy Markdown
Contributor

🚨 CRITICAL Supply Chain Risk Detected

This PR contains a pattern that has been used in real supply chain attacks. A maintainer must review the flagged code carefully before merging.

🚨 CRITICAL: Install-hook file added or modified

These files can execute code during package installation or interpreter startup.

Files:

hermes_cli/setup.py

Scanner only fires on high-signal indicators: .pth files, base64+exec/eval combos, subprocess with encoded commands, or install-hook files. Low-signal warnings were removed intentionally — if you're seeing this comment, the finding is worth inspecting.

@teknium1 teknium1 merged commit a3beee4 into main May 22, 2026
16 of 18 checks passed
@teknium1 teknium1 deleted the hermes/hermes-5b3daa3d branch May 22, 2026 21:27
@teknium1

Copy link
Copy Markdown
Contributor Author

infographic upload (image only — will be moved into PR body)

@alt-glitch alt-glitch added type/perf Performance improvement or optimization P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard labels May 22, 2026
teknium1 pushed a commit that referenced this pull request May 22, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR #30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).
Gpapas pushed a commit to Gpapas/hermes-agent that referenced this pull request May 23, 2026
Gpapas pushed a commit to Gpapas/hermes-agent that referenced this pull request May 23, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).
Mucky010 pushed a commit to Mucky010/hermes-agent that referenced this pull request May 24, 2026
Mucky010 pushed a commit to Mucky010/hermes-agent that referenced this pull request May 24, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).
exosyphon pushed a commit to exosyphon/hermes-agent that referenced this pull request May 24, 2026
exosyphon pushed a commit to exosyphon/hermes-agent that referenced this pull request May 24, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).
mathias3 pushed a commit to mathias3/hermes-agent that referenced this pull request May 28, 2026
mathias3 pushed a commit to mathias3/hermes-agent that referenced this pull request May 28, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).
Bryce-huang pushed a commit to wbkunlun/hermes-agent that referenced this pull request May 29, 2026
Bryce-huang pushed a commit to wbkunlun/hermes-agent that referenced this pull request May 29, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).

#AI commit#
mosaiq-systems pushed a commit to mosaiq-systems/hermes-agent that referenced this pull request May 29, 2026
mosaiq-systems pushed a commit to mosaiq-systems/hermes-agent that referenced this pull request May 29, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
…s on stale-branch PRs

The workflow diffs base.sha..head.sha (two-dot), which compares the
tip-of-main tree directly against the PR tip. When files land on main
after a PR branched off, they appear in the diff even though the PR
never touched them — triggering false-positive findings.

Example: PR NousResearch#30609 was flagged for hermes_cli/setup.py, a file added
to main by an unrelated commit after the PR branched.

Switch to three-dot diff (base.sha...head.sha), which diffs from the
merge base to the PR tip — only changes introduced by this PR are
included. Applied to all four diff commands in both jobs (scan and
dep-bounds).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have type/perf Performance improvement or optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants