diff --git a/pkgbuilds/hermes-agent/.omarchy/package.json b/pkgbuilds/hermes-agent/.omarchy/package.json new file mode 100644 index 0000000..db153c3 --- /dev/null +++ b/pkgbuilds/hermes-agent/.omarchy/package.json @@ -0,0 +1,4 @@ +{ + "source": "local", + "release_ring": "fast" +} diff --git a/pkgbuilds/hermes-agent/PKGBUILD b/pkgbuilds/hermes-agent/PKGBUILD new file mode 100644 index 0000000..a71d38c --- /dev/null +++ b/pkgbuilds/hermes-agent/PKGBUILD @@ -0,0 +1,73 @@ +# Maintainer: David Heinemeier Hansson + +# Hermes pins every one of its ~120 dependencies with == and declares +# Requires-Python >=3.11,<3.14, so it can neither be built against Arch's +# Python nor share the python-* packages, and Arch's next Python bump would +# break any venv this package built. So the package ships a wrapper rather than +# the application: mise gives Hermes a private, supported environment on first +# run and keeps it current, the arrangement omarchy-mise-install already makes +# for the other coding agents. pkgver therefore tracks the wrapper, not Hermes. + +pkgname=hermes-agent +pkgver=1.0.0 +pkgrel=1 +pkgdesc='The self-improving AI agent that grows with you' +arch=('any') +url='https://github.com/NousResearch/hermes-agent' +license=('MIT') + +depends=( + 'hicolor-icon-theme' + 'mise' + 'uv' # mise's pipx backend refuses to run without uv or pipx + 'xdg-terminal-exec' +) + +optdepends=( + 'chromium: browser automation tools' + 'ffmpeg: text-to-speech voice messages' + 'git: version control integration' + 'nodejs: browser-use CLI and MCP servers' + 'ripgrep: faster file search' +) + +makedepends=('imagemagick') +options=('!debug') + +source=('hermes.sh' + 'hermes.desktop' + 'hermes.png') +sha256sums=('bed3664912e9e818c623fb77cc0111ec3a376da400bd329032a1949b9bd9991f' + 'fc738787ccf156aee9f701252a298d47bc6828ea53ea4b53d0e31d27d6209c7b' + 'd60d164e24fdcf6532133b8ea43c77a201e4b9e9dbc396187b58d51d8590ef52') + +build() { + # Upstream ships one 1024x1024 master. Menus and the dock ask for the small + # sizes, and letting them downscale a 1024px portrait themselves is what + # makes it a smudge at 48px. + local size + for size in 512 256 128 64 48; do + magick "$srcdir/hermes.png" -resize "${size}x${size}" "$srcdir/hermes-${size}.png" + done +} + +package() { + install -Dm755 "$srcdir/hermes.sh" "$pkgdir/usr/bin/hermes" + + # Hermes' other two entry points. The wrapper dispatches on the name it was + # invoked under, so these are symlinks rather than copies. + ln -s hermes "$pkgdir/usr/bin/hermes-agent" + ln -s hermes "$pkgdir/usr/bin/hermes-acp" + + install -Dm644 "$srcdir/hermes.desktop" \ + "$pkgdir/usr/share/applications/hermes.desktop" + + install -Dm644 "$srcdir/hermes.png" \ + "$pkgdir/usr/share/icons/hicolor/1024x1024/apps/hermes.png" + + local size + for size in 512 256 128 64 48; do + install -Dm644 "$srcdir/hermes-${size}.png" \ + "$pkgdir/usr/share/icons/hicolor/${size}x${size}/apps/hermes.png" + done +} diff --git a/pkgbuilds/hermes-agent/hermes.desktop b/pkgbuilds/hermes-agent/hermes.desktop new file mode 100644 index 0000000..2a4bdf2 --- /dev/null +++ b/pkgbuilds/hermes-agent/hermes.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=Hermes +GenericName=AI Agent +Comment=The self-improving AI agent that grows with you +Exec=xdg-terminal-exec --app-id=TUI.tile -e hermes +Icon=hermes +Terminal=false +Categories=Utility; +Keywords=ai;agent;assistant;hermes;nous; +StartupNotify=true diff --git a/pkgbuilds/hermes-agent/hermes.png b/pkgbuilds/hermes-agent/hermes.png new file mode 100644 index 0000000..539fdf9 Binary files /dev/null and b/pkgbuilds/hermes-agent/hermes.png differ diff --git a/pkgbuilds/hermes-agent/hermes.sh b/pkgbuilds/hermes-agent/hermes.sh new file mode 100755 index 0000000..601ddb1 --- /dev/null +++ b/pkgbuilds/hermes-agent/hermes.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Hermes is a Python application that pins every one of its dependencies +# exactly and declares Requires-Python >=3.11,<3.14, so it cannot be built +# against Arch's Python or share the python-* packages. mise builds it a +# private environment instead, on first run and on demand. +# +# The interpreter pin below is not belt-and-braces. Given no compatible +# interpreter to hand, uv builds the venv against the system Python in +# violation of Hermes' own bound, reports success, and leaves the failure to +# surface later inside a dependency. + +set -euo pipefail + +readonly tool='pipx:hermes-agent[extras=all]' +readonly python="${HERMES_PYTHON:-3.13}" + +export UV_PYTHON="$python" + +# `mise up` -- which omarchy update runs -- reinstalls without this wrapper's +# UV_PYTHON, so an upgrade can quietly move Hermes onto the system Python. +# Check the interpreter that is actually there, not merely that something is. +hermes_installed_on_pinned_python() { + local prefix + prefix=$(mise where "$tool" 2>/dev/null) || return 1 + [[ -d "$prefix/hermes-agent/lib/python$python" ]] +} + +if ! hermes_installed_on_pinned_python; then + echo "Installing Hermes on Python $python (this takes a minute)..." >&2 + + # Hermes ships several times a week, so mise's release cooldown would hold a + # new version back for days. Same call omarchy-mise-install makes. + MISE_MINIMUM_RELEASE_AGE=0 mise use -g --quiet --force "$tool" || exit 1 +fi + +# Installed as /usr/bin/hermes, with hermes-agent and hermes-acp symlinked to +# it, so the name we were invoked under picks the entry point. Anything else -- +# someone running this file straight out of a checkout -- means hermes. +command=$(basename "$0") +case "$command" in +hermes | hermes-agent | hermes-acp) ;; +*) command='hermes' ;; +esac + +exec mise x "$tool" -- "$command" "$@"