Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions bin/omarchy-agent
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ if omarchy-cmd-missing "$agent"; then
exit 1
fi

# Agents launched from the keybinding or menu run unattended, so each one starts
# with its own spelling of "don't stop to ask". Pi and Ori have none to skip.
# Prompt launches run unattended, so each agent gets its own spelling of
# "don't stop to ask". Plain Hermes is the exception: its interactive launch
# remains approval-gated, while its one-shot prompt mode bypasses approvals.
# Pi and Ori have no approval prompts.
case "$agent" in
opencode)
command=(opencode --auto)
Expand All @@ -62,6 +64,21 @@ agy)
command=(agy --dangerously-skip-permissions)
[[ -n ${prompt:-} ]] && command+=(--prompt-interactive "$prompt")
;;
hermes)
# Plain Hermes stays interactive and approval-gated. A supplied prompt uses
# one-shot mode, which auto-bypasses approvals. New terminal launches go
# through a small holder so the final answer stays visible; --inline returns
# it directly to the terminal the user already has open.
if [[ -n ${prompt:-} ]]; then
if [[ $inline == "true" ]]; then
command=(hermes -z "$prompt")
else
command=(omarchy-agent-hermes-prompt "$prompt")
fi
else
command=(hermes)
fi
;;
copilot)
command=(copilot --allow-all)
[[ -n ${prompt:-} ]] && command+=(--interactive "$prompt")
Expand Down
64 changes: 64 additions & 0 deletions bin/omarchy-agent-hermes-prompt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/bin/bash

# omarchy:summary=Show a Hermes one-shot result and accept typed follow-ups
# omarchy:args=<prompt>
# omarchy:hidden=true

set -u

if (($# != 1)); then
echo "Usage: omarchy-agent-hermes-prompt <prompt>" >&2
exit 1
fi

status=0
session_id=""
tmp_file=""

cleanup() {
[[ -n $tmp_file ]] && rm -f "$tmp_file"
}
trap cleanup EXIT

# One-line heads-up before the first call: a full diagnosis takes minutes and
# Hermes one-shot mode prints nothing until it finishes, so an unexplained
# blank window reads as a hang. This line is what makes the wait legible.
echo "Diagnosing with Hermes — this may take a few minutes."

# The first call uses single-query mode with the same auto-bypass approval
# semantics as `hermes -z`. Output is teed so Hermes' live progress (agent
# startup, reasoning, tool activity) streams to the window instead of being
# buffered until the end, and the session id is captured for follow-ups.
run_turn() {
local question=$1
shift
tmp_file=$(mktemp)
hermes chat -q "$question" --yolo "$@" 2>&1 | tee "$tmp_file"
status=${PIPESTATUS[0]}
if [[ -z $session_id ]]; then
session_id=$(sed -n -E 's/^(session_id|Session):[[:space:]]*([A-Za-z0-9_-]+).*/\2/p' "$tmp_file" | tail -1)
fi
rm -f "$tmp_file"
tmp_file=""
}

run_turn "$1"

while true; do
printf 'Ask a follow-up, or press Enter to close: '
read -r followup || { printf '\n'; break; }
[[ -n $followup ]] || break

if [[ -n $session_id ]]; then
run_turn "$followup" --resume "$session_id"
else
run_turn "$followup"
fi
done

if ((status != 0)); then
echo "Hermes exited with status $status. Press Enter to close." >&2
read -r || true
fi

exit "$status"
28 changes: 22 additions & 6 deletions bin/omarchy-default-agent
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# omarchy:summary=Set and launch the default coding agent
# omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush]
# omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush|hermes]
# omarchy:examples=omarchy default agent | omarchy default agent codex | omarchy default agent claude

installing=false
Expand Down Expand Up @@ -33,20 +33,32 @@ codex) agent="codex"; name="Codex" ;;
crush) agent="crush"; name="Crush" ;;
grok) agent="grok"; name="Grok"; agent_package="npm:@xai-official/grok" ;;
agy | antigravity | antigravity-cli | gemini | gemini-cli) agent="agy"; name="Antigravity"; agent_package="antigravity-cli" ;;
hermes | nous-hermes) agent="hermes"; name="Hermes" ;;
copilot | github-copilot) agent="copilot"; name="GitHub Copilot" ;;
*)
echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush>"
echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|agy|copilot|crush|hermes>"
exit 1
;;
esac

