Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .surface
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ hey search filters
hey seen
hey setup
hey setup omarchy
hey setup omarchy --no-notify
hey setup omarchy --notify
hey setup omarchy --remove
hey skill
hey skill install
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ read from `~/.local/state/omarchy/current/theme/`, and restyles live when you ru
```bash
yay -S hey-cli # hey-cli is on the AUR
hey setup omarchy # install into the desktop
hey setup omarchy --notify # also toast new Imbox mail (--no-notify turns it off)
hey setup omarchy --remove # take it all out again
```

Expand All @@ -361,7 +362,12 @@ indicator that lights when the Imbox has unread mail (no count, by design), and
`hey.toml.tpl` theme template so theme authors can tune the overlay. It prints the
`bindings.lua` snippet for a keybinding rather than editing your file. Omarchy's shipped
HEY web app, its SUPER+SHIFT+E binding and the mailto handler are left untouched.
See [docs/omarchy.md](docs/omarchy.md) for the details and what is planned next.

`--notify` turns on new-mail toasts, off by default: the bar indicator's poll also sends
at most one notification per interval — `Sender — Subject` for one new thread, `N new in
Imbox` for more — replacing the previous toast rather than stacking, and clicking it
focuses the TUI. Omarchy's notification silencing (SUPER+CTRL+comma) mutes them like any
other app. See [docs/omarchy.md](docs/omarchy.md) for the details and what is planned next.

## Agent Skill

Expand Down
65 changes: 56 additions & 9 deletions docs/omarchy.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ failing step does not stop the others.
|---|---|---|
| Desktop entry | `~/.local/share/applications/HEY TUI.desktop` | Distinct from Omarchy's shipped `HEY.desktop` web app. Launches under app-id `org.omarchy.hey` |
| Menu row | marker block in `~/.config/omarchy/extensions/omarchy-menu.jsonc` | one root `HEY` row that focuses or launches the TUI; its guard is a PATH lookup, never network or `hey` itself. Becomes a submenu once there is more than one thing to open |
| Bar indicator | inline command module `hey-unread` in `~/.config/omarchy/shell.json` | runs `hey omarchy bar-status` every 3 minutes; click focuses or launches the TUI |
| Bar indicator | inline command module `hey-unread` in `~/.config/omarchy/shell.json` | runs `hey omarchy bar-status` every 3 minutes; click focuses or launches the TUI. `--notify` / `--no-notify` toggle new-mail toasts by rewriting the module's exec — enablement lives where it acts, no config key |
| Theme template | `~/.config/omarchy/themed/hey.toml.tpl` | renders `hey.toml` into every theme so theme authors can override the overlay; triggers `omarchy-theme-refresh` |
| Keybinding | printed, never written | `o.bind("SUPER + SHIFT + ALT + H", "HEY TUI", "omarchy-launch-or-focus-tui --app-id=org.omarchy.hey hey tui")`; SUPER+SHIFT+E keeps opening the web app unless you `hl.unbind` it. Spelled out rather than `{ tui = "hey tui" }` because the lua helper quotes that into one word and the app-id derived from it would never match |

Expand All @@ -93,6 +93,52 @@ is no place for an error message. Credentials come from the keyring or the
`credentials.json` fallback exactly as for any other command, so it works from the
shell's headless context; token refresh happens in-process.

### New-mail toasts (default off)

`hey setup omarchy --notify` rewrites the bar module's exec to
`hey omarchy bar-status --notify`: the same 3-minute poll that lights the indicator also
diffs the unseen Imbox postings against a fingerprint file
(`~/.local/state/hey-cli/omarchy-poll.json`) and sends **at most one toast per tick** via
`omarchy-notification-send` — sparse notices, never a per-message firehose. One Imbox
fetch serves both the indicator and the toasts.

- **What counts as new**: an unseen posting not fingerprinted yet, or one whose
`visible_entry_count` grew (a new reply on a known thread). Fingerprints avoid
`updated_at` (it churns) and `seen` (it flips on read). Muted threads are fingerprinted
but never toast.
- **First run seeds silently.** No state file means write the fingerprints and toast
nothing — never toast the backlog. The fingerprints carry the identity they were taken
for — server, account filter and the signed-in user's id — so after
`hey accounts use`, a base URL change, or signing in as someone else by any route
(login, logout, `HEY_TOKEN`) the next tick reseeds silently instead of toasting the
other identity's backlog. Re-enabling with `--notify` after a `--no-notify` stretch
drops stale fingerprints for the same reason, and `--remove` keeps them while the bar
module could not actually be removed.
- **The whole unseen set is read when seeding.** HEY sorts Imbox postings unseen-first,
so the poll follows pages while they are all-unseen and stops at the first seen
posting. A seed (first run, or a new identity) reads them all, so no pre-existing
thread can later surface as new; a steady-state tick stops at ten pages, because new
mail always lands on page 1 and older threads are already fingerprinted. The
indicator-only path reads one page. Fingerprints prune to the postings still unseen
once the snapshot is complete; a truncated snapshot (cap reached, a page fetch
failed) keeps absent fingerprints instead.
- **One toast, replaced not stacked.** `Sender — Subject` for one new thread, `N new in
Imbox` with the first few senders for more. The daemon's printed id (`-r <id> -p`, the
`omarchy-display-text-size` pattern) is cached so the next tick replaces the on-screen
toast instead of stacking; a stale id after a shell restart just makes a fresh toast.
- **DND is honored.** The toast passes `--app-name HEY` deliberately: omarchy's default
app-name `omarchy-action` bypasses notification silencing, so identifying as HEY is
what makes SUPER+CTRL+comma mute the toasts (into history) like any other app.
- **Clicking focuses the TUI** via the shared `omarchy-launch-or-focus-tui` exec hint,
which the shell runs itself so it survives shell restarts.
- **Same silence discipline as the bar**: any error — auth, network, a failed send —
produces no output beyond the bar JSON and exits 0. A failed fetch leaves the
fingerprints untouched, and a failed send keeps the undelivered postings out of them
so the toast retries on the next tick.

`hey setup omarchy --no-notify` reverts the exec; a plain re-run leaves it as it is;
`--remove` deletes the state file along with everything else.

## Decisions

- **Indicator, not count.** Pending screener mail is not what people mean by "important",
Expand All @@ -108,19 +154,20 @@ shell's headless context; token refresh happens in-process.

## Follow-ups, in rough order

1. **New-mail toasts** via `omarchy-notification-send --glyph --exec`, default-off,
sharing one poller with the bar so the Imbox is fetched once per interval.
2. **mailto: handler** that opens a floating compose (`hey compose --mailto`), opt-in
1. **mailto: handler** that opens a floating compose (`hey compose --mailto`), opt-in
against the incumbent `omarchy-webapp-handler-hey`.
3. **Agent-triage digests**: `hey --json` feeding a system agent that emits sparse
2. **Agent-triage digests**: `hey --json` feeding a system agent that emits sparse
toasts instead of per-message noise.
4. **Upstream contributions**: a `default/themed/hey.toml.tpl` PR alongside
3. **Upstream contributions**: a `default/themed/hey.toml.tpl` PR alongside
`claude.json.tpl`; an Install-menu TUI row; possibly branching the mailto handler to
the TUI when installed. (An AUR package already ships: `yay -S hey-cli`, published by
the release workflow.)
5. **Shell plugin graduation** for the bar widget: `manifest.json`, a settings panel,
IPC refresh when a thread is archived from the TUI instead of waiting for the next
poll.
4. **Shell plugin graduation** for the bar widget: `manifest.json`, a settings panel,
and event-driven freshness — refreshing the indicator the moment a thread is
archived in the TUI. That needs a real widget plugin: inline `command` modules are
interval-only, with no IPC to force a re-run (`Bar.qml` has no `IpcHandler` and
`omarchy bar` has no refresh verb), which is also why the toasts share the interval
poll rather than pushing.

## Anti-features, recorded

Expand Down
Loading
Loading