diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1b1d7ed..4797a95 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ End-user install paths are documented in [INSTALL.md](INSTALL.md) cargo fmt --all cargo clippy --workspace --all-targets -- -D warnings cargo test --workspace -# optional UI: +# menu bar app: cd apps/microbridge-ui && npm ci && npm run build ``` diff --git a/INSTALL.md b/INSTALL.md index 58928df..4bf0486 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,8 +1,8 @@ # Installing Microbridge -Microbridge is a local daemon plus an optional companion UI. There is **no -cloud account** — install puts binaries on your machine and runs a user-level -service. +Microbridge installs a **menu bar app** (primary UI for the keyboard) plus a +local daemon that drives the Micro. There is **no cloud account** — everything +runs on your machine. ## Recommended on macOS: Homebrew (with updates) @@ -51,8 +51,7 @@ Governance / why this path: [docs/governance.md](docs/governance.md). | Piece | Need | |---|---| | Daemon (Homebrew) | Homebrew; Rust pulled in as a build dependency | -| Daemon (from source) | Rust stable (`rustup`), macOS 13+ or Linux | -| Companion UI (optional) | Node ≥ 20; full `.app` also needs Xcode CLT | +| Full install (from source) | Rust stable, Node ≥ 20; macOS also needs Xcode CLT for the `.app` | | Hardware LEDs | Codex Micro over USB (HID packing still landing — mock works without hardware) | ## From source (developers) @@ -60,21 +59,14 @@ Governance / why this path: [docs/governance.md](docs/governance.md). ```sh git clone https://github.com/DevVig/microbridge.git cd microbridge -./scripts/install.sh # macOS: binaries + launchd -# ./scripts/install.sh --with-ui +./scripts/install.sh # macOS: daemon + menu bar app + launchd +# ./scripts/install.sh --no-ui # daemon/CLI only (headless) # ./scripts/install-linux-systemd.sh -microbridgectl status ``` Uninstall: `./scripts/uninstall.sh` (add `--purge` to remove `~/.microbridge`). -### Optional companion UI - -```sh -./scripts/install.sh --with-ui -# or during development: -cd apps/microbridge-ui && npm install && npm run dev -``` +During UI development: `cd apps/microbridge-ui && npm install && npm run tauri dev`. ## Linux diff --git a/README.md b/README.md index 613698d..14203ae 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The Micro's best feature — bidirectional Agent Keys — currently works throug 1. **Invisible footprint.** Event-driven end to end: no polling loops, no heartbeat timers. Idle CPU is 0.0% and idle RSS targets single-digit megabytes. If Microbridge is noticeable in Activity Monitor, that is a bug — the [footprint budget](docs/architecture.md#footprint-budget) is a spec, not an aspiration. 2. **Zero network.** No telemetry, no update pings, no cloud. The daemon's only I/O is a local Unix socket and the USB device. It links no HTTP client — auditable in `Cargo.lock`. 3. **Rust core, any-language adapters.** The always-resident part is a single static Rust binary. First-party adapters compile into it (in-process, ~zero overhead). Community adapters are separate processes speaking [newline-delimited JSON](docs/protocol.md) — write one in whatever you like. -4. **The UI is optional.** A menu bar companion shows connection status and opens Settings for key remapping; you can quit it and the daemon keeps working. +4. **The menu bar app is the product UI.** Configure keys, lighting, and adapters there. The daemon keeps the hardware alive underneath; `microbridgectl` is a support/debug escape hatch. ## Architecture @@ -61,7 +61,7 @@ The Micro's best feature — bidirectional Agent Keys — currently works throug └──────────────────────┬───────────────────────────┘ │ same socket (status + commands) ┌─────────┴─────────┐ - │ menu bar app │ optional, quit-able (Tauri) + │ menu bar app │ primary UI (Tauri) └───────────────────┘ ``` @@ -74,8 +74,8 @@ crates/mb-protocol wire types (serde) — the protocol's source of truth crates/mb-device device abstraction; mock today, HID packing TBD crates/mb-adapters first-party Codex CLI + Claude Code watchers crates/microbridged the daemon: socket server, registry, focus, key source -crates/microbridgectl inspect a live bus (`status`) -apps/microbridge-ui optional Tauri companion (MagicPath-faithful) +crates/microbridgectl support/debug CLI (`status`) +apps/microbridge-ui menu bar app — primary UI (MagicPath-faithful) adapters/ out-of-process community adapters + reference impl docs/ protocol, architecture, adapter guide, design, HID notes ``` diff --git a/apps/microbridge-ui/README.md b/apps/microbridge-ui/README.md index 0c1e9df..b348ad2 100644 --- a/apps/microbridge-ui/README.md +++ b/apps/microbridge-ui/README.md @@ -1,7 +1,8 @@ # microbridge-ui -Optional Tauri 2 companion for Microbridge. **Status + setup only** — agent -actions stay on the physical Codex Micro. +Primary Microbridge UI (Tauri 2 menu bar app). **Status + setup** for the +keyboard — agent actions (approve / reject / interrupt) stay on the physical +Codex Micro. MagicPath mockups remain the visual go-to: diff --git a/docs/architecture.md b/docs/architecture.md index 798b896..2ea0500 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -7,7 +7,7 @@ | `microbridged` | resident daemon (launchd agent) | Rust | yes | | First-party adapters (Codex CLI, Claude Code) | in-process modules of the daemon | Rust | bundled | | Community adapters | separate processes on the socket | any | optional | -| Menu bar app | tray app talking to the same socket | Tauri 2 + React (`apps/microbridge-ui`) | optional, quit-able | +| Menu bar app | primary UI (tray + settings + focus HUD) | Tauri 2 + React (`apps/microbridge-ui`) | yes (default install) | The daemon owns three things: the **status bus** (session registry fed by adapters), the **focus policy** (which session owns the deck), and the diff --git a/docs/design/README.md b/docs/design/README.md index 5a604cb..6b0366b 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -1,8 +1,8 @@ # UI design -The interface direction for Microbridge's optional UI surfaces. **MagicPath -interactive mockups are the go-to reference** for M3 implementation; this -document describes what they show and why. +The menu bar app is the **primary** way people deal with the keyboard. +**MagicPath interactive mockups are the go-to reference**; this document +describes what they show and why. ## Lean companion principle @@ -138,10 +138,17 @@ Keyboard setup. Four sections in a left rail: ### 3. Focus HUD — [interactive mockup](https://api.magicpath.ai/v1/sunnily-shadow-8075) -A transient, **non-interactive** frosted overlay confirming deck ownership -when focus changes: app badge, app name, thread title, state chip, a -six-key echo of miniature frosted caps with the focused key lit, -press-behavior hint, and a 2px drain bar (~2.5s). No buttons on the HUD card. +A transient, **non-interactive** frosted overlay confirming **deck focus** — +which single thread currently owns Approve / Reject / dial / command keys. + +**When it appears (you don’t open it):** whenever the daemon’s focused +session changes, for about 2.5 seconds — for example after you press an +Agent Key, an approval preempts another thread, or auto-follow moves the +deck to another app. It is a glanceable confirmation, not a settings +screen. No buttons on the HUD card. + +Contents: app badge, app name, thread title, state chip, a six-key echo +with the focused key lit, press-behavior hint, and a 2px drain bar. ## Interaction rules @@ -157,8 +164,8 @@ press-behavior hint, and a 2px drain bar (~2.5s). No buttons on the HUD card. - **Approvals are privileged on the deck**, not in the popover. An `awaiting_approval` thread may temporarily claim the approve/reject keys (user-toggleable in Settings → Agent Keys). -- The UI processes are optional; quitting them changes nothing about the - daemon's behavior. +- Quitting the menu bar app does not stop the daemon or LEDs; you lose + status/setup chrome until you reopen it. ## Assets diff --git a/scripts/install.sh b/scripts/install.sh index 63b73ff..fcf00c2 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,19 +1,20 @@ #!/usr/bin/env bash -# Unified Microbridge installer (daemon + optional UI). +# Unified Microbridge installer — daemon + menu bar app (default). set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" BIN_DIR="${MICROBRIDGE_BIN:-$HOME/.local/bin}" -WITH_UI=0 +WITH_UI=1 WITH_LAUNCHD=1 LABEL="ai.microbridge.daemon" +UI_LABEL="ai.microbridge.ui" usage() { cat < Companion UI" + echo "==> Menu bar app (primary UI)" need npm ( cd "$ROOT/apps/microbridge-ui" npm ci npm run build - if command -v cargo >/dev/null && [[ -d src-tauri ]]; then - if npm run tauri build; then - echo " Tauri app built under apps/microbridge-ui/src-tauri/target/release/bundle/" + if npm run tauri build; then + APP_SRC="$(find "$ROOT/apps/microbridge-ui/src-tauri/target/release/bundle" -name 'Microbridge.app' -type d 2>/dev/null | head -n1 || true)" + if [[ -n "$APP_SRC" && "$(uname -s)" == "Darwin" ]]; then + rm -rf "$HOME/Applications/Microbridge.app" + mkdir -p "$HOME/Applications" + cp -R "$APP_SRC" "$HOME/Applications/Microbridge.app" + echo " installed ~/Applications/Microbridge.app" + if [[ "$WITH_LAUNCHD" -eq 1 ]]; then + UI_PLIST="$HOME/Library/LaunchAgents/${UI_LABEL}.plist" + cat >"$UI_PLIST" < + + + + Label + ${UI_LABEL} + ProgramArguments + + ${HOME}/Applications/Microbridge.app/Contents/MacOS/microbridge-ui + + RunAtLoad + + KeepAlive + + + +EOF + launchctl bootout "gui/$(id -u)/${UI_LABEL}" 2>/dev/null || true + launchctl bootstrap "gui/$(id -u)" "$UI_PLIST" + launchctl enable "gui/$(id -u)/${UI_LABEL}" + launchctl kickstart -k "gui/$(id -u)/${UI_LABEL}" 2>/dev/null || open "$HOME/Applications/Microbridge.app" + echo " menu bar app set to launch at login" + else + open "$HOME/Applications/Microbridge.app" 2>/dev/null || true + fi else - echo " note: Tauri bundle skipped/failed — web build is in apps/microbridge-ui/dist" - echo " run: cd apps/microbridge-ui && npm run dev" + echo " note: .app bundle not found — web build is in apps/microbridge-ui/dist" + echo " run: cd apps/microbridge-ui && npm run tauri dev" fi + else + echo " note: Tauri bundle failed — web build is in apps/microbridge-ui/dist" + echo " run: cd apps/microbridge-ui && npm run tauri dev" fi ) fi echo "" echo "Microbridge installed." +echo " UI: ~/Applications/Microbridge.app (menu bar)" echo " status: $BIN_DIR/microbridgectl status" echo " logs: ~/.microbridge/daemon.log" echo " config: ~/.microbridge/config.toml" diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index ca1d3c5..73ebef5 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -4,6 +4,7 @@ set -euo pipefail BIN_DIR="${MICROBRIDGE_BIN:-$HOME/.local/bin}" LABEL="ai.microbridge.daemon" +UI_LABEL="ai.microbridge.ui" PURGE=0 usage() { @@ -23,9 +24,15 @@ while [[ $# -gt 0 ]]; do done if [[ "$(uname -s)" == "Darwin" ]]; then - echo "==> Stopping launchd agent" + echo "==> Stopping launchd agents" launchctl bootout "gui/$(id -u)/${LABEL}" 2>/dev/null || true + launchctl bootout "gui/$(id -u)/${UI_LABEL}" 2>/dev/null || true rm -f "$HOME/Library/LaunchAgents/${LABEL}.plist" + rm -f "$HOME/Library/LaunchAgents/${UI_LABEL}.plist" + if [[ -d "$HOME/Applications/Microbridge.app" ]]; then + echo "==> Removing menu bar app" + rm -rf "$HOME/Applications/Microbridge.app" + fi fi if [[ -f "$HOME/.config/systemd/user/microbridge.service" ]]; then