agent_package=${agent_package:-$agent}

if [[ $installing == "false" ]] && ! mise where "$agent_package" &>/dev/null; then
exec omarchy-launch-floating-terminal-with-presentation omarchy-default-agent --install "$agent"
if [[ $installing == "false" ]]; then
if [[ $agent == "hermes" ]]; then
if ! omarchy-install-hermes-cli --check; then
exec omarchy-launch-floating-terminal-with-presentation omarchy-default-agent --install "$agent"
fi
elif ! mise where "$agent_package" &>/dev/null; then
exec omarchy-launch-floating-terminal-with-presentation omarchy-default-agent --install "$agent"
fi
fi

if ! mise use -g "$agent_package"; then
if [[ $agent == "hermes" ]]; then
if [[ $installing == "true" ]] && ! omarchy-install-hermes-cli; then
echo "Could not install Hermes" >&2
exit 1
fi
elif ! mise use -g "$agent_package"; then
if [[ $installing == "true" ]]; then
echo "Could not install $name with mise" >&2
else
Expand All @@ -60,7 +72,11 @@ printf '%s\n' "$agent" >"$agent_file"

if [[ $installing == "true" ]]; then
printf '\033[2J\033[3J\033[H'
exec omarchy-agent --inline
if [[ $agent == "hermes" ]]; then
exec hermes setup
else
exec omarchy-agent --inline
fi
else
exec omarchy-agent
fi
73 changes: 73 additions & 0 deletions bin/omarchy-install-hermes-cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/bash

# omarchy:summary=Install Hermes CLI through its supported upstream installer
# omarchy:args=[--check|--stub]

hermes_command="$HOME/.local/bin/hermes"
stub_marker="# omarchy-hermes-installer-stub"

is_installer_stub() {
[[ -f $hermes_command ]] && grep -Fxq "$stub_marker" "$hermes_command"
}

is_installed() {
omarchy-cmd-present hermes && ! is_installer_stub
}

case "${1:-}" in
--check)
is_installed
exit
;;
--stub)
if [[ -e $hermes_command ]]; then
if ! is_installer_stub; then
exit 0
fi
elif [[ ! -L $hermes_command ]] && is_installed; then
exit 0
fi

mkdir -p "$HOME/.local/bin"
rm -f "$hermes_command"
cat >"$hermes_command" <<'STUB'
#!/bin/bash
# omarchy-hermes-installer-stub
omarchy-install-hermes-cli || exit 1
exec "$HOME/.local/bin/hermes" "$@"
STUB
chmod +x "$hermes_command"
exit 0
;;
"") ;;
*)
echo "Usage: omarchy-install-hermes-cli [--check|--stub]" >&2
exit 1
;;
esac

# A real Hermes install owns its updates through `hermes update`. Omarchy only
# bootstraps missing installations and never turns a normal system update into
# an unrequested Hermes update.
if is_installed; then
exit 0
fi

installer=$(mktemp)
trap 'rm -f "$installer"' EXIT

if ! curl -fsSL https://hermes-agent.nousresearch.com/install.sh -o "$installer"; then
echo "Could not download the official Hermes installer" >&2
exit 1
fi

if ! bash "$installer" --skip-setup --non-interactive; then
echo "The official Hermes installer failed" >&2
exit 1
fi

hash -r
if [[ ! -x $hermes_command ]] || is_installer_stub; then
echo "Hermes installer finished without creating $hermes_command" >&2
exit 1
fi
10 changes: 9 additions & 1 deletion bin/omarchy-provision-user
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fi
# Dev-aware skill symlinks. Cannot live in /etc/skel because OMARCHY_PATH may
# point at a dev checkout (omarchy dev link) where the target differs.
# Loops every skill directory, so shipping a new one needs no edit here.
mkdir -p ~/.agents/skills ~/.claude/skills ~/.codex/skills ~/.pi/agent/skills ~/.gemini/config/skills
mkdir -p ~/.agents/skills ~/.claude/skills ~/.codex/skills ~/.pi/agent/skills ~/.gemini/config/skills ~/.hermes/skills
for skill in "$OMARCHY_PATH"/default/agents/skills/*/; do
skill=${skill%/}
name=${skill##*/}
Expand All @@ -93,6 +93,14 @@ for skill in "$OMARCHY_PATH"/default/agents/skills/*/; do
ln -sfn "$skill" ~/.codex/skills/"$name"
ln -sfn "$skill" ~/.pi/agent/skills/"$name"
ln -sfn "$skill" ~/.gemini/config/skills/"$name"
ln -sfn "$skill" ~/.hermes/skills/"$name"
if [[ -d ~/.hermes/profiles ]]; then
for profile in ~/.hermes/profiles/*/; do
[[ -d $profile ]] || continue
mkdir -p "$profile/skills"
ln -sfn "$skill" "$profile/skills/$name"
done
fi
done

