Skip to content

feat: add release update channel - #24938

Open
Sunwo0u wants to merge 1 commit into
NousResearch:mainfrom
Sunwo0u:feat/release-update-channel
Open

feat: add release update channel#24938
Sunwo0u wants to merge 1 commit into
NousResearch:mainfrom
Sunwo0u:feat/release-update-channel

Conversation

@Sunwo0u

@Sunwo0u Sunwo0u commented May 13, 2026

Copy link
Copy Markdown

Summary

  • add updates.channel with main and release modes for Hermes updates
  • add hermes update --channel {main,release} and apply the same override to --check
  • implement release-channel checks/updates using canonical release tags instead of commit drift
  • make startup banner update checks respect the configured update channel

Safety notes

  • upstream-compatible default remains main
  • EvAH can opt into release via profile config without changing global behavior
  • release tag selection prefers the successfully fetched remote via ls-remote --tags --refs, avoiding stale/local-only tags when possible
  • release update path keeps existing dependency reinstall, skill sync, config migration, and gateway cleanup flow
  • --channel main remains available for emergency hotfixes between releases

Test Plan

  • python -m py_compile hermes_cli/main.py hermes_cli/banner.py hermes_cli/config.py
  • python -m pytest tests/hermes_cli/test_update_check.py tests/hermes_cli/test_cmd_update.py -q -o 'addopts='
  • git diff --check
  • static secret/danger pattern scan returned {}
  • smoke: python -m hermes_cli.main --profile evah update --check
  • smoke: python -m hermes_cli.main --profile evah update --check --channel main
  • independent pre-commit review: no blockers

@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles P3 Low — cosmetic, nice to have labels May 13, 2026
@hustshawn

Copy link
Copy Markdown

Thanks for picking this up @Sunwo0u — this is a solid first step toward #34514, and the --channel {main,release} plumbing + banner/--check integration look good. I'm the author of #34514; sharing some feedback from the original report's perspective, plus a few correctness concerns. None of this is blocking the concept, but a couple of items affect whether release-tracking users actually get what the issue asked for.

1. Default channel — worth aligning on scope

#34514 talks about release-tracking being the default, but on reflection I don't think a hard default-flip is a must — keeping "channel": "main" as the default is a defensible, lower-risk choice, and opt-in covers the people who actually want release-tracking today. The one thing I'd ask: if this lands as opt-in, let's make sure the issue isn't auto-closed as "fully resolved," since "fresh installs ride main by default" is the part that stays open. Either a note here that the default-flip is intentionally deferred, or leaving #34514 open with a partially-addressed framing, would keep that clear. No objection to the opt-in-first approach at all.

2. Release path clobbers tag pins instead of respecting them

The issue specifically calls out that a tag-pinned (detached-HEAD) install gets forced back onto main. This PR doesn't fix that and arguably makes the pin story messier:

  • The "Currently on {detached HEAD} — switching to {main}" block isn't channel-gated, so a release-channel update on a pinned checkout still runs git checkout main first.
  • The release path then does git reset --hard <tag> on the main branch, which moves the local main ref onto the tag commit, diverging it from origin/main. A subsequent --channel main update then has to reset --hard origin/main to recover. Checking out the tag as a detached HEAD (a real pin) would be cleaner and matches the issue's "respect the pin" request.

3. Release path skips the post-pull syntax guard + rollback

