Version Manager - Cross-Machine Software Dashboard
Version Manager - Cross-Machine Software Dashboard
A real-time admin dashboard on the Midimaze platform that provides a single pane of glass for all installed software, git repo sync status, and configuration parity across multiple macOS machines.
Problem
Managing software across multiple machines (MacBook Pro and Mac mini) with 6+ package managers (Nix, Homebrew, pip, bun globals, Mac App Store, manual installs) creates fragmentation. Without a unified view, there's no way to quickly answer:
- Is package X up to date?
- Is package Y installed via multiple managers (conflict)?
- Are my git repos (dotfiles, nix-config, claude skills) in sync across machines?
- Which brew packages still need to be migrated to Nix?
Architecture
Collector-Push Model
A local Bun script runs on each machine and pushes data to Convex via authenticated HTTP actions. This is the same pattern used by monitoring tools like Datadog — each machine reports its own state to a central store.
┌─────────────┐ POST /software-inventory/collect
│ MacBook Pro │ ──────────────────────────────────────► ┌─────────┐
│ (collector) │ │ Convex │
└─────────────┘ │ Cloud │
│ │
┌─────────────┐ POST /software-inventory/repos │ Tables: │
│ Mac mini │ ──────────────────────────────────────► │ - pkgs │
│ (collector) │ │ - repos │
└─────────────┘ └────┬────┘
│
useQuery()│
▼
┌─────────────────┐
│ /admin/version- │
│ manager │
│ (React dashboard)│
└─────────────────┘
Data Sources
| Collector | Command | What it yields |
|---|---|---|
| Homebrew | brew info --installed --json=v2 | Name, version, latest, homepage, description |
| Bun globals | bun pm ls -g | Package name, version |
| pip | pip list --format=json | Package name, version |
| System Profiler | system_profiler SPApplicationsDataType -json | GUI apps, App Store vs developer |
| Audit logs | Parse ~/.brew-audit-log.txt | Migration status per package |
| Git repos | git commands on each repo | Branch, HEAD, dirty, ahead/behind |
Security
- Dashboard: Admin-only via
requireRole(ctx, "admin")— not even professor role can see it - Collector HTTP endpoints: Authenticated with
SOFTWARE_INVENTORY_SECRETBearer token (same pattern as vault-sync) - Data: Package names and versions are not sensitive; repo status shows only commit SHAs and branch names
Features
Package Inventory
- Conflict Detection: Same package installed via 2+ managers gets flagged (e.g., VLC via both Nix and Homebrew cask)
- Outdated Indicator: Compares installed version against latest available
- Migration Tracking: Shows which brew packages are pending migration to Nix, already migrated, or intentionally kept in brew
- Changelog Links: Auto-resolves GitHub releases URL from homepage; manual overrides for non-GitHub projects (Obsidian, Slack, Zoom, etc.)
- Source Badges: Color-coded dots per package manager (sky=Nix, amber=Brew, pink=Bun, green=pip, gray=System)
Repo Sync Status
- Cross-Machine Comparison: Groups repos by name, shows HEAD commit per machine — if they differ, shows DESYNC badge
- Dirty Detection: Flags repos with uncommitted changes
- Ahead/Behind Counts: Shows how many commits ahead/behind remote
- Repo Types: Categorized as project, dotfiles, config, or claude for targeted filtering
- Scans:
~/Code/github.com/theslyprofessor/,~/nix-config,~/dotfiles
Dashboard UI
- Two tabs: Packages and Repos
- Machine filter dropdown (All / 21-MBP / Nakuls-Mac-mini)
- Filter presets: All, Conflicts, Outdated, Pending Migration, Out of Sync, Dirty
- Sortable table columns
- Click-to-expand detail sidebar for packages
- Summary stat cards with counts
Running the Collector
bash# From the midimaze-platform repo export SOFTWARE_INVENTORY_SECRET=<your-secret> bun run scripts/collect-software-inventory.ts
The collector:
- Detects which machine it's running on via
scutil --get ComputerName - Runs all package collectors in parallel
- Merges results with name normalization (handles aliases like
python312→python3) - Scans git repos for sync status
- Pushes everything to Convex
Run it on both machines to populate cross-machine comparison data.
Convex Schema
Three tables in convex/schema/softwareInventory.ts:
softwarePackages: One row per (package, machine) pair with per-source version fieldsrepoSyncStatus: One row per (repo, machine) pair with branch, HEAD, dirty, ahead/behindsoftwareCollectionRuns: Audit log of collector invocations with timestamps and stats
Key Files
| File | Purpose |
|---|---|
convex/schema/softwareInventory.ts | Schema definition (3 tables) |
convex/softwareInventory.ts | Queries + internal mutations |
convex/http.ts | HTTP endpoints for collector |
apps/web/src/routes/admin/version-manager.tsx | Dashboard UI |
scripts/collect-software-inventory.ts | Local collector script |
Future Ideas
- Nix store path parsing: Extract versions from
~/.nix-profile/bin/symlink targets for Nix-only packages - Scheduled collection: Run the collector on a cron (every 6 hours) via launchd
- Diff view: Side-by-side comparison of what's on MBP vs Mac mini
- Export: JSON/CSV export for auditing
- Migration planner: Auto-generate
brew uninstallcommands for conflicting packages