Conversation
… commit via fake git remote windows sibling of install-e2e-run.yml. no bubblewrap on windows, so the git proxying is git's own transport rewrite: an isolated GIT_CONFIG_GLOBAL with multi-valued url.<file://fake.git>.insteadOf for both hardcoded repo URLs, so the published Hermes-Setup.exe's install.ps1 clone, hermes update's fetch, and the desktop's ls-remote all land on a local bare repo whose main the driver controls - installer and updater run verbatim. one run: seed fake.git from the checkout, force fake main to the newest release tag, drive the real published bootstrap installer with AutoHotkey (GUI, no headless mode), promote fake main to HEAD, then apply the desktop app's builtin update route (scripts/desktop-update.ps1 -NoUi when the installed base ships it, staged hermes-setup.exe --update otherwise) and assert HEAD == target with a working hermes. TODO routes: bare hermes update, and re-running the bootstrap installer over the existing checkout.
… the checkout trip the driver's dirty-tree guard
…licking Install
AutoHotkey64 is a GUI-subsystem exe: spawned without -NoNewWindow it has
no console, FileAppend('*') throws '(6) The handle is invalid' on the first
Log call, and OnError's own Log rethrows inside the handler - the script
hangs with the error tooltip painted over the installer and Install is
never clicked (confirmed from the run 31443096241 screen recording; ahk.log
was never created because the stdout write preceded the file write).
Wrap the stdout append in try (the log file is the record) and spawn the
helper with -NoNewWindow so its live lines reach the job log.
…d installer Run 31445244722's recording shows the published Hermes-Setup.exe renders '[ INSTALL ]' as flat blue text on off-white - nothing like the solid-blue 'Install Hermes ->' reference from the dev-build era, so ImageSearch never matched. Replace the reference with a crop of the real button taken from that recording (tolerance *60 to absorb H.264 drift, click retried across animation frames), and drop launch-button.png entirely: completion now polls the installer's own bootstrap-complete marker (.hermes-bootstrap-complete, see paths.rs likely_bootstrap_marker), which cannot go stale with a UI restyle.
…attempt Run 31445907233's recording shows the runner session's maximized console covering the installer for the whole run: WinWait matches by title regardless of z-order, but ImageSearch reads screen pixels, so the Install button was never visible to it. WinActivate + WinMoveTop before every attempt; run 31443096241 already proved the same reference crop renders match-ably when the window is frontmost.
Run 31446292343 disproved the z-order theory: the recording shows the installer frontmost, red click-marker dots painting on it, and the button rendered - yet ImageSearch missed on all 5 attempts. The reference crop is the problem: it came from an H.264/yuv420p recording whose chroma subsampling smears glyph edges. Diffing the crop against run 5's OWN recording of the same screen gives max 8 shades/channel (matches easily), so the crop is video-faithful but not screen-faithful, and no tolerance fixes that reliably. Keep ImageSearch as the first try, but fall back to PixelSearch for the button text's saturated blue (~0x3B82F6, variation 90) in the window's lower half - the only blue there (the title sits in the upper third). Verify the click landed by the blue vanishing (the progress view replaces the button); retry up to 10 times.
…he button Run 31446691812: every attempt logged 'blue text at 220, 330' - exactly the 45%-height scan boundary, which lands inside the HERMES AGENT title (title bottom ~47% of window height; button ~62%, measured from the run 2/5 recordings). The click-landed check then correctly reported no advance, ten times. Raise the boundary to 55%, between the two.
…TALL_DIR on runners Run 31447045981: the click landed (manifest received, stages ran) but Stage-Uv failed with 'uv installed but not found at ...\bin\uv.exe'. GitHub windows runners ship uv preinstalled WITH an astral install receipt; astral's cargo-dist installer then updates the receipt's location in place and ignores UV_INSTALL_DIR, so Install-Uv's managed copy never appears. Seed HERMES_HOME\bin\uv.exe from the runner's uv before launching the installer - Install-Uv short-circuits on an existing managed uv, and 'user already has a managed uv' is a legitimate install state, not a bypass. Also abort the run the moment the tailed bootstrap log says 'bootstrap FAILED': the failure screen waits on a human Retry, and the AHK helper would otherwise idle out its whole 25-minute marker deadline (and its blue-text retry loop hammers the Retry button, re-running doomed installs - observed in run 7).
… heuristic Run 31447405319 is the big win and the bug in one log: uv seeding worked, the Install click LANDED, and 6 stages ran (clone off the fake remote via SSH rewrite, venv, all Python dependencies) - then the AHK loop, still hunting for 'the button', PixelSearch-matched the PROGRESS view's own blue stage text (left column, x~106-115), decided the UI 'did not advance' 10 times, threw, and the driver killed a healthy install mid-node-deps. Fixes, all sourced from that recording: narrow the scan band to the center third so the left-column stage text can never match; verify a click by the blue vanishing AT THE CLICK POINT (a 24px box) instead of anywhere in the band; and never throw from the click loop - the authoritative failure signal is the driver's 'bootstrap FAILED' log abort, and the marker deadline caps a wedged UI.
… helper runs The ImageSearch reference must be cropped from a lossless capture of the real screen: the ffmpeg recording is H.264/yuv420p and its chroma subsampling shifts glyph pixels enough that a video-sourced crop never matches live rendering. Taken before the helper starts so no tooltip or click marker contaminates it; lands in the log-dir artifact.
…Search removed install-button.png is now cut from run 31449192962's LOSSLESS welcome-screen.png (blue-text extents x465-558 y449-459 plus 3px margin, verified complete '[ INSTALL ]' with no foreign pixels) instead of the H.264 recording whose chroma subsampling made every video-sourced crop miss the live screen. Tolerance drops from *60 to *20 accordingly. PixelSearch is deleted outright: color-hunting matched the blue title (run 31446691812) and the progress view's stage text (run 31447405319) before it ever matched the button. Click-landed detection reuses the same ImageSearch (button visible = not clicked). The TEMP stop-after-screenshot exit is removed - the AHK path is live again.
…e the silent dep-install hang The first full AHK run (31449642122) got all the way through install, verify, and the desktop hand-off's git leg (fetch from the fake remote, reset to target - the proxying works), then sat 65 minutes inside 'Updating Python dependencies' with zero uv output until the job timeout cancelled it. Cancellation kills any chance of a post-mortem: no process table, no partial log. Run the hand-off through Start-Process with a driver-owned 45-minute deadline (the same budget the staged-exe branch already gets), poll-tail its log into the console, and on deadline dump the live uv/python/git process table plus stderr tail before killing the tree - so a hang diagnoses itself instead of burning another silent 75 minutes. RUST_LOG=uv=debug is scoped to the update leg so uv says what it is doing (or waiting on: cache lock, network, resolution).
…desktop updates Two consecutive Windows E2E runs hung inside dependency install until the job timeout: 31449642122 65 minutes in uv pip install .[all], 31453853006 43 minutes in the SQLite-repair uv sync (RUST_LOG=uv=debug made THAT run hang earlier and with more stderr - the tell). Root cause: scripts/desktop-update.ps1 redirects both child pipes but only pumps stdout while the child runs; stderr is ReadToEnd()'d after exit. uv and pip write progress to stderr. Once that pipe hits the ~64KB buffer, uv blocks on write, hermes update blocks on uv, the hand-off blocks on hermes update: deadlock. Slower stderr producers survive by finishing before the buffer fills, which is why the linux sandbox never sees this. Fix both sides of the class: - managed_uv.py candidate sync + main.py _run_install_with_heartbeat: merge stderr into stdout (the pipe that IS drained). This arm heals EXISTING installs, whose old hand-off script drives the NEW python after the git reset. - desktop-update.ps1: drain stderr concurrently via ReadToEndAsync so future bases never block regardless of what a child writes there. _run_logged_subprocess and _run_npm_install_deterministic already merge or capture both pipes; the two fixed sites were the only update- path spawns that redirect stderr without draining it live.
…the deadlock it was diagnosing Run 31457301901 proved both halves of the stderr fix and then hung anyway, in uv pip install -e .[all] (process table caught it live): - The SQLite-repair uv sync that deadlocked run 2 now streams its whole package list and completes in ~80s WITH debug tracing on - managed_uv.py is imported lazily after the git reset, so even this old base ran the fixed copy. - The .[all] install runs _run_install_with_heartbeat from main.py, which was imported when hermes update STARTED - the v0.20.1 copy, which pipes uv's stderr undrained. RUST_LOG=uv=debug guaranteed >64KB of stderr, so the driver's own diagnostic manufactured the deadlock. Comments in both fixed call sites now state the real import-time reach of each arm. This also explains run 1 failing WITHOUT tracing: the pipe budget is cumulative across every child of the update sharing it. The old-code sync burned ~30KB of it on the package list; the .[all] leg finished the job. With the sync leg now on stdout, the old .[all] leg's natural output should fit - which is the real-world story too: old bases hang or survive on stderr luck, new bases are safe by construction.
Every commit on main now proves, on a real Windows machine, that:
1. the PRIOR commit (HEAD~1) installs from scratch through its own
scripts/install.ps1 (-IncludeDesktop: uv, managed Python, Node,
venv, packaged Electron Hermes.exe),
2. that install updates TO this commit through the real Desktop GUI
update path (scripts/desktop-update.ps1, the exact hand-off the
Update button spawns -- fail-closed gates, marker lifecycle,
hermes update, result JSON), and
3. this commit updates FORWARD to a synthetic next commit, proving
the updater code shipping in this commit is not the one that
strands users when the next commit lands.
Staging: the driver bare-clones the checkout into serve.git and
redirects the canonical GitHub URLs at it with git insteadOf env
config, then advances the served main ref BASE -> CURRENT -> NEXT
between legs. Installer and updater run byte-for-byte unmodified.
Supersedes the AutoHotkey pixel-driving approach (NousResearch#68183): the GUI
Update button's entire effect is spawning desktop-update.ps1 with
documented flags, so driving that contract directly tests the same
production code deterministically.
The push-triggered validation run failed with zero jobs ('workflow file
issue'): job-level env only allows github/inputs/matrix/needs/secrets/
strategy/vars. Use a sibling of github.workspace for the E2E workroot
instead. actionlint now passes clean.
…tion Will be reverted before merge; workflow_dispatch only becomes available once the workflow file exists on the default branch.
…nfig First CI run's install leg cloned real GitHub main instead of the staged BASE (caught by the HEAD-at-BASE assert): install.ps1 sets GIT_CONFIG_COUNT=1 / windows.appendAtomically itself, silently clobbering the driver's env-config insteadOf rewrites. A driver-owned gitconfig file selected via GIT_CONFIG_GLOBAL survives that (and install.ps1's own --global writes land harmlessly in the same file). Verified locally by cloning with the clobber vars set: clone lands on staged BASE.
The Windows E2E ran end-to-end green on this branch (run 31462244593): install at BASE, update BASE->CURRENT, update CURRENT->NEXT, all asserts passing. Back to main/nightly/tags/dispatch triggers only.
…I updater Second job on the Windows E2E workflow covering the surfaces a user actually touches, per Teknium's requirement: * INSTALL: downloads the production Hermes-Setup.exe from hermes-assets.nousresearch.com, launches it HEADED, and AutoHotkey clicks Install -> waits -> clicks Launch (button templates + ImageSearch approach from @ethernet8023's NousResearch#68183, retargeted by process name and extended to exercise the Launch hand-off). The real Electron Hermes.exe window must appear. * UPDATE x2: the installed Hermes.exe is launched under Playwright's Electron driver and the test CLICKS Settings -> About -> Update now. The production hand-off chain runs untouched: app quits, detached updater (repo script or staged binary) runs hermes update, rebuilds the desktop, relaunches Hermes.exe. Asserts: target sha, marker cleanup, result JSON when the script path wrote one, working hermes, and the RELAUNCHED app window. Leg 1 -> CURRENT, leg 2 -> synthetic NEXT. Proof artifacts: per-step renderer screenshots (booted app, settings, About panel, update-available, updating overlay), full-desktop frames every 3s across the whole run, ahk.log, bootstrap-installer.log, desktop-update-handoff.log — uploaded on success AND failure. The website exe runs exactly as shipped (its own pinned install.ps1, its baked release-pin commit); the only environmental deltas are the serve.git URL redirect, uploadpack.allowAnySHA1InWant for the commit pin fetch, and a placeholder provider key so the update legs meet the app shell instead of onboarding. The contract job from the previous commits is unchanged and independent — it remains the rollback position if the GUI job proves flaky.
…rows Frame-0005 of the proof capture showed the exact failure: 'Unhandled error: (6) The handle is invalid' rendered over the installer within seconds of launch. AutoHotkey started via Start-Process has no console, so FileAppend to '*' (stdout) throws — and the throw fired inside Log(), killing the script before it clicked anything. The installer then sat untouched at the INSTALL screen for 50 minutes. * Log() now try-wraps the stdout write (file log is the real record) * Install/Launch clicks fall back to the button's relative window position when the NousResearch#68183-era PNG templates don't match the restyled UI ('[ INSTALL ]' bracket style visible in the same frame) * install-finished has a second signal: 'bootstrap complete' in bootstrap-installer.log (read with write-sharing), so a template miss can't strand the wait * driver passes the bootstrap log path as arg 3
…metry Attempt 2's proof frames showed two bugs, both now fixed from the live evidence: 1. The NousResearch#68183 install-button.png predated the installer UI restyle to the '[ INSTALL ]' bracket look, so the template never matched and we fell through to the position fallback. Re-captured install-button.png from a real CI desktop frame (the actual rendered button). 2. The fallback then clicked the WRONG spot: ahk_exe's first WinGetPos matched a hidden 16x16 helper window ('Window found at w=16 h=16' in ahk.log), and BTN_FY=0.87 aimed below the real button anyway. The button center measured at ~(0.50, 0.59) of the ~full-screen window. Rewrite: * WaitForRealWindow() skips phantom/hidden matches (requires w>400,h>300) and returns the true rect; the installer window is then activated before any click. * Install-finished is now driven primarily by the authoritative 'bootstrap complete' line in bootstrap-installer.log (matches BootstrapEvent::Complete), with the Launch template as a secondary signal and a window-relative fallback click. * Fallback clicks use the corrected (0.50, 0.59) window fraction.
Attempt 3's proof frames showed the install SUCCEEDED end-to-end (bootstrap complete, installer self-copied to HERMES_HOME) and the window advanced to 'HERMES IS READY' with a [ LAUNCH ] button at the same centered CTA spot the [ INSTALL ] button occupied — screen (511,454) inside window x=64 y=34 w=896 h=659. Two Launch-step bugs, both fixed from that evidence: * launch-button.png was the stale NousResearch#68183 template and never matched the restyled '[ LAUNCH ]' button. Re-captured from the live frame. * the window-relative fallback used fy=0.59, clicking y=422 — above the real button. Correct fraction is (454-34)/659 = 0.637. With the template now matching, the fallback is belt-and-braces anyway. Install click, completion detection, and the app-window wait were all already correct in attempt 3; only the Launch click missed.
The full GUI install flow now works end-to-end (attempt 4 proof: Install clicked, bootstrap complete, Launch clicked, real Hermes.exe window appeared 1024x720, installer exited, 5 Hermes processes running). The only failure was an over-strict staging assertion. The website Hermes-Setup.exe pins a main release commit. On a real push-to-main run CURRENT is main's tip, so that pin is its ancestor and the check holds. On a diverged feature branch CURRENT is a branch commit the release pin is not an ancestor of — a legitimate topology, not a bug. The update leg resets the checkout to serve.git's main ref (= CURRENT) regardless of ancestry and asserts it lands there, which is the actual forward-update proof. Downgrade the ancestor check to an informational note so branch validation can exercise the update legs.
Windows PowerShell 5.1 reads .ps1 without a BOM under the legacy OEM
codepage, mis-decoding UTF-8 bytes. Em-dashes/box-drawing survived in
comments through attempts 2-4, but the previous commit added an em-dash
INSIDE a double-quoted Write-Host string — the misdecode there ate the
quote boundary and cascaded into a whole-file parse failure at the Stage
step ('Unexpected token', 'string is missing the terminator').
scripts/install.ps1 documents this exact constraint ('pure ASCII for PS
5.1 parser compatibility'). Strip all non-ASCII from the .ps1 and .ahk
files (em-dash->--, arrows->->, box-drawing->-). drive-update.cjs keeps
UTF-8 (Node decodes it natively). Both PowerShell files parse clean.
…heck Install + GUI update leg now reached (attempt 6): full install passes, first update leg begins. It tripped a preflight assert checking apps/desktop/node_modules/@playwright/test — but the root npm ci HOISTS workspace devDependencies to the REPO-ROOT node_modules, so that path is empty by design. Node's own resolution walks up from apps/desktop and finds it (which is exactly how the copied-in drive-update.cjs will load it), so assert via 'node -e require.resolve(...)' from apps/desktop instead of a hardcoded nested path.
…iver
Attempt 7 got the whole way into the GUI update leg: the installed
Electron app launched under Playwright, booted, composer attached, first
screenshot captured. It then couldn't find the settings gear -- the
ERROR screenshot showed why: a fresh install with no CONFIGURED provider
(the seeded .env key isn't read as model.provider) shows the onboarding
card ('Let''s get you setup with Hermes Agent'), which covers the shell
and its settings gear.
The update path needs no provider, so the driver now clicks 'I'll choose
a provider later' (with skip fallbacks) to dismiss onboarding and reach
the shell before looking for the gear. Harmless no-op when onboarding
isn't shown. Gear (aria-label 'Open settings') and About nav ('About')
selectors already match the real components.
…e event Attempt 8 drove the ENTIRE GUI update click-path successfully: onboarding dismissed, Settings opened, About opened, Update now clicked, updating overlay shown. The hand-off log proves the real update then ran: desktop (pid 8880) exited, venv unlocked, 'hermes update --yes --gateway --force --branch main' fetched from serve.git, found 1 new commit, pulled, and restored. Everything worked. The only failure was the driver waiting on Playwright's app 'close' event, which doesn't fire reliably when the Electron app self-quits for the hand-off. Switch to the authoritative signal: poll for the HERMES_HOME/.hermes-update-in-progress marker (or the result JSON, or a genuine window-gone), which the hand-off writes ~4s after the click. The PowerShell driver still owns asserting the OUTCOME (target sha, marker cleanup, working hermes, relaunched app) after the driver returns.
hideOnly chrome pinned the Sessions/Bots strip on at any tab count, so never was a silent no-op. The panes stay; ⌘⌥T brings the strip back. Co-authored-by: Cursor <cursoragent@cursor.com>
The importer stays in the command palette. The labeled nav row was clutter next to New session / Capabilities / Messaging. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Lowering the session trigger must not replace the window-relative lean selection budget with threshold times target_ratio. Invalidate the lean cache through the existing property while preserving explicit legacy and external-engine fallback behavior. Narrow adaptation of the aux-sync diagnosis and invariants in NousResearch#93576, without adding a required recalibration method to context engines. Related: NousResearch#95681, NousResearch#93576 Co-authored-by: Turgut Kural <58116817+TurgutKural@users.noreply.github.com>
Add Move up/down controls for actual rooms without changing bot or folder ordering. Preserve default pin/activity ordering until an explicit move, retain hidden room slots, and persist Desktop-local order through room updates, mirror merges, and hydration. No membership or routing writes. Adapted narrowly from the group ordering idea in archived NousResearch/Hermes-Bot-Mode#105 by @onuraycicek; rename already exists. Co-authored-by: Onur Aycicek <onur.m.aycicek@gmail.com>
Port Adolanium's focused-turn pose from Hermes-Bot-Mode#101 and hermes-agent#88134 to the current typed Bot Mode implementation. Match the busy signal's connection-qualified focused owner rather than the gateway socket, retain worker activity, and ease transitions in elapsed time on the existing shared face clock. Includes owner-isolation and animated-pose invariants, both proven red on origin/main, and native Electron before/after verification against a real temporary Hermes backend with held loopback inference. Co-authored-by: Teknium <127238744+teknium1@users.noreply.github.com>
…tention-salvage fix(bot-mode): clear resolved Group Chat attention and bind prompts across rename
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolve the conflict blocking NousResearch#18188 by merging upstream
mainatfacb9eb4f17735a7d70f28cb6a26d95ffdc4c105into the existingfeat/runtime-footer-quotahead3e5500a5694e7b2b0c02b667594dca81fda8437d.There was one content conflict, in
gateway/run_turn_runner.py: both branches added independent declarations after the module logger. This merge preserves both:_resolve_runtime_footer_metadata, including profile-scoped, runtime-credential-aware account/quota lookup and the no-raw-key result contract;_ExecApprovalDeclinedand all egress-decline handling, so a refused approval destination does not receive a plain-text fallback or leave approval work pending.No footer capability or upstream authorization behavior was removed. The quota feature remains opt-in; default footer fields and stale-while-revalidate behavior are unchanged. The diff against upstream
mainremains the existing 11-file footer feature, not a new implementation.Integration
This is a merge-based refresh rather than a rebase because the contributor cannot push directly to the author's branch. Original commits and authorship are preserved. Please merge normally (not squash), or fast-forward
feat/runtime-footer-quotato this branch, to preserve the upstream-main ancestry and clear the conflict in NousResearch#18188.Published head:
cb38c7662289e5f07e9f0706c20ce82dc23f8d3d.Verification
Canonical per-file test runner, 8 focused files: 143 passed, 0 failed:
tests/gateway/test_runtime_footer.pytests/gateway/test_runtime_footer_usage_cache.pytests/gateway/test_runtime_footer_runner_wiring.pytests/test_account_usage.pytests/agent/test_account_usage.pytests/gateway/test_prompt_decline_no_fallback.pytests/gateway/test_decline_fallback_suppression.pytests/gateway/relay/test_relay_egress_declines.pyAdditional checks:
git diff --check origin/main...HEADpassed.An unrelated existing trailing-space line in upstream
tests/install/windows-e2e.ps1was left unchanged; the footer diff relative to main is whitespace-clean. The full repository suite was not run; these are local results, not GitHub-hosted CI.