Skip to content

feat: ship v0.1.0 production readiness (prebuilt brew + privacy) - #31

Merged
DevVig merged 1 commit into
mainfrom
feat/production-readiness-v0.1.0
Jul 18, 2026
Merged

DevVig merged 1 commit into
mainfrom
feat/production-readiness-v0.1.0

Conversation

@DevVig

@DevVig DevVig commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Homebrew formula installs prebuilt daemon + UI release archives; bump-formula.sh hashes the same URLs brew fetches
  • OSS hardening: PRIVACY.md, tighter SECURITY.md, Unix socket/dir 0600/0700
  • Version bump to 0.1.0; README/INSTALL honesty (HID after Jul 22); Linux aarch64 gated in release installer
  • UI: Simulator/Detected/Demo chip honesty; Cursor/T3 marked scaffold-only
  • Tracking: GitHub milestones Phase A/B (Public repo + release hygiene (v0.1.0) #19Hardware release v0.2.0 after bidirectional Micro path #30) — Linear MCP unavailable; see docs/project-tracking.md

Closes #19, #21, #22, #23, #25, #26 (partially #20/#24 remain for tag smoke + action bridge).

Test plan

  • CI green
  • Make repo public after merge
  • Tag v0.1.0 and babysit Release (signed DMGs)
  • Merge formula bump PR (fills sha256)
  • Anonymous brew tap / brew install smoke

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added privacy documentation describing local-only operation, data storage, and network behavior.
    • Homebrew installation now uses prebuilt release binaries and includes the menu bar app.
    • Improved connection-status messaging for simulator, detected-device, and disconnected states.
    • Added stronger local socket security protections.
  • Documentation

    • Updated release, installation, security, architecture, and contribution guidance for version 0.1.0.
    • Clarified hardware LED and key behavior and documented project tracking.
  • Bug Fixes

    • Linux ARM64 release installation now exits with a clear unsupported-platform message.

Switch Homebrew to prebuilt release assets, fix formula bump checksums,
enforce socket 0600, add PRIVACY.md, bump to 0.1.0, and harden install
docs/UI honesty ahead of public launch. HID remains post-Jul-22.
Copilot AI review requested due to automatic review settings July 18, 2026 12:03
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR prepares the v0.1.0 release, changes Homebrew to install prebuilt macOS artifacts, updates UI demo and device-state handling, tightens daemon socket permissions, and expands privacy, security, installation, and project documentation.

Changes

Release distribution and versioning

Layer / File(s) Summary
Version metadata alignment
Cargo.toml, apps/microbridge-ui/package.json, apps/microbridge-ui/src-tauri/*
Project and UI versions are bumped to 0.1.0.
Prebuilt release packaging
Formula/microbridge.rb, scripts/bump-formula.sh
Homebrew and formula automation use architecture-specific prebuilt daemon and UI archives with SHA-256 values.
Release installation guidance
.github/ISSUE_TEMPLATE/bug_report.yml, CONTRIBUTING.md, INSTALL.md, docs/governance.md, scripts/install-from-release.sh
Release examples and Homebrew guidance are updated, and Linux ARM64 release installation now fails with a source-build hint.

UI device-state presentation

Layer / File(s) Summary
Browser demo snapshot identity
apps/microbridge-ui/src/lib/bus.ts
The browser demo uses an unconnected demo-browser snapshot and dedicated detection logic.
Connection status rendering
apps/microbridge-ui/src/surfaces/Popover.tsx
Popover labels, tones, helper text, and disconnected messaging now distinguish demo, simulator, detected, and HID-unclaimed states.
Adapter status copy
apps/microbridge-ui/src/surfaces/Settings.tsx
Cursor and T3 Code entries are marked scaffold-only and not production-ready.

Local control, security, and project policy

Layer / File(s) Summary
Private daemon socket
crates/microbridged/src/socket.rs, PRIVACY.md, SECURITY.md
Socket directory and file permissions are tightened, while local data and security boundaries are documented.
Daemon behavior documentation
crates/microbridged/src/{frontmost.rs,registry.rs,state.rs}, docs/architecture.md
Action acknowledgments, focus tracking, auto-follow, and macOS polling behavior are clarified.
Project status and tracking
README.md, docs/project-tracking.md
Public-alpha status, HID timing, project phases, and milestone tracking guidance are added or updated.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: copilot

Poem

A rabbit tags the release with cheer,
“v0.1.0 is hopping here!”
Prebuilt crates and sockets tight,
Demo LEDs glow soft and bright.
Local paths, no clouds in sight—
Hop, ship, and nibble through the night!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 70.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The version bumps satisfy part of #19, but repo-public status and tagging from main cannot be verified from the provided changes. Provide evidence for the repository visibility change and the release tag creation from main, or include those changes in the PR context.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the release-prep focus and the main changes: v0.1.0, prebuilt Homebrew, and privacy/security updates.
Out of Scope Changes check ✅ Passed The changes align with the release-prep objectives and do not show unrelated or out-of-scope additions.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@DevVig
DevVig merged commit 14ba7d7 into main Jul 18, 2026
7 of 8 checks passed
@DevVig
DevVig deleted the feat/production-readiness-v0.1.0 branch July 18, 2026 12:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/microbridged/src/frontmost.rs`:
- Around line 4-7: Update Registry::resolve_focus so it evaluates frontmost_app
and switches to the new application’s session when focus changes, rather than
returning early solely because the current focus still exists; ensure
set_frontmost_app triggers this behavior and add a regression test covering live
application switching. If live switching cannot be implemented, revise the
frontmost.rs documentation to state that auto-follow is currently limited.

In `@crates/microbridged/src/socket.rs`:
- Around line 19-24: Update the parent-directory permission setup in the socket
initialization flow to propagate errors from std::fs::set_permissions instead of
ignoring them. Ensure failure to apply mode 0700 returns before remove_file or
UnixListener::bind proceeds, while preserving the existing socket mode handling.

In `@docs/architecture.md`:
- Around line 44-46: Update the Auto-follow description in the architecture
documentation to accurately state that the watcher polls NSWorkspace every 400ms
to identify the frontmost app. Remove the claim that it is event-driven and not
polled, and note that NSWorkspace notifications are planned future work.

In `@Formula/microbridge.rb`:
- Around line 52-55: Update post_install to write the .microbridge-brew
ownership marker beside the installed Microbridge.app rather than inside its
signed bundle. Keep the resource("ui").stage installation flow and app path
unchanged, and ensure any marker path references use the external location
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f4334359-d06b-45e4-9163-2f557a63a5b2

📥 Commits

Reviewing files that changed from the base of the PR and between 21a8b2f and 9eb058a.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • apps/microbridge-ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (23)
  • .github/ISSUE_TEMPLATE/bug_report.yml
  • CONTRIBUTING.md
  • Cargo.toml
  • Formula/microbridge.rb
  • INSTALL.md
  • PRIVACY.md
  • README.md
  • SECURITY.md
  • apps/microbridge-ui/package.json
  • apps/microbridge-ui/src-tauri/Cargo.toml
  • apps/microbridge-ui/src-tauri/tauri.conf.json
  • apps/microbridge-ui/src/lib/bus.ts
  • apps/microbridge-ui/src/surfaces/Popover.tsx
  • apps/microbridge-ui/src/surfaces/Settings.tsx
  • crates/microbridged/src/frontmost.rs
  • crates/microbridged/src/registry.rs
  • crates/microbridged/src/socket.rs
  • crates/microbridged/src/state.rs
  • docs/architecture.md
  • docs/governance.md
  • docs/project-tracking.md
  • scripts/bump-formula.sh
  • scripts/install-from-release.sh

Comment on lines +77 to +98
const demo = snapshot.device_name === "demo-browser";
const simulator = snapshot.device_name === "mock" || demo;
const detected =
!snapshot.device_connected && snapshot.device_name.includes("usb");
const connected = snapshot.device_connected || simulator || detected;
// Show the live UI shell in simulator/detected modes; only "Connected"
// means claimed HID (not yet shipped for production hardware).
const showLiveShell =
snapshot.device_connected || simulator || detected;
const chipLabel = snapshot.device_connected
? "Connected"
: detected
? "Detected"
: simulator
? "Simulator"
: "Disconnected";
: demo
? "Demo"
: simulator
? "Simulator"
: "Disconnected";
const chipTone = snapshot.device_connected
? "ok"
: detected || simulator
? "warn"
: "off";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep demo-browser consistent across the UI.

bus.ts:31-32 now emits device_name: "demo-browser", so Popover labels the state as Demo; however, Settings.tsx:374-381 only recognizes "mock" and otherwise displays not connected. The Device tab will therefore disagree with this status. Reuse isDemoSnapshot(snapshot) or add the same demo branch there.

Comment on lines +4 to +7
//! pushes changes onto the bus. This is an intentional, documented exception to
//! the “no timers” footprint ideal — a CFRunLoop notification observer can
//! replace the poll later. The daemon (not the UI) owns this signal so
//! `--no-ui` still auto-follows.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Do not document auto-follow as working until focus resolution can switch live focus.

The watcher publishes frontmost changes, but Registry::resolve_focus returns early when the current focus still exists, before evaluating frontmost_app. Since set_frontmost_app calls resolve_focus, changing applications does not move focus to the new app’s session. Either fix that policy and add a regression test, or document the current limitation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/microbridged/src/frontmost.rs` around lines 4 - 7, Update
Registry::resolve_focus so it evaluates frontmost_app and switches to the new
application’s session when focus changes, rather than returning early solely
because the current focus still exists; ensure set_frontmost_app triggers this
behavior and add a regression test covering live application switching. If live
switching cannot be implemented, revise the frontmost.rs documentation to state
that auto-follow is currently limited.

Comment on lines +19 to +24
// Keep the config dir private; the socket itself is locked to 0600 below.
let _ = std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700));
}
let _ = std::fs::remove_file(&path);
let listener = UnixListener::bind(&path)?;
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed when private directory permissions cannot be applied.

Line 20 ignores set_permissions errors, then the daemon proceeds to bind. If an existing directory cannot be chmodded to 0700, other local users may still traverse it and connect using the socket’s effective mode, contradicting the documented privacy guarantee. Propagate the error before binding.

Proposed fix
-        // Keep the config dir private; the socket itself is locked to 0600 below.
-        let _ = std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700));
+        // Fail closed if the config directory cannot be made private.
+        std::fs::set_permissions(
+            parent,
+            std::fs::Permissions::from_mode(0o700),
+        )?;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Keep the config dir private; the socket itself is locked to 0600 below.
let _ = std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700));
}
let _ = std::fs::remove_file(&path);
let listener = UnixListener::bind(&path)?;
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600))?;
// Fail closed if the config directory cannot be made private.
std::fs::set_permissions(
parent,
std::fs::Permissions::from_mode(0o700),
)?;
}
let _ = std::fs::remove_file(&path);
let listener = UnixListener::bind(&path)?;
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600))?;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/microbridged/src/socket.rs` around lines 19 - 24, Update the
parent-directory permission setup in the socket initialization flow to propagate
errors from std::fs::set_permissions instead of ignoring them. Ensure failure to
apply mode 0700 returns before remove_file or UnixListener::bind proceeds, while
preserving the existing socket mode handling.

Comment thread docs/architecture.md
Comment on lines +44 to 46
3. **Auto-follow.** Otherwise the frontmost app's active session owns the
deck — driven by `NSWorkspace` frontmost-app notifications (event-driven,
not polled).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the current polling implementation.

This section contradicts line 24 and frontmost.rs, where the watcher polls NSWorkspace every 400ms. Replace “event-driven, not polled” with the current polling behavior and mention notifications as future work.

Proposed wording
-3. **Auto-follow.** Otherwise the frontmost app's active session owns the
-  deck — driven by `NSWorkspace` frontmost-app notifications (event-driven,
-  not polled).
+3. **Auto-follow.** Otherwise the frontmost app's active session owns the
+  deck — currently tracked by a 400ms `NSWorkspace` poll; a notification
+  observer can replace this later.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
3. **Auto-follow.** Otherwise the frontmost app's active session owns the
deck — driven by `NSWorkspace` frontmost-app notifications (event-driven,
not polled).
3. **Auto-follow.** Otherwise the frontmost app's active session owns the
deck — currently tracked by a 400ms `NSWorkspace` poll; a notification
observer can replace this later.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/architecture.md` around lines 44 - 46, Update the Auto-follow
description in the architecture documentation to accurately state that the
watcher polls NSWorkspace every 400ms to identify the frontmost app. Remove the
claim that it is event-driven and not polled, and note that NSWorkspace
notifications are planned future work.

Comment thread Formula/microbridge.rb
Comment on lines +52 to +55
resource("ui").stage do
app = Dir["**/Microbridge.app"].first
odie "Microbridge.app missing from UI release archive" if app.nil?
prefix.install app

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Keep the Homebrew ownership marker outside the signed app bundle.

Line 55 installs the prebuilt signed app, but post_install subsequently writes .microbridge-brew inside that bundle. This changes its sealed contents and can invalidate strict signature verification. Store the marker beside the app instead.

Proposed fix
     apps = Pathname.new(Dir.home)/"Applications"
     apps.mkpath
     dest = apps/"Microbridge.app"
-    marker = dest/".microbridge-brew"
+    marker = apps/".Microbridge.app.microbridge-brew"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Formula/microbridge.rb` around lines 52 - 55, Update post_install to write
the .microbridge-brew ownership marker beside the installed Microbridge.app
rather than inside its signed bundle. Keep the resource("ui").stage installation
flow and app path unchanged, and ensure any marker path references use the
external location consistently.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prepares Microbridge for the v0.1.0 “public alpha” release by aligning install/distribution paths with GitHub Release assets, tightening local-only security/privacy posture, and updating UI/docs to be explicit about current hardware/HID limitations.

Changes:

  • Switch Homebrew + formula bump tooling to use prebuilt GitHub Release assets (daemon + UI) and align install docs accordingly.
  • Add OSS hardening documentation (PRIVACY.md, updated SECURITY.md) and tighten daemon socket/dir permissions.
  • UI/UX “honesty pass” (Simulator/Detected/Demo/Connected semantics) + version bumps across Rust/Tauri/UI packages.

Reviewed changes

Copilot reviewed 23 out of 25 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
SECURITY.md Expands security policy scope/reporting details and clarifies local socket posture.
scripts/install-from-release.sh Gates Linux aarch64 release installs until binaries are published.
scripts/bump-formula.sh Reworks formula bump script to hash the same prebuilt release asset URLs Homebrew will fetch.
README.md Updates public status messaging and sets expectations about HID timing.
PRIVACY.md Adds a privacy statement emphasizing local-only operation and no telemetry/networking.
INSTALL.md Updates release install examples and documents Homebrew’s prebuilt install behavior.
Formula/microbridge.rb Changes formula to install prebuilt daemon + UI release archives (instead of building from source).
docs/project-tracking.md Documents milestone-based tracking and Linear bridging plan.
docs/governance.md Updates supported install path language to reflect prebuilt Homebrew installs.
docs/architecture.md Documents footprint budget exception for frontmost polling and updates focus model wording.
crates/microbridged/src/state.rs Clarifies action forwarding behavior for in-process adapters pending #24.
crates/microbridged/src/socket.rs Tightens socket directory/socket file permissions.
crates/microbridged/src/registry.rs Updates focus resolution doc comment regarding auto-follow behavior.
crates/microbridged/src/frontmost.rs Clarifies polling watcher as an intentional “no timers” exception.
CONTRIBUTING.md Updates tagging/install-from-release examples to v0.1.0.
Cargo.toml Bumps workspace version to 0.1.0.
Cargo.lock Updates crate versions to 0.1.0.
apps/microbridge-ui/src/surfaces/Settings.tsx Marks Cursor/T3 adapters as scaffold-only / not production.
apps/microbridge-ui/src/surfaces/Popover.tsx Refines device state chip semantics and adds clearer messaging for demo/simulator/detected.
apps/microbridge-ui/src/lib/bus.ts Adjusts browser demo snapshot semantics and simplifies demo detection helper.
apps/microbridge-ui/src-tauri/tauri.conf.json Bumps Tauri app version to 0.1.0.
apps/microbridge-ui/src-tauri/Cargo.toml Bumps UI crate version to 0.1.0.
apps/microbridge-ui/package.json Bumps UI package version to 0.1.0.
apps/microbridge-ui/package-lock.json Updates lockfile package versions to 0.1.0.
.github/ISSUE_TEMPLATE/bug_report.yml Updates bug template placeholder version to v0.1.0.
Files not reviewed (1)
  • apps/microbridge-ui/package-lock.json: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Formula/microbridge.rb
on_arm do
url "https://github.com/DevVig/microbridge/releases/download/v#{version}/microbridge-v#{version}-aarch64-apple-darwin.tar.gz"
# sha256 filled by scripts/bump-formula.sh after each release
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
Comment thread Formula/microbridge.rb

resource "ui" do
url "https://github.com/DevVig/microbridge/releases/download/v#{version}/microbridge-ui-v#{version}-aarch64-apple-darwin.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
Comment thread Formula/microbridge.rb
end
on_intel do
url "https://github.com/DevVig/microbridge/releases/download/v#{version}/microbridge-v#{version}-x86_64-apple-darwin.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
Comment thread Formula/microbridge.rb
system "npm", "run", "tauri", "build", "--", "--bundles", "app"
resource "ui" do
url "https://github.com/DevVig/microbridge/releases/download/v#{version}/microbridge-ui-v#{version}-x86_64-apple-darwin.tar.gz"
sha256 "0000000000000000000000000000000000000000000000000000000000000000"
Comment thread Formula/microbridge.rb
Comment on lines +47 to +50
def install
# Release tarball layout: microbridge-vX.Y.Z-<target>/{microbridged,microbridgectl,…}
bin.install Dir["**/microbridged"].first
bin.install Dir["**/microbridgectl"].first
Comment on lines 18 to 21
std::fs::create_dir_all(parent)?;
// Keep the config dir private; the socket itself is locked to 0600 below.
let _ = std::fs::set_permissions(parent, std::fs::Permissions::from_mode(0o700));
}
Comment thread docs/architecture.md
Comment on lines +44 to 46
3. **Auto-follow.** Otherwise the frontmost app's active session owns the
deck — driven by `NSWorkspace` frontmost-app notifications (event-driven,
not polled).
Comment thread SECURITY.md
Comment on lines +3 to +4
Microbridge runs unprivileged on your Mac, listens only on a **local Unix
socket** (mode `0600` under `~/.microbridge/`), and performs **no network I/O**.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Public repo + release hygiene (v0.1.0)

2 participants