heron
CLAUDE.md1 starsChanged 56 days agoMITView on GitHub
Cross-platform menu bar / system tray app that watches your Claude Code CLI sessions: how many are running, which one is working / idle / waiting for you, start a new session in any folder, resume a past one, and get a native notification when Claude needs permission or finishes. Everything stays on the machine — there is no network code in this repository at all. Tauri v2 (Rust core, native webview) + SvelteKit static / Svelte 5 runes /…
We split this CLAUDE.md into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 109
AppStatelocks: Never hold the parking_lot::Mutex while calling into Tauri (emit, window APIs).
≈ “Common” is an estimate: at least 1 in 5 of the 25,680 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Heron
Cross-platform menu bar / system tray app that watches your Claude Code CLI sessions: how many are running, which one is working / idle / waiting for you, start a new session in any folder, resume a past one, and get a native notification when Claude needs permission or finishes. Everything stays on the machine — there is no network code in this repository at all.
Stack
Tauri v2 (Rust core, native webview) + SvelteKit static / Svelte 5 runes / TypeScript. Plain CSS with design tokens, no UI kit. Targets macOS 12+, Windows 10/11, Linux. Unsigned local builds; no Apple developer identity needed.
Commands
yarn install # once
yarn tauri dev # dev app with hot reload (tray appears)
cd src-tauri && cargo check && cargo test && cargo clippy -- -D warnings && cargo fmt
yarn run check # svelte-check (NOT `yarn check`, see below)
yarn prettier -w src # format frontend
yarn tauri build # release bundle → src-tauri/target/release/bundle/Layout
src-tauri/src/
lib.rs Tauri builder: plugins, setup (tray, state, panel), window events
main.rs entry
model.rs shared types (Session, HookEvent, Snapshot, TerminalApp…) — mirrored in src/lib/types.ts
settings.rs Settings + SettingsStore (JSON in app-data dir)
state.rs AppState hub: registry poll, hook watcher, history refresh, actions, publish()
commands.rs #[tauri::command] IPC surface (thin)
tray.rs tray icon, count, menu
windows.rs popover / panel / settings window behaviour and placement
claude/ paths.rs (per-OS ~/.claude), registry.rs (live sessions), transcripts.rs (history + titles)
hooks/ installer.rs (settings.json), watcher.rs (spool dir), notify.rs
launch/ terminals per OS, launch scripts, focus, find_claude
src/
app.css design tokens (light/dark via light-dark())
lib/api.ts the only file that talks to Tauri
lib/stores.svelte.ts runes store fed by the `snapshot` event
lib/types.ts TS mirror of model.rs / settings.rs
lib/components/ shared UI
routes/popover, routes/panel, routes/settings one route per window
docs/ARCHITECTURE.md data formats Heron reads · docs/HOOKS.md hook payloads · docs/PRIVACY.mdModules talk only through model.rs, settings.rs and state.rs. Read the
//! contract at the top of a file before changing its behaviour.
Rules (auto-loaded from .claude/rules/)
privacy-and-security.md— no network, read-only on~/.claude, never*.key, never persist prompt text, no shell strings, minimal capabilities.rust.md— lenient JSON parsing, ms timestamps, head-only transcripts, never hold a mutex across Tauri calls, cfg for all three OSes.frontend.md— Svelte 5 runes only,api.tsis the IPC boundary, tokens.ui.md— the design language.testing-and-verification.md,git-and-workflow.md.
Skills (.claude/skills/)
Project: heron-build, heron-claude-data, heron-tray-windows.
Imported (see THIRD-PARTY-LICENSES.md): rust-engineer, typescript-pro,
secure-code-guardian, code-reviewer, test-master, svelte5-init,
svelte5-review, frontend-design, tauri, tauri-app-system-tray,
tauri-window, tauri-app-notification, tauri-security, tauri-build,
tauri-app-positioner, tauri-app-autostart. Load the relevant ones before
non-trivial work in that area.
Agents (.claude/agents/)
rust-reviewer, security-auditor, ui-polisher, app-tester. Workflow
review-changes (.claude/workflows/) runs a four-dimension review with
adversarial verification.
Hooks (.claude/settings.json)
SessionStart → repo state. PreToolUse(Bash) → blocks damage to ~/.claude,
.key reads, publishing, force-push. PostToolUse(Edit/Write) → rustfmt /
prettier. Stop → refuses to end the turn while cargo check or svelte-check fail.
Things that will bite you
Each of these cost real debugging. They are the reason this section exists.
- Monitor coordinates. macOS lays the desktop out in points but reports each
monitor's origin in that monitor's own pixels. On a mixed-DPI desk (2x built-in
beside a 1x external) the physical rectangles overlap: 0..3024 and
1512..3432. Placing a window by them puts it on the wrong screen or half on
each.
windows::monitor_infosnormalises every monitor by its own scale, so everything downstream is in points andMonitorInfo::scaleis 1.0.device_scalekeeps the real factor, used only to read raw platform rects. - Which screen's menu bar was clicked. The tray rect arrives in the pixels of
that screen, and position alone cannot tell the screens apart. The icon's
height can: divided by the right scale it matches that screen's menu bar
inset. See
placement::tray_monitor. yarn run check, neveryarn check. Yarn 1 has a built-incheckthat silently shadows the script and exits 0 without running svelte-check.- Notifications need the bundle.
tauri-plugin-notificationattributes banners to Terminal.app in a dev build and discards the click response, so macOS notifications go throughmac-notification-sysdirectly. Test them fromHeron.app, neveryarn tauri dev. - The hook keeps firing when Heron is not running. What it spools is the CLI's raw payload, prompt text included. Unread files are discarded after ten minutes and the spool is removed on uninstall. Do not weaken that.
AppStatelocks. Never hold theparking_lot::Mutexwhile calling into Tauri (emit, window APIs). Clone what you need and drop the guard first.
Security scanners
scripts/scan-supply-chain.py (this repo, every remote branch) and
scripts/scan-machine.py (any folder) look for dropper signatures, fonts whose
bytes are not fonts, and any network code, since "Heron has none" is the
central claim. Both run in CI on push and daily. Both skip themselves, because
they quote the signatures verbatim.
Verifying for real
yarn tauri dev, run claude in a terminal folder → it shows in the
popover within 2 s; quit → gone within 2 s. Install hooks from Settings →
Hooks, then trigger a permission prompt in a session → notification.
In this repository24 other files it gives its agents.
- ai-video-generationSkill
- claude-md-improverSkill
- code-reviewerSkill
- frontend-designSkill
- heron-buildSkill
- heron-claude-dataSkill
- heron-tray-windowsSkill
- minimalist-uiSkill
- product-launch-videoSkill
- rust-engineerSkill
- secure-code-guardianSkill
- seo-auditSkill
- svelte5-initSkill
- svelte5-reviewSkill
- tauri-app-autostartSkill
- tauri-app-notificationSkill
- tauri-app-positionerSkill
- tauri-app-system-traySkill
- tauri-buildSkill
- tauri-securitySkill
- tauriSkill
- tauri-windowSkill
- test-masterSkill
- typescript-proSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

