# HANDOFF — understatus
> Handoff doc for a fresh agent/session. Product was originally codenamed **statusticon** and renamed to **understatus** before publishing. The on-disk project directory is still `statusticon/` but the product/crate/repo/binary are all **understatus**.
## Goal
A **calm, unobtrusive macOS statusline addon** for AI coding CLIs (primarily Claude Code). It renders one line at the bottom of the terminal showing live system + AI-session info, designed to sit there permanently **without drawing attention**. Publicly published; **v0.2.0 is live on all 4 channels.**
## ⚠️ Read this FIRST — local toolchain is broken
**The Homebrew `rustc`/`cargo` on PATH are broken** on this machine: `/opt/homebrew/bin/rustc` links to a missing `/opt/homebrew/opt/llvm/lib/libLLVM.dylib`, so bare `cargo`/`rustc`/`clippy`/`rust-analyzer` fail (dyld error; sometimes a misleading exit 0). `/opt/homebrew/bin` is ahead of `~/.cargo/bin` in PATH, so **bare `cargo` resolves to the broken one.**
**Always use the rustup toolchain** for build/test/clippy:
```bash
export PATH="$HOME/.cargo/bin:$PATH" # ~/.cargo/bin/cargo = stable-aarch64, works
```
- **rust-analyzer also uses the broken homebrew toolchain** → it emits **garbage diagnostics** (phantom E0308, `None` flagged as non-snake-case). **Ignore IDE diagnostics; trust only rustup `cargo`/`clippy` output.**
- Recover homebrew rust with `brew reinstall rust` or `brew link llvm` (system change — ask the user first).
- x86_64 cross-compile still fails locally — use CI (macos-14). Native arm64 build/test via rustup is fine.
## Key Facts / Coordinates
- **GitHub (public):** https://github.com/ictechgy/understatus — default branch `main`, account `ictechgy` (gh CLI authed).
- **Homebrew tap repo:** https://github.com/ictechgy/homebrew-understatus (`Formula/understatus.rb`, builds from source).
- **Local project dir:** `/Users/jinhongan/Desktop/status_ticon/statusticon` (dir name is legacy; product = understatus).
- **Design specs:** `.omc/plans/statusticon.md` (v1 design), `.omc/plans/themes-and-interval.md` + `.omc/plans/session-cache-isolation.md` (v0.2.0 ralplan consensus plans), `docs/superpowers/specs/2026-06-03-themes-and-interval-design.md` (v0.2.0 design spec, committed). `.omc/` is gitignored.
- **Open Design artifacts:** project `status_ticon` → `statusticon-design.html` (v1 calm lab) + `understatus-themes.html` (v0.2.0 theme gallery, 5 themes × 5 load bands).
- **Language/platform:** Rust 2021, **macOS only** (Apple Silicon + Intel). build.rs links IOKit + CoreFoundation frameworks.
### Published channels (ALL LIVE at v0.2.0, verified)
| Channel | Version | Install |
|---|---|---|
| crates.io | 0.2.0 | `cargo install understatus` |
| Homebrew | 0.2.0 | `brew install ictechgy/understatus/understatus` |
| npm | 0.2.0 (`latest`) | `npm install -g understatus` |
| GitHub Release | v0.2.0 (arm64 + x64 tarballs + .sha256) | — |
> **Versions now aligned.** Unlike v0.1.x (where npm wrapper was 0.1.1 but binary 0.1.0), **everything is 0.2.0**: `Cargo.toml`, `npm/package.json`, and the binary-download pin `npm/install.js` (`const VERSION = '0.2.0'`). When cutting a new release, bump all three together.
### ⏳ Pending manual step (needs npm passkey — agent can't do it)
`npm deprecate understatus@0.1.0` is **not yet done** — npm requires browser passkey auth (EOTP) which an agent can't complete. Run it yourself:
```bash
npm deprecate understatus@0.1.0 "broken launcher; use >=0.1.1 (latest 0.2.0)"
```
(`latest` already points to 0.2.0, so new installs are fine regardless.)
### Currently INSTALLED on this machine
`~/.claude/settings.json` → `statusLine.command` = `…/target/release/understatus` (dev build, now 0.2.0), `refreshInterval: 5`. The pre-existing OMC HUD (`node $HOME/.claude/hud/lterm-omc-hud.mjs`) is preserved as `chain_command` in `~/.config/understatus/config.toml` and chained. Backup at `~/.claude/settings.json.understatus.bak`. `understatus uninstall` restores exactly.
## Current Progress
- **v0.2.0 shipped.** **161 tests passing** (rustup), clippy `-D warnings` clean, release build green, CI green on `main`.
- Git: on `main`, latest commit `d0bed83`. v0.2.0 commits (rebased, atomic): `fix(security)` → `feat` → `docs` → 2× `fix` (quad-review) → `style: cargo fmt` → `chore(release): v0.2.0` → `chore(homebrew)`.
### v0.2.0 features / fixes
- **Themes (5):** `src/themes.rs` (new) — `calm`(default)/`mono`/`vivid`/`ember`/`emoji` presets. config.toml `theme = "name"` (name-reference); resolution priority **user key > preset > calm**. Downstream `render.rs`/`theme.rs` **unchanged** (fields stay concrete; `config.rs::apply_theme` fills only unset theme keys via `toml::Value` has_key). COLOR-ONCE + ≥90% crit breath preserved. Commands: `understatus theme <name>` (switch), `understatus theme` (show current), `understatus themes` (list).
- **Install-time interval:** `understatus install [--interval N] [--theme NAME] [--yes]` — TTY prompts for omitted items, non-TTY/`--yes` uses flags/defaults (default 5). Reinstall **inherits** existing `interval_seconds` (flag > existing > 5). Breath-invariant warning (`pulse_period/interval ≥ 6`) using the user's actual config.
- **Session cache isolation (bug fix):** `chain_output`/`pulse_state`/`net_counters` keyed by sanitized `session_id` (`~/Library/Caches/understatus/sessions/<key>/`). Fixes cross-terminal value bleed (another terminal's OMC HUD value, e.g. ctx 85%, leaking into the chained segment). `battery` stays machine-global. `sanitize_session_key`: allowlist `[A-Za-z0-9_-]` + 64-char cap + `default`/`default-<hash>` fallback + FNV-1a (deterministic) collision hash; path re-sanitized at assembly (release-safe, traversal-blocked).
- **Security:** `claude.rs::read_branch_from_git_dir` validates stdin `workspace.git_worktree` (`..` rejection + `canonicalize` symlink check).
## What Worked
- **ralplan consensus planning** (Planner→Architect→Critic) for BOTH the themes/interval feature (5 rounds → APPROVE) and the cache bug fix (3 rounds → APPROVE). Plans in `.omc/plans/`.
- **Multi-agent execution + layered review:** team(executor) sequential build (cache fix → themes → security/docs, sequenced because all touch `main.rs`), then verifier + code-reviewer + security-reviewer + fix loop.
- **quad-review-loop on PR #1** (Claude+Codex+Forge tracks): Round 1 found **4 consensus HIGH blockers** — (A) install wrote settings.json before config.toml (partial-install risk), (B) `existing_interval` `i64 as u64` negative-wrap/0, (C) `sanitize_session_key` non-empty all-disallowed → shared `"default"`, (D) section setters silent no-op on non-table. All fixed; Round 2 = 0 blockers (converged). Antigravity(agy) skipped (8KB prompt limit); Forge flaky on >100KB prompts.
- **`cargo fmt --check` is a CI gate** — the pre-existing code (incl render.rs/theme.rs) was never rustfmt-clean, so CI failed on first push. Fixed with one `style: cargo fmt` commit (formatting-only; behavior identical).
- **Local npm E2E before publish** (`npm install ./npm --prefix /tmp/...`) confirmed install.js downloads the v0.2.0 binary and the launcher reports 0.2.0 — do this every npm change.
- Used **rustup `~/.cargo/bin/cargo`** throughout (homebrew rust broken).
## What Didn't Work / Gotchas (don't repeat)
- **Bare `cargo`/`rustc` are broken** (see top section). Always `export PATH="$HOME/.cargo/bin:$PATH"`.
- **rust-analyzer emits phantom errors** off the broken toolchain — ignore; trust rustup cargo/clippy.
- **`npm publish` / `npm deprecate` need browser passkey (EOTP)** — an agent cannot complete them; hand off to the user (run via terminal). `npm whoami` working ≠ publish auth.
- **`cargo publish` worked autonomously** (`~/.cargo/bin/credentials.toml` token present). Used `--allow-dirty` (untracked `.serena/`, `HANDOFF.md` aren't in the package per Cargo.toml `exclude`/git rules).
- **GitHub REST secondary rate limits** still bite during bursts — `gh api rate_limit` is exempt; space out calls or `git push`/`curl`.
- **`x86_64` cross-compile fails locally** — CI on macos-14 only (release.yml builds both targets there).
## Next Steps (all optional — product is fully shipped at v0.2.0)
1. **(Pending) Deprecate npm 0.1.0** — see command above (needs your passkey).
2. **Non-blocker follow-ups surfaced by review** (deferred by consensus or single-track):
- Session cache **GC**: `sessions/<id>/` dirs accumulate until `uninstall` (which removes the whole cache root). ralplan deliberately deferred runtime GC (hot-path cost). If accumulation is ever a problem, add an `install`-time sweep.
- Install **full atomicity** (MEDIUM): config.toml is written before settings.json (dangerous case fixed), but a settings.json write failure still leaves config.toml mutated. Self-healing on next install. Temp-file + restore would close it.
- config **dotted-key** test (LOW): `apply_theme` handles `color.band_tints = [...]` correctly but no regression test pins it.
- `theme emoji` UX (LOW): glyphs are 2-cell wide; could print a one-line notice.
3. **(Optional) `RELEASING.md`** documenting the multi-channel flow (below).
4. **P4 (optional):** extract `CliAdapter` + Gemini/Codex stub adapters. **Blocked upstream** — neither exposes a custom-command statusline yet. Also: a real "bold/flashy" pulse style (`pulse_style="bold"` is currently a no-op; all themes use the calm brightness breath) — toward the "more eye-catching themes" the user wants next.
### Future release process (for v0.2.x+)
1. Bump **all three** versions: `Cargo.toml`, `npm/package.json`, and `npm/install.js` `VERSION` pin. Commit on a branch → PR to `main` (version bump itself is a trivial release chore and may go straight to main).
2. `git tag vX.Y.Z && git push origin vX.Y.Z` → `release.yml` builds arm64+x64 on macos-14, attaches tarballs+sha256 to the GitHub Release.
3. `cargo publish` (crates.io; token present, `--allow-dirty` ok). **IRREVERSIBLE** — versions can't be re-published.
4. Update `homebrew-understatus` `Formula/understatus.rb`: bump `url` to the new tag + recompute source sha256 (`curl -L <archive-url> | shasum -a 256`). Keep repo's `homebrew/understatus.rb` copy in sync.
5. npm: local `npm install ./npm --prefix /tmp/test` E2E first, then **you** run `npm publish ./npm --access public` (passkey browser auth).
## Verify current state quickly
```bash
cd /Users/jinhongan/Desktop/status_ticon/statusticon
export PATH="$HOME/.cargo/bin:$PATH" # MUST — homebrew cargo is broken
cargo test # 161 passing
cargo clippy --all-targets -- -D warnings # clean
cargo build --release # green
COLORTERM=truecolor ./target/release/understatus < tests/fixtures/claude_full.json | cat -v
# theme preview: UNDERSTATUS_CONFIG=<tmp with theme="vivid"> ./target/release/understatus < tests/fixtures/claude_full.json | cat -v
npm view understatus version # 0.2.0
```