mkdir -p ~/Downloads ~/Pictures ~/Videos ~/.config/gtk-3.0
Expand Down
8 changes: 7 additions & 1 deletion bin/omarchy-remove-preinstalls
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ if gum confirm "Are you sure you want to remove all preinstalled web apps, TUI w
touch ~/.local/state/omarchy/preinstalls-removed
hyprctl reload

# Remove mise stubs
# Remove lazy launchers. Hermes stops being Omarchy-owned as soon as its
# marked stub replaces itself with the upstream installer's real launcher.
hermes_launcher="$HOME/.local/bin/hermes"
if [[ -f $hermes_launcher ]] && grep -Fxq '# omarchy-hermes-installer-stub' "$hermes_launcher"; then
rm -f "$hermes_launcher"
fi

rm -f ~/.local/bin/codex ~/.local/bin/claude ~/.local/bin/agy ~/.local/bin/copilot \
~/.local/bin/gh ~/.local/bin/opencode ~/.local/bin/playwright ~/.local/bin/playwright-cli ~/.local/bin/pi \
~/.local/bin/omp ~/.local/bin/ori ~/.local/bin/grok ~/.local/bin/crush ~/.local/bin/ghui ~/.local/bin/hunk
Expand Down
1 change: 1 addition & 0 deletions default/omarchy/omarchy-menu.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
"setup.default.agent.copilot": {"icon":"","label":"Copilot","checked":"[[ \"$(omarchy-default-agent)\" == \"copilot\" ]]","action":"omarchy-default-agent copilot"},
"setup.default.agent.crush": {"icon":"󰋑","label":"Crush","checked":"[[ \"$(omarchy-default-agent)\" == \"crush\" ]]","action":"omarchy-default-agent crush"},
"setup.default.agent.grok": {"icon":"","iconFont":"omarchy","label":"Grok","checked":"[[ \"$(omarchy-default-agent)\" == \"grok\" ]]","action":"omarchy-default-agent grok"},
"setup.default.agent.hermes": {"icon":"󰚩","label":"Hermes","checked":"[[ \"$(omarchy-default-agent)\" == \"hermes\" ]]","action":"omarchy-default-agent hermes"},
"setup.default.agent.omp": {"icon":"","iconFont":"omarchy","label":"omp","checked":"[[ \"$(omarchy-default-agent)\" == \"omp\" ]]","action":"omarchy-default-agent omp"},
"setup.default.agent.opencode": {"icon":"","iconFont":"omarchy","label":"OpenCode","checked":"[[ \"$(omarchy-default-agent)\" == \"opencode\" ]]","action":"omarchy-default-agent opencode"},
"setup.default.agent.ori": {"icon":"","iconFont":"omarchy","label":"Ori","checked":"[[ \"$(omarchy-default-agent)\" == \"ori\" ]]","action":"omarchy-default-agent ori"},
Expand Down
5 changes: 3 additions & 2 deletions docs/file-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,12 @@ Runs once per user. It does **not** copy `~/.config/**`, `~/.bashrc`,
`flags.lua`, or the nautilus extensions — `/etc/skel` already seeded those.
It only does the things `/etc/skel` can't:

- Skill symlinks `~/.{agents,claude,codex,pi/agent}/skills/<name>` →
- Skill symlinks `~/.{agents,claude,codex,pi/agent,hermes}/skills/<name>` (and each `~/.hermes/profiles/*/skills/<name>`) →
`$OMARCHY_PATH/default/agents/skills/<name>`, looping over every skill
directory there (currently `omarchy` and `diagnose-crash`) so new skills
need no edit. Symlinks (not copies) so `omarchy dev link` against a dev
checkout repoints them correctly.
checkout repoints them correctly. Hermes profile dirs are only linked when
they already exist — provision does not create Hermes profiles.
- `xdg-user-dirs-update` (Templates/Public/Desktop folded back into `$HOME`)
and `~/.config/gtk-3.0/bookmarks` (needs `$HOME` expansion).
- Hyprland's package-owned default input reads `XKBLAYOUT` / `XKBVARIANT`
Expand Down
1 change: 1 addition & 0 deletions install/user/mise.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ omarchy-mise-install npm:playwright playwright
omarchy-mise-install pi
omarchy-mise-install github:can1357/oh-my-pi omp
omarchy-mise-install npm:@xai-official/grok grok
omarchy-install-hermes-cli --stub
omarchy-mise-install npm:@kitlangton/ghui ghui
omarchy-mise-install aqua:modem-dev/hunk hunk
omarchy-mise-install github:basecamp/hey-cli hey
Expand Down
13 changes: 8 additions & 5 deletions manual/17-ai.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AI

Omarchy treats AI coding agents as first-class citizens, but it doesn't pick a favorite for you. Instead, every major coding-agent CLI comes pre-wired as a lazy-loaded launcher. The launchers are tiny [mise](https://mise.jdx.dev/)-managed stubs in `~/.local/bin/`, so nothing is downloaded until the first time you actually run one. Invoke any of these and authenticate when prompted:
Omarchy treats AI coding agents as first-class citizens, but it doesn't pick a favorite for you. Instead, every major coding-agent CLI comes pre-wired as a lazy-loaded launcher in `~/.local/bin/`, so nothing is downloaded until the first time you actually run one. Most are tiny [mise](https://mise.jdx.dev/)-managed stubs; Hermes uses its supported upstream installer instead. Invoke any of these and authenticate when prompted:

| Command | Agent |
|------------|------------------------------------------------------------------|
Expand All @@ -13,17 +13,18 @@ Omarchy treats AI coding agents as first-class citizens, but it doesn't pick a f
| `grok` | Grok CLI from xAI |
| `pi` | [Mario Zechner's Pi](https://github.com/badlogic/pi-mono) |
| `omp` | [Oh My Pi](https://github.com/can1357/oh-my-pi) |
| `hermes` | [Hermes](https://hermes-agent.nousresearch.com) |
| `ori` | [Ori](https://openrouter.ai/docs/guides/ori/harness), OpenRouter's harness |

`ori` is the odd one out: it runs the other harnesses against OpenRouter's whole model catalog, so `ori claude`, `ori codex`, or `ori opencode` start those agents on whichever model you point them at, and `ori code` is Ori's own agent.

To wrap an additional CLI the same way, run `omarchy-mise-install <package> [command-name]`. The stubs are kept current along with everything else mise manages when you run `omarchy update` (or the `mup` alias).
Most agent commands are lazy mise wrappers. To wrap another CLI the same way, run `omarchy-mise-install <package> [command-name]`; those stubs stay current along with mise during `omarchy update` (or the `mup` alias). Hermes is the exception because its PyPI package is unsupported upstream: its lazy stub invokes Hermes' official Linux installer with setup deferred, and later updates belong to `hermes update`.

### The default agent

Pick your default agent with `omarchy default agent <name>` or under _Setup > Defaults > Agent_ in the Omarchy Menu (`Super + Space`). If the agent isn't installed yet, picking it installs it first. A fresh Omarchy will invite you to make this choice with a one-time notification.
Pick your default agent with `omarchy default agent <name>` or under _Setup > Defaults > Agent_ in the Omarchy Menu (`Super + Space`). If the agent isn't installed yet, picking it installs it first. Hermes then opens `hermes setup` for its one-time provider configuration. A fresh Omarchy will invite you to make this choice with a one-time notification.

Once you've chosen, `Super + Shift + Ctrl + A` launches the default agent in a dedicated terminal window (or brings up the picker if you haven't chosen yet). You can also launch it straight into a task with `omarchy agent prompt "Review this project"`. Agents launched this way run unattended in their respective don't-stop-to-ask modes, so be ready for them to actually do things! And since agents refuse to remember trust for your home directory, launches from `$HOME` start in `~/Work` instead.
Once you've chosen, `Super + Shift + Ctrl + A` launches the default agent in a dedicated terminal window (or brings up the picker if you haven't chosen yet). You can also launch it straight into a task with `omarchy agent prompt "Review this project"`. Prompt launches run unattended in each agent's don't-stop-to-ask mode, so be ready for them to actually do things; in Hermes, `-z` one-shot mode auto-bypasses approvals. An ordinary interactive Hermes launch stays approval-gated. And since agents refuse to remember trust for your home directory, launches from `$HOME` start in `~/Work` instead.

There are terminal shortcuts too: `a` runs the default agent inline in the current terminal, while `c`, `cx`, and `cy` start OpenCode, Claude Code, and Codex directly (again in their auto-approving modes). Theme changes sync to the agents as well: Claude Code, Pi, and OpenCode all follow along when you switch the Omarchy theme.

Expand All @@ -37,6 +38,8 @@ Left-click the bar icon for the panel, right-click to launch your default agent.

Omarchy watches systemd-coredump for process crashes. When something segfaults, you'll get a "Process crashed" notification — click it, and the crash is handed to your default agent along with Omarchy's diagnose-crash skill, which walks the agent through establishing the facts from the core dump and deciding whether the crash is worth reporting upstream. You can also run it by hand against any PID from `coredumpctl list` with `omarchy agent crash <pid>`.

The diagnosis runs in a dedicated terminal. A full investigation takes a few minutes, and the window says so up front — Hermes' live progress (agent startup, reasoning, tool activity) streams to the window while it works, and the full report appears when it's done. The window then stays open: type a follow-up question to keep asking about the same crash in the same conversation, or press Enter to close.

The watching is on by default. Turn it off under _Trigger > Toggle > Crash Capture_ (or with `omarchy toggle crash-capture`) and the notifications stop; `omarchy agent crash <pid>` still works by hand.

### Desktop apps
Expand All @@ -49,6 +52,6 @@ Omarchy recommends two ways of running local LLM models: LM Studio and Ollama. L

### The Omarchy Skill

Agent skills help AI use specific tools in a specific way, and Omarchy ships with a default skill for tailoring the system. Like tweaking your Hyprland config, adjusting the bar, or even creating a new theme from scratch. It's symlinked into the skill directories for Claude Code (`~/.claude/skills`), Codex (`~/.codex/skills`), Pi (`~/.pi/agent/skills`), Antigravity (`~/.gemini/config/skills`), and the generic `~/.agents/skills` location, so most harnesses pick it up automatically.
Agent skills help AI use specific tools in a specific way, and Omarchy ships with a default skill for tailoring the system. Like tweaking your Hyprland config, adjusting the bar, or even creating a new theme from scratch. It's symlinked into the skill directories for Claude Code (`~/.claude/skills`), Codex (`~/.codex/skills`), Pi (`~/.pi/agent/skills`), Antigravity (`~/.gemini/config/skills`), Hermes (`~/.hermes/skills` and each `~/.hermes/profiles/*/skills`), and the generic `~/.agents/skills` location, so most harnesses pick it up automatically.

But you should treat this skill as experimental. Different models will use it to different effect. It's best to run in plan mode first, so you have an idea of what the agent would like to change. And then be ready to rollback changes or even invoking `omarchy reinstall configs`, if the agent makes a mess of everything.
25 changes: 25 additions & 0 deletions migrations/1787063342.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
echo "Install Hermes lazy official-installer stub"

if [[ ! -f $HOME/.local/state/omarchy/preinstalls-removed ]]; then
omarchy-install-hermes-cli --stub
fi

echo "Link Omarchy skills into the Hermes skill directory"

# Skill symlinks are deliberately unguarded: crash diagnosis is a core
# feature, not an optional preinstall, and the other agent skill symlinks
# (bin/omarchy-provision-user, migrations/1786539345.sh) are created
# unconditionally as well.
mkdir -p "$HOME/.hermes/skills"
for skill in "$OMARCHY_PATH"/default/agents/skills/*/; do
skill=${skill%/}
name=${skill##*/}
ln -sfn "$skill" "$HOME/.hermes/skills/$name"
if [[ -d $HOME/.hermes/profiles ]]; then
for profile in "$HOME"/.hermes/profiles/*/; do
[[ -d $profile ]] || continue
mkdir -p "$profile/skills"
ln -sfn "$skill" "$profile/skills/$name"
done
fi
done
Loading