Current main wraps the pull in _validate_critical_files_syntax(...) and auto-rolls-back to the pre-pull SHA on failure (the PR #28452 incident guard). The new release branch resets to the tag and falls straight through to dependency reinstall with no syntax validation and no rollback SHA captured. Since the whole motivation in #34514 is "don't break on bad code between tags," the release path is exactly where that guard matters most — please route it through the same validate-or-rollback logic. (Note: this PR is based on an older main that predates that guard, so a rebase will surface the conflict regardless.)

4. Pinning a specific release (nice-to-have, follow-up is fine)

The issue floated hermes update --release <tag> / --release latest for holding on a known-good version. This PR offers --channel release (always latest tag), which is the more important half. Specific-tag pinning is a natural companion to the detached-HEAD handling in #2 but is clearly follow-up material — just noting it so it isn't lost.

Minor

  • merge-base --is-ancestor <tag> HEAD treats "HEAD is ahead of the latest tag" (e.g. sitting on main past the last release) as "already up to date." That's defensible, but the message "Already up to date with latest release" is slightly misleading for someone actually on a newer untagged commit.
  • This PR is based on a fairly old main; a rebase before merge will be needed and will likely conflict around the syntax-guard block.

Happy to help with any of the above (default flip, tag-pin/detached-HEAD handling, or wiring the syntax guard into the release path) if it's useful. Thanks again for moving this forward.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for implementing an opt-in release channel; current main still defaults updates to main (hermes_cli/main.py:8386-8394), so the capability is useful. The branch needs substantive updater-path integration before it is safe to salvage.

Problems

  • PR hermes_cli/main.py:7602 treats a tag ancestor of HEAD as release-current. A checkout on main after the latest tag therefore remains on unreleased code when release mode is selected.
  • PR hermes_cli/main.py:7566-7585,7627 checks out main and resets it to the tag. That both discards detached tag-pin state and makes local main diverge from origin/main.
  • The release reset path bypasses current main's syntax validation and rollback (hermes_cli/main.py:9767-9841; introduced by aedb8ac83b8c6ecb89b9d370909fa46ff4733da2).

Suggested changes

  • Make release mode compare against and land on the exact tag commit; add a test for HEAD ahead of the latest tag.
  • Preserve tag state without moving main, and route the release path through the current validation/rollback guarantees.
  • Document updates.channel in the update and configuration guides.

Automated hermes-sweeper review.

Comment thread hermes_cli/main.py
if not latest_tag:
print("✗ No release tags found.")
sys.exit(1)
if _head_contains_ref(git_cmd, PROJECT_ROOT, latest_tag):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge-base --is-ancestor also succeeds when HEAD is on main after this tag. In that common opt-in transition, this reports release-current and leaves untagged main code installed; compare HEAD to the resolved tag commit (and add that regression case) instead.

Comment thread hermes_cli/main.py
_create_pre_update_snapshot()
print("→ Moving main to latest release tag...")
reset_result = subprocess.run(
git_cmd + ["reset", "--hard", latest_tag],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This runs after the unconditional checkout of main, so it moves local main to the tag rather than preserving a release/tag pin. That leaves main diverged from origin/main; use a release-specific detached/ref strategy and retain the current update rollback guard around the transition.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform area/install-update Installer, updater, packaging, wheels, doctor labels Jul 13, 2026
@kmukul123

Copy link
Copy Markdown

can we please prioritize this. thanks

@GottZ GottZ left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during triage.

Summary

Two PRs address release-based update channels. #11450 adds an edge/stable selector around the update command, while #24938 extends the same core capability to update checks and the startup banner but does not yet safely enforce exact release-tag state.

Related pull requests

  • #11450 [closed] duplicate — (+886/-137) — superseded reference: Adds update.channel with edge/stable CLI and config selection plus release-tag checkout tests, but its updater extraction predates later cmd_update safety refactors. Although closed, it remains relevant as the earlier implementation and its author explicitly offered commit bcb358a1 for selective reuse.
  • #24938 related — (+530/-104) — keep open with a salvage path: Adds updates.channel with main/release modes across hermes update, --check, banner checks, remote tag discovery, and tests. The contributor keep_open review on #24938 correctly identifies blocking updater-path defects in the diff: ancestor testing treats HEAD ahead of the latest tag as current, reset --hard <tag> moves local main instead of preserving an exact tag checkout, and the release path bypasses current syntax-validation and rollback guarantees.

Duplicates

#11450 and #24938 substantially duplicate the opt-in release-channel mechanism; #24938 is the broader successor because it also integrates release tracking into --check and banner update checks.

Suggested consolidation

Keep open with a salvage path for #24938: retain its channel configuration, CLI override, remote release-tag discovery, banner/--check integration, and associated tests, but rework updates to compare HEAD with the exact tag commit, land on that tag without moving local main, and pass through the existing syntax-validation and rollback path; add coverage for HEAD being ahead of the latest tag. Keep #11450 closed as a duplicate superseded by #24938, using bcb358a1 only for any still-useful isolated pieces.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    subgraph Dup11450 ["PRs duplicating each other"]
        P11450["PR #11450 (closed)"]
        P24938["PR #24938 (open)"]
    end
    class P11450 closed
    class P24938 open
    class P24938 target
    click P11450 "https://github.com/NousResearch/hermes-agent/pull/11450"
    click P24938 "https://github.com/NousResearch/hermes-agent/pull/24938"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 93 kB of PR diffs, 5 kB of issue/PR text, 6 kB of discussion (4 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles area/install-update Installer, updater, packaging, wheels, doctor comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants