Skip to content

Repository files navigation

🛰 Mission Control

A local dev dashboard: one page at http://localhost:4000 that launches, supervises, and opens all the projects on your machine — instead of juggling a terminal window per app and remembering each start command.

Mission Control

Each app still runs as its own process on its own port. The dashboard starts/stops them, shows live status, and gives every project its own workspace: a left sidebar with one item per project and per-project tabs — Info, Console (a real pty for a shell or Claude Code), Logs, Docs, Files, Settings, and Preview — plus an Overview board of all projects at a glance. Vanilla HTML/CSS/JS frontend with no build step; the only runtime dependency is Express.

Features

  • Real process supervision — each app is spawned in its own process group with a TCP readiness probe, so Stop reliably kills the whole tree and frees the ports. Multi-process apps (backend + frontend) are first-class.
  • Overview board — a card per app with a status header (gray stopped · amber starting · green running · red crashed), Start / Stop / Restart, and an Open link once the app's port answers.
  • Console tabs — real pty terminal sessions per project (plain shell or a Claude Code session), which survive a page reload and reattach. The sidebar badges show crashed › Claude waiting › session exited › busy.
  • Live logs — streamed over SSE per process with a replayed ring buffer, in a tab or a pop-out window.
  • Files tab — a lazy project file tree with a CodeMirror 6 editor (atomic writes, stale-file conflict detection, binaries and dependency dirs excluded).
  • Docs on every card — each project's Markdown files (README, LOG, IDEAS, plus anything else in the root or docs/) open in an in-page viewer/editor.
  • Git at a glance — branch, dirty count, ahead/behind, and last commit on the Info tab.
  • App previews — automatic headless-Chrome screenshots of each running app, shown in the Preview tab and archived as a cheap time-lapse of the project.
  • Add projects from the UI — pick a folder, the dashboard auto-detects the framework, start command, and a collision-free port; tweak and save. Every project is editable and deletable. Everything writes to one hand-editable file, apps.json, which also hot-reloads on hand edits.
  • Shortcuts — open the project folder in Finder, a terminal, or your editor of choice; keyboard-first navigation (⌘K switcher, ⌘1–9 projects, ⌘[ / ⌘] tabs, ⌘E new console).
  • Always-on mode — an optional macOS launchd login item keeps the dashboard running in the background, so you can bookmark it or make it your browser home page.

Requirements

  • Node.js 18+ (the server is plain Node + Express, no build step).
  • Python 3 for the pty bridge behind the Console tabs (macOS ships it).
  • macOS for the extras: Finder/Terminal/editor shortcuts, the native folder picker, the launchd always-on mode, and app previews (headless Chrome/Chromium/Edge/Brave). The core supervision + UI is plain Node and not macOS-specific.

Quick start

git clone https://github.com/smombartz/mission-control.git
cd mission-control
npm install
npm start          # opens http://localhost:4000 in your browser

You'll get an empty dashboard — add a project from the sidebar and the form pre-fills the name, framework tag, start command, and port from the folder. Or seed the registry by hand:

cp apps.example.json apps.json   # then edit paths/commands to match your projects

Useful env vars: NO_OPEN=1 npm start skips auto-opening the browser; DASHBOARD_PORT=5000 overrides the port; PROJECTS_DIR=~/Projects sets the folder picker's starting location.

Press Ctrl-C to quit — the dashboard stops every app it started before exiting (no orphan processes, all ports freed).

Keyboard

⌘K switcher · ⌘B sidebar · ⌘0 overview · ⌘1–9 nth project · ⌘[ / ⌘] prev/next tab · ⌘E new console · ⌘⇧E new Claude session · ⌘⇧D close tab (⌘W is reserved by the browser) · ⌘S save (docs/files) · / focus the filter · Esc close/clear.

The registry: apps.json

One file is the single source of truth for every app, editable two ways with the same result:

  • From the UI — add a project from the sidebar, or edit any project in its Settings tab. Changes hot-register into the running dashboard (no restart needed).
  • By hand — edit apps.json; the dashboard watches the file and reloads it live.

An app is a name, a folder, and one or more processes (command + port), plus optional project links. See apps.example.json for a single-process and a multi-process example. The file is git-ignored — it's personal to your machine.

Always-on (launch at login)

bash scripts/install-launchd.sh

This installs a macOS login item (a launchd agent, label com.<your-username>.devdashboard) that keeps the dashboard running in the background — no Dock app, no popups. Bookmark http://localhost:4000 (or make it your home page) and it's always loadable. It auto-restarts on crashes and comes back at the next login. Logs go to ~/Library/Logs/dev-dashboard.log.

LABEL="com.$(id -un).devdashboard"

# restart (e.g. after pulling a new version)
launchctl kickstart -k gui/$(id -u)/$LABEL

# stop now (graceful — stops all managed apps; stays down until next login)
launchctl kill SIGTERM gui/$(id -u)/$LABEL

# uninstall the login item entirely
launchctl bootout gui/$(id -u)/$LABEL && rm ~/Library/LaunchAgents/$LABEL.plist

On Apple Silicon, the supervisor wraps every spawn in arch -arm64 so apps run native arm64 even though launchd launches in an x86_64-preferring context (otherwise Python apps fail to load their arm64 wheels).

How it works

  • apps.json — the single registry: top-level dashboardPort / defaultDocs / docsDirs plus an apps[] array. The dashboard's own entry is a code constant in server.js, not in the file. apps.order.json — the saved display order, overlaying the registry order at boot.
  • server.js — Express + Server-Sent Events. Three SSE connections per page regardless of tab count: one status stream (which also carries terminal-session events), one multiplexed log stream, and one multiplexed terminal stream with resume offsets (reloads and tab changes never replay what the page already has).
  • lib/supervisor.js — spawns each process in its own process group (detached: true) so Stop can signal the whole tree; tracks state with a TCP readiness probe; buffers logs; registers, updates, and removes apps live.
  • lib/registry.js — load/save/validate of apps.json (atomic writes), the command tokenizer, the order sidecar, and the on-disk watcher behind live reloads.
  • lib/terminals.js + lib/pty-bridge.py — real pty sessions for the Console tabs, with scrollback resume and Claude Code busy/waiting detection (OSC 9;4 progress sequences).
  • lib/files.js — the Files tab's tree + read/write, with path containment, atomic writes, an mtime precondition, and binary/dependency-dir exclusion. lib/git.js — read-only git status.
  • lib/detect.js — read-only folder inspection (package.json framework, manage.py, run.sh) that powers the add form's auto-fill.
  • lib/preview.js — headless-Chrome screenshot capture of each running app, no dependencies.
  • public/ — the whole frontend: vanilla ES modules, no build step. Shared design tokens and card styles live in public/styles/; the shell/panel styles in public/css/. CodeMirror 6 is one prebuilt, committed bundle (public/vendor/cm6.js, rebuilt via scripts/build-cm6.sh). docs/design-system.html (card) and docs/design-system-shell.html (shell) are live style guides.

Only runtime dependency: express (plus vendored marked, dompurify, xterm, and CodeMirror in public/vendor/).

License

MIT

About

Mission Control — a one-page local dev dashboard to launch, supervise, and open the apps in your projects folder (Express + SSE, no build step).

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages