Commit Graph
669 Commits
Author SHA1 Message Date
Erik Melton bf10b75150 Protect the Windows VM web console 2026-08-29 15:15:51 +01:00
079d116511 Cover the Plymouth parent-chain walk and guard its test harness
Deleting the whole ancestor walk from validate_trusted_directory and checking
only the immediate parent left the suite green, so the invariant the design
rests on had no coverage: a writable ancestor lets an attacker swap a validated
directory out from under the leaf. Reject a run whose destination grandparent
is world-writable while the destination itself is pristine.

The harness also rewrites the root script's fixed /usr/share paths by string
substitution. A drifted string silently no-ops that rewrite and would point the
simulation at the real system tree, so assert each substitution landed. Assert
the scratch directory exists too: a failed mktemp left it empty and the suite
carried on building paths from it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-29 16:01:01 +02:00
David Heinemeier HanssonandClaude Opus 5 d3b7810a76 Say why the privileged Plymouth transaction refused
Every check inside the root shell is a bare [[ ]] or (( )) assertion that
aborts under set -e, so a refusal exited with status 1 and no output at all.
The floating-terminal wrapper then printed its green "Done!" for any status
but 130, so a failed boot-theme change read as a success.

The refusal a working machine actually hits is omarchy dev link, which points
OMARCHY_PATH at a checkout the desktop user owns. Name that case outright and
point at omarchy dev unlink; report every other rejection through an ERR trap
that names what failed validation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 16:00:50 +02:00
Erik Melton 05fb36d3cc Build Plymouth assets in a root-owned stage 2026-08-29 15:05:13 +02:00
Afonso Oliveiraanditz4blitz 20a23b8c16 [Security] Complete Plymouth publication coverage
Keep SDDM color substitution collision-free for White themes, based on the fix proposed in #8469.

Co-authored-by: itz4blitz <itz4blitz@users.noreply.github.com>
2026-08-29 14:45:17 +02:00
Afonso Oliveira 0f15e2330f [Security] Harden Plymouth asset publication 2026-08-29 14:45:17 +02:00
Afonso Oliveira 2b91fdc0d3 [Security] Pin Plymouth asset reads before elevation 2026-08-29 14:44:37 +02:00
Ryan Hughes 0b3f1b7ead Merge pull request #8496 from Chessing234/security/webapp-http-only 2026-08-29 03:32:08 -04:00
Ryan Hughes f20bf0a21b Merge pull request #8473 from bastidotnet/fix/webapp-desktop-value-escaping 2026-08-29 03:27:39 -04:00
Ryan Hughes 9da8824098 Merge pull request #8416 from mdisec/theme-name-shell-syntax
Refuse a theme name that is shell syntax, and quote the one the unlock picker returns
2026-08-29 03:19:45 -04:00
Ryan Hughes 169ad00a84 Merge pull request #8627 from mdisec/security/harden-cups-browsed
Harden CUPS printer discovery
2026-08-29 02:19:53 -04:00
Ryan Hughes 74997fd523 Ship CUPS authorization through settings package 2026-08-29 02:18:44 -04:00
Ryan Hughes f0672772d2 Merge pull request #8268 from Skeptomenos/fix/copy-url-python-shim-recursion
Avoid mise shim recursion in Copy URL migration test
2026-08-28 21:54:19 -04:00
Tobi Lutke 41a40ccc78 Show captive portal status and sign-in action in network panel 2026-08-28 20:08:26 -05:00
Ryan Hughes 6b10dbf191 Harden Firefox policy dirs even when the theme refresh fails 2026-08-28 19:00:03 -04:00
Ryan Hughes 5925929cb6 Stop the browser policy EXIT trap from reporting a clean run as failed 2026-08-28 19:00:03 -04:00
Ryan Hughes 7d58bb9a62 Merge pull request #7972 from acrogenesis/harden-browser-policy-dirs
Stop world-writable browser policy directories
2026-08-28 18:00:20 -04:00
Spencer BullandCodex XHigh 5284be6582 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>
2026-08-28 16:32:19 -05:00
Ryan Hughes 468b511249 Merge pull request #8397 from ErikMelton/unauthorized-http-get-requests-from-notifications
Require textFormat declaration for all Text elements
2026-08-28 15:50:19 -04:00
Afonso Oliveira 4fc14173b7 [Security] Add Windows VM boundary race regressions 2026-08-28 19:37:04 +01:00
David Heinemeier Hansson 06e32d243d Merge pull request #8198 from bastidotnet/harden-apple-brightness-device-cache
Validate the cached Apple-display device path before use
2026-08-28 14:42:22 +02:00
Spencer BullandCodex XHigh 64203cc208 Keep prompted Hermes sessions local
Clear inherited session-source tags for Omarchy's local one-shot process so Hermes records the launch directory before the exact session is resumed in the TUI.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 23:07:42 -05:00
Spencer BullandCodex XHigh 36353296aa Harden prompted Hermes session handoff
Bind option-looking prompts to one-shot mode, require a successful completed usage report before resuming, replay the prompt after first-run setup, and reject Hermes runtimes that lack the session-report capability.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 23:01:30 -05:00
Spencer BullandCodex XHigh 288e387a22 Preserve Hermes session workspace metadata
Keep the one-shot session on Hermes' native CLI source so it records the launch directory before the exact session is resumed in the TUI.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 22:50:28 -05:00
Spencer BullandCodex XHigh 750dde5ed2 Resume prompted Hermes sessions literally
Hermes TUI startup queries execute slash, shell, interpolation, and multiline syntax before reaching the model. Run the prompt through literal one-shot mode, read its exact session ID from a private usage report, and resume that session in the TUI so arbitrary prompt text stays data while the conversation remains interactive.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 22:37:03 -05:00
Spencer BullandCodex XHigh b609ae2355 Keep prompted Hermes sessions interactive
Hermes oneshot deliberately exits after answering, which closes the agent terminal. Seed the TUI chat session instead, keep inherited flags after the subcommand for older Hermes parsers, and bind the query as one argument so dash-prefixed prompts remain data.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 21:31:17 -05:00
Afonso Oliveira a165185a3f [Security] Complete Windows VM mount hardening 2026-08-27 23:53:44 +01:00
9d8c0176d1 Make the cache tests fail when either check is removed
Neither half of the validation was covered. Dropping `&& -c $cached` from the wrapper left the whole file green: all three poison values fail on the pathname prefix, so none of them ever reached the character-device test. A path that matches the hiddev glob but is not a device now covers it, and it is the real case rather than a synthetic one -- the display replugs, the interface renumbers, and the cached node is gone. It is added only when the host has no such node, so a machine with the display attached cannot fail there spuriously.

The no-XDG_RUNTIME_DIR assertion had the same problem for the opposite reason: its decoy held a path the validation rejects on its own, so restoring the `${XDG_RUNTIME_DIR:-/tmp}` fallback left it passing. It asserts on the open now instead of on the contents -- a FIFO with no writer blocks whoever opens it, so a wrapper that consults the path hangs and one that ignores it exits. mkfifo is atomic and fails outright if the path is taken, so it still neither overwrites a file nor follows a symlink at the fixed path.

Clearing created_tmp_cache as soon as the decoy is removed keeps this run's EXIT trap from deleting a concurrent run's decoy at the same fixed path, which would have let that run pass against the old code.

🤖 Generated by Opus 5 in Claude Code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 21:40:31 +02:00
9382410026 Validate the web app URL before anything fetches it
The scheme check ran after the interactive branch, which had already handed the URL to curl: a refused `file://` or `ftp://` URL was dereferenced first, the whole string went out to Google's favicon endpoint in a `domain=` query, and a fetch that happened to succeed left an orphan icon and a rebuilt icon cache behind. Validating immediately after normalization puts the refusal ahead of every dereference in both branches.

A leading space also kept the URL out of the scheme test entirely. `normalize_webapp_url` saw no scheme, prefixed it, and ` file:///etc/passwd` became `https:// file:///etc/passwd`, which passes `^https?://`. The desktop `Exec` field is unquoted, so it splits back into two arguments, and `omarchy-launch-webapp` forwards everything after the first to the browser, where a bare argument is another URL to open. Refusing whitespace closes that without touching desktop-entry escaping.

Scheme comparison is case-insensitive because schemes are: `HTTPS://example.com` installed before this check existed and has no reason to stop.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 20:10:15 +02:00
b07374f03c Reserve the cups-browsed account name at install
The username prompt already refuses the service accounts a desktop user must not claim, cups and lp among them. A user who took cups-browsed would get a primary group of that name, and the CUPS authorization written here puts that group in SystemGroup, handing that desktop user the passwordless administration the rest of this change removes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 19:55:36 +02:00
68fc0cf6e6 Match the CUPS directives being rewritten the way cupsd reads them
cupsd compares directive names with _cups_strcasecmp, so a hand-edited "systemgroup sys root wheel" is live configuration, but matching $1 against the canonical spelling skipped it and appended a second directive at the end of the file. parse_groups accumulates the groups of every SystemGroup directive it reads rather than replacing them, so both lines took effect and wheel kept the passwordless administration this is meant to remove, with the migration reporting success.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 19:55:36 +02:00
David Heinemeier HanssonandCodex XHigh 2b923cf5bd Pin the theme name check to C, and read a colon before any slash as scp-style
A bracket range is collated, not ASCII, so `[a-z]` admits `é` under
en_US.UTF-8 and refuses it under C: the same theme URL installed on one
desktop and was refused on the next, and the manual's stated set was only
true in the C locale. Pinning the comparison makes the written set the
shipped one everywhere.

git reads a URL as scp-style when a colon appears before any slash, so the
path after it need not contain one. Requiring a slash left the prefix on
`git@host:omarchy-blue-theme.git` and derived the name
`git@host:omarchy-blue`, which the allowlist then refuses -- a repo that
clones fine could no longer be installed at all.

Co-Authored-By: Codex XHigh <codex@openai.com>
2026-08-27 19:52:37 +02:00
521f1ae9ac Resume cups-browsed on whether it is enabled, not on whether it was running
The migration recomputed whether cups-browsed was active at the start of every run, after an earlier run may already have stopped it. A run interrupted between that stop and the completion marker left the service down, and the retry that followed read it as inactive, skipped the restart, and wrote the marker anyway: printer discovery stayed off until the next reboot with no migration left to bring it back. Keying the restart to whether the unit is enabled survives the interruption, and reports not-enabled for a unit the user masked or disabled, which restarting would fail on and abort the migration short of its marker.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 19:47:10 +02:00
c2587dff08 Escape .desktop values with parameter expansion, not sed
GNU sed's N auto-prints the pattern space and exits at end of input, so the
`:a;N;$!ba` slurp skipped every following s/// for a value with no newline in
it. That is every value except the injection attempt the escaping exists to
stop, so the Exec quoting's own backslashes were written to the file unescaped
and GLib refused to load the entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex GPT-5.6-sol (xhigh) <noreply@openai.com>
2026-08-27 19:45:45 +02:00
Omarchybot 83881e979b Merge pull request #7984 from Chessing234/fix/webapp-name-slashes
Keep a web app name out of the launcher's directory structure
2026-08-27 19:40:46 +02:00
ClaudeandClaude Opus 5 9ece53cede Prove the web app name guard, and reject before the icon is fetched
The slash guard was the only thing keeping a name out of the directory structure, and nothing tested it: deleting it left the suite green, because creating the launcher directly in the applications directory already makes the redirect fail on its own, with a raw bash error instead of the message. The assertion is on the message now, alongside the traversal case the guard actually closes -- on quattro a name of `../../../../escaped` writes its launcher clean outside the applications directory.

The interactive prompt read the name, fetched the favicon, wrote it and updated the icon cache before the name was ever checked, so a URL typed into the Name field left an icon behind on every attempt. Validating as soon as the name is read covers both paths from one place.

Removing by name also scanned unconditionally, so a machine with no applications directory printed a find error where omarchy-remove-gaming-xbox-cloud does not hide stderr.

🤖 Generated by Opus 5 in Claude Code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 19:25:25 +02:00
Mehmet InceandDaybreak Blue 5c336885d2 Harden CUPS printer discovery
Run cups-browsed as a locked service account with a dedicated cache and a focused systemd sandbox. Restrict automatic queues to driverless IPP printers, remove wheel from passwordless CUPS administration, replace cups-pdf with Polkit-backed setup, and migrate existing systems safely.

Reported-By: Erik Hunstad (Bad Sector Labs)

Co-Authored-By: Daybreak Blue <noreply@openai.com>
2026-08-27 18:00:12 +01:00
4be440b501 Close six ways the textFormat scan reported success without checking
Each of these is a Text rendering external data with no textFormat, written in
a form that passed silently. None exists in this tree, so they were holes in
the guard rather than live exposures — but a guard is only worth what it
catches, and every one of them is a single line someone could plausibly write.

  Text /* why */ {          strip_noise knew // and not /* */, so a block
                            comment between the type name and its brace hid
                            the element from every rule at once
  QQ.Text { ... }           a namespaced import made the name compare unequal
                            to `Text`, and the element was skipped outright
  visible: textFormatEnabled  textFormat was matched as a substring, so a
                            lookalike property exempted the whole block
  component Info:           a component root with its Text on the next line;
    Text {                  the one-line form was covered and this was not
  an unreadable subdirectory  rglob() swallows a directory it cannot enter, so
                            a locked subtree scanned as though it were empty

The scan moves out of the heredoc into qml-text-format-scan.py, taking its root
as an argument, because nothing could run it over anything but the real tree —
and a scanner whose only input always passes cannot be shown to fail. The test
now runs it over nineteen fixtures, one per form above and one per form the
scan already handled, so a later edit that loosens it fails here instead of
going unnoticed until something renders a remote image.

Two limits stay open and are written down in the module docstring rather than
papered over: text assigned from elsewhere (a Binding element, PropertyChanges,
an onCompleted assignment, a property alias onto a child) is invisible to a
scanner that reads each element's own declaration, and a regex literal holding
a brace throws off the brace depth. Neither shape exists in this tree and both
need a QML parser, not another regex.

Co-Authored-By: Codex XHigh <noreply@openai.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 17:28:13 +02:00
David Heinemeier Hansson 7026ede90b Strip image tags after the newline rewrite, not before it
The card binds the body Text to styledBody, which rewrites newlines to <br/>
*after* sanitizeBody has run. That rewrite inserts tag syntax into text the
stripper deliberately kept: a kept tag may hold a `<` of its own, and `<x`,
newline, `<img src="http://host/x.png">` is one tag named `x` to both the
stripper and Qt, so it survives whole — until the rewrite splits it into
`<x<br/>` and a live image tag the input never contained.

Measured against Qt 6.11.2 with an offscreen StyledText and a local HTTP
server: that body issues the GET after this branch's sanitizer and issues
nothing before it, because the one-pass /<img[^>]*>/gi it replaces deleted the
inner substring outright. The whole-tag bound is still the right trade — it is
what stops the stripper manufacturing tags — but it only holds if nothing edits
the string afterwards.

So move the rewrite into NotificationLogic, next to the reasoning it depends
on, and strip again after it. What Qt parses is then what was checked last. The
tests assert on styledBody for the same reason, since sanitizeBody's output is
no longer the string that reaches the renderer, and a regex assertion pins the
card's binding because no JavaScript assertion can see a QML property.
2026-08-27 16:53:55 +02:00
David Heinemeier HanssonandClaude Opus 5 cda02f0a88 Ask the installer who owns the Hermes wrapper
Three files spelled out the line that marks ~/.local/bin/hermes as Omarchy's:
the installer that writes it, Remove Preinstalls, and the migration. Two of
them were copies, and a change to what ownership means would have left them
matching a line nobody writes any more -- Remove Preinstalls quietly sweeping
nothing, the migration mistaking Omarchy's own wrapper for a stranger's.

omarchy-install-hermes-cli --owns answers it now, and the other two ask. The
installer's own metadata was also a flag behind: --check has been there since
this landed and was never listed.

A test pins the marker to one file, so a second copy fails rather than drifts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 11:45:23 +02:00
12646eb5a1 Run the app's Hermes before calling it ready
desktop_hermes_ready decided from a marker file and a text match, while a
hermes the user installed themselves had to answer --version before it counted.
The marker says the app's install once landed, not that it is still there, so a
runtime deleted afterwards left --check reporting success: the default agent
records Hermes, skips the install terminal, and the launch fails.

It now runs the command, on the same 15 second budget the app itself uses. The
path match is a plain string for the same reason it is in the remover -- the
dot in ~/.hermes would otherwise claim a wrapper pointing at ~/xhermes.

foreign_hermes_runs never tested foreignness, only that the command runs, so it
is hermes_runs now and both callers share it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
2026-08-27 11:45:15 +02:00
ba78e7df09 Leave a Hermes the app never installed alone
Remove > AI > Hermes deleted ~/.hermes/hermes-agent, bootstrap-cache, bin and
node unconditionally, plus any wrapper on PATH pointing into ~/.hermes. The
official Hermes installer uses those same paths, so a user who installed the
CLI themselves, then installed the app and never launched it, lost their
checkout, venv and any local changes -- while being told their chats, memories
and skills were safe.

The app provisions its runtime on first launch and writes
.hermes-bootstrap-complete when it lands. Without that marker the app never got
that far and everything under ~/.hermes predates it, so dropping the package is
the whole job.

Two smaller things in the same path. The wrapper test matched ~/.hermes as a
pattern, and the dot made it claim a wrapper pointing at a sibling like
~/xhermes; it is a plain string now, and a symlink there is the user's
arrangement rather than something to delete. And -u, so an unset HOME is an
error instead of a set of rm -rf paths rooted at /.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
2026-08-27 11:44:39 +02:00
OmarchybotandCodex XHigh ea6ee9440a Add omarchy-crash-mute to mute and unmute one program
The mute was reachable only as `omarchy-toggle crash-ignore/<program>`, which asks whoever runs it to know the flag layout, to reduce a binary's path to the name the watcher keys on, and to have read the rule that a name climbing out of that directory writes an unrelated toggle. All of that was carried in the skill's prose, which is the wrong place for a rule that has to hold: prose is advice, and the thing being advised about is a name the crashed program chose.

So it is a command now. `omarchy crash mute hyprland` silences that program, `off` lifts it, `toggle` flips it, and no argument lists what is muted. It takes the binary's path as readily as the name and reduces it the way the watcher does, so the `Executable:` line from `coredumpctl` can be handed straight to it; it refuses what is not one component of a name, so it cannot be talked into writing outside its own directory whatever it is given; and it re-reads the flag afterwards and reports what is now true rather than what was asked for. The listing counts only regular files, because that is all the watcher honours -- anything else in there would read as muted while the crashes kept arriving. A leading `--` is consumed so a program named `-h`, which the router would otherwise answer with its own help, can still be muted.

The watcher gained an unrelated fix that this uncovered. Its fields are read with `IFS=$'\t'`, and tab is IFS whitespace, so an empty field collapsed into the next delimiter and shifted every field after it along one: a crash whose comm was empty had a path read as its pid and was discarded as somebody else's. A process can set its comm to nothing, so that was reachable. Empty fields now arrive as a dash like missing ones, and a dash joins the empty and dot cases that fall back to `unknown`.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 11:26:28 +02:00
2f918a75ad Stop the Hermes interpreter pin following the agent into the user's projects
The stub exports UV_PYTHON so mise builds Hermes against 3.13, which Hermes
requires and Arch's Python is past. Exported, it survived the exec into Hermes
itself and reached every command the agent shells out to. Hermes is a coding
agent that runs commands in the user's own repositories, so a `uv venv` or
`uv sync` there resolved 3.13 as well: on a project declaring
requires-python >=3.14, uv warns that the interpreter contradicts it and builds
the venv anyway.

Dropping it at the handover keeps the pin over the install, where it belongs.
mise x resolves the tool it already installed without it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
2026-08-27 10:48:06 +02:00
David Heinemeier HanssonandClaude Opus 5 43d2fffaf0 Keep user setup running when Hermes cannot install
install/user/mise.sh is sourced through run_logged under `bash -eE`, and its
status reaches omarchy-provision-user's `set -euo pipefail`. Every other line
in the file writes a mise stub and cannot fail; omarchy-install-hermes-cli can,
and does whenever hermes-desktop is installed but the app has not been launched
yet -- what a second user on a shared machine meets on their first login.

The rest of provisioning runs after that source: refreshing applications, the
default browser, the mailto handler, the first-install migration markers and
the finalize-user marker. Without the marker the whole step retries and fails
again at every login, and omarchy-provision-first-run calls it with `|| true`,
so nothing surfaces. omarchy-install-ai-hermes and the migration already guard
this call the same way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 10:47:53 +02:00
OmarchybotandCodex XHigh 8d14869689 Let a crash diagnosis mute that program's notifications
A crash that is understood is not a crash that stops: an upstream bug waiting on a release, a program that dumps core every time it exits. The diagnosis explains it once and the toast keeps arriving, and the only answer Omarchy had was Crash Capture, which turns off every program's notifications in order to silence one.

The watcher already resolves a name to dedupe on and announces that same name in the toast, so the mute is keyed on it: a flag file under toggles/crash-ignore/, written by the existing omarchy-toggle and read by the existing omarchy-toggle-enabled. One flag per name rather than one list, so `on` mutes, `off` un-mutes, and `ls -A` shows what is muted, with no new file format and nothing to parse. It is the executable's basename wherever one was recorded, falling back to the process name, which the kernel truncates to fifteen characters -- muting the truncated form would match nothing, forever, while looking like it worked.

The name is not always a name, though, and the mute turns it into a path. A program picks its own comm and prctl takes anything, including slashes, and the watcher falls back to comm whenever a crash carries no absolute executable. So it is stripped to its last component first: without that, `a/../bar-off` is a legal comm aimed at an unrelated Omarchy flag, letting a crashing program suppress its own notification and letting a user who accepted the offered mute hide their bar instead. Stripping does not always leave a component either -- `/` leaves an empty string, which is no kind of array subscript and no kind of toast, and `.` or `..` names a directory that omarchy-toggle would touch and report success on, leaving a mute that never matches. Both fall back to `unknown`, the word omarchy-agent-crash already uses for a name it does not have, and which mutes like any other.

The skill offers this at the end of a diagnosis and never runs it unprompted, which makes it the single change a diagnosis may make to a system it otherwise only reads. It tells the agent to use the name it was handed rather than re-derive one, since the watcher resolved that name already and the two agree for ordinary names and not for strange ones; a diagnosis started by hand from `omarchy agent crash <pid>` is given no name and gets the derivation instead. It also says to treat the name as hostile text rather than as a word -- it is whatever the crashed program's author called a file, so a single quote inside one closes the quotes around it and the rest runs as the shell -- and to check the flag arrived rather than assume it.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-27 10:32:10 +02:00
Luke Parke eb7ecd13f3 Keep Ori interactive when launched with a prompt (#8455) 2026-08-27 09:21:07 +02:00
Spencer Bull 5909210cb3 Address Hermes review feedback 2026-08-27 01:36:26 -05:00
Spencer Bull d56c1ba972 Harden Hermes wrapper ownership 2026-08-27 01:09:45 -05:00
Taksh 877f1e96ef Keep web app launchers on http(s)
Chromium --app= will run javascript:, file:, and data: URLs. Prefix
schemeless input with https as before, then refuse anything else.
2026-08-27 07:17:44 +05:30