Use Hermes native prompted sessions

Hermes now keeps chat queries interactive and literal to TUI control syntax, so launch it directly and let its own session flow replace the local one-shot, usage-file, and resume bridge.

Gate installation on the capability added with native interactive queries, preserve unowned mise environments, and keep the unprompted launch path unchanged.

Co-Authored-By: Codex XHigh <noreply@openai.com>
This commit is contained in:
Spencer BullandCodex XHigh committed 2026-08-28 16:32:19 -05:00
1 parent 64203cc208
commit 5284be6582
6 files changed
+47 -183

No files matched your search

+1 -1
View File
@@ -88,7 +88,7 @@ codex)
;;
hermes)
if [[ -n ${prompt:-} ]]; then
command=(omarchy-agent-hermes "$prompt")
command=(env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=$prompt")
else
command=(hermes --yolo)
fi
-34
View File
@@ -1,34 +0,0 @@
#!/bin/bash
# omarchy:summary=Seed Hermes literally and resume the resulting interactive session
# omarchy:args=<prompt>
# omarchy:hidden=true
set -euo pipefail
prompt=${1:?usage: omarchy-agent-hermes <prompt>}
unset HERMES_SESSION_SOURCE
usage=$(mktemp)
trap 'rm -f "$usage"' EXIT
# TUI startup queries pass through Hermes' slash, shell, and interpolation
# dispatcher. One-shot treats the prompt literally and records its session ID.
seed_session() {
hermes --yolo --usage-file "$usage" --oneshot="$prompt"
}
if ! seed_session; then
if jq -e '.failed == true and (.failure | strings | startswith("No inference provider configured."))' "$usage" >/dev/null 2>&1; then
hermes setup
seed_session
else
exit 1
fi
fi
session_id=$(jq -er 'select(.completed == true and .failed != true) | .session_id | strings | select(length > 0)' "$usage")
rm -f "$usage"
trap - EXIT
exec hermes chat --yolo --tui --resume "$session_id"
+17 -12
View File
@@ -88,13 +88,13 @@ hermes_runs() {
timeout 15 "$HOME/.local/bin/hermes" --version >/dev/null 2>&1
}
# Prompted Omarchy sessions need Hermes' usage report to identify and validate
# the exact one-shot session before reopening it interactively.
# The chat subcommand's --oneshot opt-out arrived with native interactive -q,
# so its presence is a stable capability check without relying on a version.
hermes_prompt_ready() {
local help
hermes_runs &&
help=$(timeout 15 "$HOME/.local/bin/hermes" --help 2>/dev/null) &&
grep -qF -- '--usage-file' <<<"$help"
help=$(timeout 15 "$HOME/.local/bin/hermes" chat --help 2>/dev/null) &&
grep -qF -- '--oneshot' <<<"$help"
}
# --owns answers whether the wrapper on PATH is the one this command wrote, so
@@ -154,8 +154,8 @@ if foreign_hermes; then
fi
if hermes_runs; then
echo "~/.local/bin/hermes does not support the session report Omarchy needs for prompted launches." >&2
echo "Update it to Hermes Agent 0.18.1 or newer, then run omarchy-install-hermes-cli again." >&2
echo "~/.local/bin/hermes does not support the interactive seeded sessions Omarchy needs." >&2
echo "Update it to a Hermes Agent release with interactive chat queries, then run omarchy-install-hermes-cli again." >&2
exit 1
fi
@@ -164,12 +164,17 @@ if foreign_hermes; then
exit 1
fi
# An older mise environment may predate the session report. It belongs to this
# installer, so discard only that environment and let the current stub rebuild it.
# Only the marked wrapper proves the matching mise environment is ours to replace.
if installed && ! hermes_prompt_ready; then
echo "Updating Hermes for prompted sessions..." >&2
mise rm -g "$tool" >/dev/null 2>&1 || true
mise uninstall --all "$tool" >/dev/null 2>&1 || true
if ours; then
echo "Updating Hermes for prompted sessions..." >&2
mise rm -g "$tool" >/dev/null 2>&1 || true
mise uninstall --all "$tool" >/dev/null 2>&1 || true
else
echo "A Hermes mise environment exists without an Omarchy-owned wrapper." >&2
echo "Update or remove it explicitly, then run omarchy-install-hermes-cli again." >&2
exit 1
fi
fi
mkdir -p "$HOME/.local/bin"
@@ -218,7 +223,7 @@ chmod +x "$HOME/.local/bin/hermes"
if [[ $mode == "--now" ]]; then
"$HOME/.local/bin/hermes" --version
if ! hermes_prompt_ready; then
echo "Hermes installed without the session report Omarchy needs for prompted launches." >&2
echo "Hermes installed without the interactive seeded sessions Omarchy needs." >&2
exit 1
fi
fi
+12 -3
View File
@@ -431,8 +431,10 @@ assert_launched() {
fail "$agent launch $description" "expected: ${expected[*]}\nactual: ${actual[*]}"
for ((index = 0; index < ${#expected[@]}; index++)); do
[[ ${actual[$index]} == ${expected[$index]} ]] ||
fail "$agent launch $description" "expected: ${expected[*]}\nactual: ${actual[*]}"
case ${actual[$index]} in
"${expected[$index]}") ;;
*) fail "$agent launch $description" "expected: ${expected[*]}\nactual: ${actual[*]}" ;;
esac
done
}
@@ -462,11 +464,18 @@ assert_launch claude claude --permission-mode auto -- "Review this project"
assert_launch codex codex --approve-for-me -- "Review this project"
assert_launch crush crush run "Review this project"
assert_launch grok grok --permission-mode bypassPermissions -- "Review this project"
assert_launch hermes omarchy-agent-hermes "Review this project"
assert_launch hermes env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=Review this project"
assert_launch agy agy --dangerously-skip-permissions --prompt-interactive "Review this project"
assert_launch copilot copilot --allow-all --interactive "Review this project"
pass "agent launcher adapts initial prompts for every supported agent"
literal_hermes_prompt=$' --help !Crash /quit {$(touch must-not-run)}\ntrailing\\ '
printf '%s\n' "hermes" >"$agent_file"
omarchy-agent-prompt "$literal_hermes_prompt"
assert_launched hermes "binds its literal initial prompt" env -u HERMES_SESSION_SOURCE \
hermes chat --yolo --tui "--query=$literal_hermes_prompt"
pass "Hermes receives prompted launches as one literal query argument"
assert_bypass pi pi
assert_bypass omp omp --auto-approve
assert_bypass opencode opencode --auto
-126
View File
@@ -1,126 +0,0 @@
#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
mock_bin="$test_tmp/bin"
oneshot_log="$test_tmp/oneshot"
resume_log="$test_tmp/resume"
source_log="$test_tmp/source"
setup_log="$test_tmp/setup"
setup_marker="$test_tmp/setup-complete"
mkdir -p "$mock_bin"
cat >"$mock_bin/hermes" <<'SH'
#!/bin/bash
if [[ ${1:-} == "setup" ]]; then
printf '%s\0' "$@" >"$HERMES_TEST_SETUP_LOG"
[[ ${HERMES_TEST_SETUP_FAIL:-false} == "false" ]] || exit 43
touch "$HERMES_TEST_SETUP_MARKER"
exit
fi
if [[ " $* " == *" --oneshot="* ]]; then
printf '%s\0' "$@" >"$HERMES_TEST_ONESHOT_LOG"
printf '%s' "${HERMES_SESSION_SOURCE:-}" >"$HERMES_TEST_SOURCE_LOG"
while (( $# )); do
if [[ $1 == "--usage-file" ]]; then
usage=$2
break
fi
shift
done
if [[ ${HERMES_TEST_NEEDS_SETUP:-false} == "true" && ! -e $HERMES_TEST_SETUP_MARKER ]]; then
printf '{"session_id":null,"completed":null,"failed":true,"failure":"No inference provider configured. Run hermes model."}\n' >"$usage"
exit 1
fi
[[ ${HERMES_TEST_ONESHOT_FAIL:-false} == "false" ]] || exit 42
if [[ ${HERMES_TEST_USAGE_FAIL:-false} == "false" ]]; then
completed=true
failed=false
[[ ${HERMES_TEST_USAGE_INCOMPLETE:-false} == "false" ]] || completed=false
[[ ${HERMES_TEST_USAGE_FAILED:-false} == "false" ]] || failed=true
printf '{"session_id":"session-123","completed":%s,"failed":%s}\n' "$completed" "$failed" >"$usage"
fi
printf '%s\n' response
exit
fi
printf '%s\0' "$@" >"$HERMES_TEST_RESUME_LOG"
SH
chmod +x "$mock_bin/hermes"
export PATH="$mock_bin:$PATH"
export HERMES_TEST_ONESHOT_LOG="$oneshot_log"
export HERMES_TEST_RESUME_LOG="$resume_log"
export HERMES_TEST_SOURCE_LOG="$source_log"
export HERMES_TEST_SETUP_LOG="$setup_log"
export HERMES_TEST_SETUP_MARKER="$setup_marker"
sentinel="$test_tmp/hermes-seed-must-stay-literal"
prompt="--help !Crash /quit {!touch $sentinel}"$'\ntrailing\\'
HERMES_SESSION_SOURCE=gateway "$ROOT/bin/omarchy-agent-hermes" "$prompt" >/dev/null
mapfile -d '' -t oneshot_args <"$oneshot_log"
(( ${#oneshot_args[@]} == 4 )) || fail "Hermes literal seed has four one-shot arguments"
[[ ${oneshot_args[0]} == "--yolo" ]] || fail "Hermes literal seed enables yolo mode"
[[ ${oneshot_args[1]} == "--usage-file" ]] || fail "Hermes literal seed requests the session report"
usage_file=${oneshot_args[2]}
[[ ${oneshot_args[3]} == "--oneshot=$prompt" ]] || fail "Hermes literal seed binds option-looking prompts as data"
[[ ! -e $usage_file ]] || fail "Hermes literal seed removes its session report"
[[ ! -e $sentinel ]] || fail "Hermes literal seed never executes prompt interpolation"
[[ ! -s $source_log ]] || fail "Hermes literal seed preserves native CLI session metadata"
mapfile -d '' -t resume_args <"$resume_log"
[[ ${resume_args[*]} == "chat --yolo --tui --resume session-123" ]] ||
fail "Hermes literal seed resumes the exact completed session"
pass "Hermes sends initial prompts literally and resumes their exact session"
: >"$resume_log"
if HERMES_TEST_ONESHOT_FAIL=true "$ROOT/bin/omarchy-agent-hermes" failure >/dev/null 2>&1; then
fail "Hermes literal seed reports a failed initial turn"
fi
[[ ! -s $resume_log ]] || fail "Hermes literal seed does not resume a failed initial turn"
pass "Hermes does not resume after a failed initial turn"
: >"$resume_log"
if HERMES_TEST_USAGE_FAIL=true "$ROOT/bin/omarchy-agent-hermes" missing-session >/dev/null 2>&1; then
fail "Hermes literal seed requires a recorded session ID"
fi
[[ ! -s $resume_log ]] || fail "Hermes literal seed does not guess which session to resume"
pass "Hermes resumes only the session recorded by the initial turn"
for state in INCOMPLETE FAILED; do
: >"$resume_log"
if env "HERMES_TEST_USAGE_$state=true" "$ROOT/bin/omarchy-agent-hermes" "${state,,}" >/dev/null 2>&1; then
fail "Hermes literal seed rejects a reported ${state,,} initial turn"
fi
[[ ! -s $resume_log ]] || fail "Hermes literal seed does not resume a reported ${state,,} initial turn"
done
pass "Hermes resumes only completed successful initial turns"
: >"$resume_log"
HERMES_TEST_NEEDS_SETUP=true "$ROOT/bin/omarchy-agent-hermes" setup-first >/dev/null
mapfile -d '' -t setup_args <"$setup_log"
[[ ${setup_args[*]} == "setup" ]] || fail "Hermes runs setup when no inference provider is configured"
mapfile -d '' -t resume_args <"$resume_log"
[[ ${resume_args[*]} == "chat --yolo --tui --resume session-123" ]] ||
fail "Hermes replays the prompted turn after setup and resumes it"
pass "Hermes completes first-run setup before replaying the prompt"
rm -f "$setup_marker"
: >"$resume_log"
if HERMES_TEST_NEEDS_SETUP=true HERMES_TEST_SETUP_FAIL=true "$ROOT/bin/omarchy-agent-hermes" setup-cancelled >/dev/null 2>&1; then
fail "Hermes reports a failed first-run setup"
fi
[[ ! -s $resume_log ]] || fail "Hermes does not resume when first-run setup fails"
pass "Hermes stops when first-run setup does not complete"
+17 -7
View File
@@ -97,8 +97,8 @@ run_installer 1 --check && fail "--check reports Hermes missing before the app i
mkdir -p "$test_home/.hermes/hermes-agent/venv/bin"
cat >"$test_home/.hermes/hermes-agent/venv/bin/hermes" <<'SH'
#!/bin/bash
if [[ ${1:-} == "--help" ]]; then
[[ ${OMARCHY_TEST_HERMES_CAPABLE:-1} == 1 ]] && echo "--usage-file PATH"
if [[ ${1:-} == "chat" && ${2:-} == "--help" ]]; then
[[ ${OMARCHY_TEST_HERMES_CAPABLE:-1} == 1 ]] && echo "--oneshot"
else
echo "hermes-agent 0.0.0-test"
fi
@@ -135,12 +135,12 @@ run_installer 0 --now || fail "--now over a foreign hermes command returns succe
pass "a foreign hermes command is preserved and satisfies --check"
OMARCHY_TEST_HERMES_CAPABLE=0 run_installer 0 --check &&
fail "--check rejects a foreign Hermes without prompted-session reports"
fail "--check rejects a foreign Hermes without native prompted sessions"
OMARCHY_TEST_HERMES_CAPABLE=0 run_installer 0 &&
fail "installing refuses a foreign Hermes without prompted-session reports"
fail "installing refuses a foreign Hermes without native prompted sessions"
[[ $(cat "$test_home/.local/bin/hermes") == "$official_body" ]] ||
fail "an older foreign Hermes command is left untouched"
pass "a foreign Hermes must support prompted-session reports"
pass "a foreign Hermes must support native prompted sessions"
# Broken foreign paths are still foreign. They cannot be used, so --check says
# so and the installer refuses rather than replacing them.
@@ -237,6 +237,16 @@ tr '\0' '\n' <"$mise_log" | grep -q '^rm$' || fail "an older owned Hermes enviro
tr '\0' '\n' <"$mise_log" | grep -q '^uninstall$' || fail "an older owned Hermes environment is uninstalled"
pass "reinstalling replaces an older owned Hermes environment"
rm -f "$test_home/.local/bin/hermes"
: >"$mise_log"
OMARCHY_TEST_MISE_WHERE_OK=1 run_installer 0 &&
fail "installing refuses to claim an unmarked Hermes mise environment"
tr '\0' '\n' <"$mise_log" | grep -Eq '^(rm|uninstall)$' &&
fail "an unmarked Hermes mise environment is never removed"
[[ ! -e $test_home/.local/bin/hermes ]] ||
fail "an unmarked Hermes mise environment is not given an Omarchy wrapper"
pass "a Hermes mise environment needs wrapper ownership before replacement"
# install/user/mise.sh is sourced by install/user/all.sh through run_logged,
# which runs it under `bash -eE` and hands its exit code back to
# omarchy-provision-user's `set -euo pipefail`. Everything that finalizes a user
@@ -377,8 +387,8 @@ run_ready_check && fail "--check rejects the app's wrapper when its runtime is g
cat >"$ready_home/.hermes/hermes-agent/venv/bin/hermes" <<'SH'
#!/bin/bash
if [[ ${1:-} == "--help" ]]; then
echo "--usage-file PATH"
if [[ ${1:-} == "chat" && ${2:-} == "--help" ]]; then
echo "--oneshot"
else
echo "hermes-agent 0.0.0-test"
fi