Skip to content

The Squidbrake app for hosted dashboards: sign in with your email, no keys to copy - #233

Open
escher-m wants to merge 2 commits into
hosted-sleep-not-deletefrom
hosted-desktop-app
Open

escher-m wants to merge 2 commits into
hosted-sleep-not-deletefrom
hosted-desktop-app

Conversation

@escher-m

Copy link
Copy Markdown
Collaborator

Stacked on #232 (sleep instead of delete). Merge that one first, then GitHub retargets this PR to main.

What it is

A small menu-bar (Mac) or tray (Windows) app. The gateway stays hosted, so we get the same telemetry as every hosted pilot. The app only connects the agents on this computer to that hosted dashboard. The start page's install commands keep working exactly as before, as the backup.

For the person: install → the app opens a sign-in page → email → 6-digit code → "You're protected". There are no keys to copy, and it starts at every login. If they closed the start-page tab, nothing is lost: the app signs in with their email.

How it works

squidbrake.com (insights/app.py):

Endpoint What it does
POST /v1/app/code Supabase emails a code. The answer is the same whether or not the email has a dashboard. Rate-limited per email and per IP.
POST /v1/app/connect Supabase checks the code (the email must be confirmed). Returns a one-time link the app polls.
GET /v1/app/link/ID Says where things are: waking / waiting (with the number ahead) / starting / connecting. Then, once: dashboard, agent key, device token.
POST /v1/app/heartbeat Every 10 min. Wakes a sleeping dashboard. An app seen within a day keeps the dashboard from being put to sleep.
POST /v1/app/signout Forgets the computer.

Where the agent key comes from:

  • The start page's agent key, if it was never taken. That's the "closed the tab" case, and it's instant. The start page then shows "your agent key is already with the app".
  • Otherwise, a new key just for this computer. provision.py app_keys() makes it, named e.g. app-karishmas-macbook-air so it shows on the Team page. It checks the key opens the gateway before handing it over; it never rotates or removes other keys.
  • Only ever an agent key. It can't approve or sign in to the dashboard, so a code typed on someone else's computer never hands over control.

The app (desktop.py, squidbrake app, squidbrake login):

  • Sign-in page: served on 127.0.0.1 at a random secret path, so other websites can't drive it. The browser never sees the agent key.
  • Saved sign-in: ~/.squidbrake/app.json, readable only by the owner (0600).
  • Connecting agents: the same steps as install.sh (connect claude-code --hook-only, connect agents, connect guard, dashboard shortcut).
  • Icon: green = protecting, amber = waking, grey = can't reach the dashboard. Menu: Open dashboard, Reconnect agents, Start at login, Quit.
  • Start at login: Mac LaunchAgent com.squidbrake.app, Windows Run key, Linux XDG autostart.
  • Terminal commands: squidbrake login (the same sign-in in a terminal), squidbrake app --status, squidbrake app --signout.

Installers (packaging/native, native.yml):

  • The build installs .[app] (pystray, Pillow).
  • Windows: gets a console-less squidbrake-app.exe, a Start menu shortcut and the login item. It launches after an interactive install.
  • Mac: the .pkg postinstall opens the app for the logged-in user.
  • Silent / MDM installs (/qn, URL+KEY, installer CLI): unchanged, no app pop-up.
  • The CI smoke test checks the app and its page are in the build.

Start page: a new "App (no terminal)" tab with download buttons. It's the default on Mac/Windows, shown only when INSIGHTS_APP_DOWNLOADS is set, so nothing changes until a release contains the app.

Rollout (after merge)

  1. Supabase: add {{ .Token }} to the Magic Link and Confirm signup email templates (e.g. "or enter this code: {{ .Token }}").
  2. Release: cut a release so native.yml attaches installers that include the app.
  3. Deploy:
    • deploy insights;
    • copy provision.py to the VM, then systemctl restart squidbrake-provision;
    • set INSIGHTS_APP_DOWNLOADS=https://github.com/batrapulkit/squidbrake/releases/latest/download and rebuild insights.
  4. Signing (later, costs money): the installers are still unsigned. The start page tells Mac users about "Open Anyway".

Not in this PR

  • Dashboard sign-in for people: the admin key, still shown on the start page. Passkey/email sign-in is a separate PR.
  • Approval notifications from the icon: they need a gateway endpoint an agent key may read.
  • Intel Mac build.

Tests

  • tests/test_pilot.py:
    • app sign-in takes the untaken key;
    • a second computer gets a minted key;
    • wakes and keeps awake;
    • never reveals who signed up;
    • rate limits;
    • the App tab is off by default.
  • tests/test_provision.py: the real key snippet on a real keys.json (other keys keep working; the new one is an agent); a key that doesn't open the gateway is removed and never handed out.
  • tests/test_desktop.py:
    • the sign-in page answers only at its secret path and never returns the key;
    • app.json is 0600;
    • agent wiring matches install.sh;
    • login item on/off (Mac, Linux);
    • status colours;
    • the CLI.
  • Full suite: 1632 passed, 5 skipped.
  • Run by hand on macOS against a stand-in server: the real tray app opened its sign-in page and went email → code → queue → connected, and squidbrake app --status reported "Protecting".
  • Not checked yet: the Windows MSI and Mac pkg builds (they only run in native.yml).

🤖 Generated with Claude Code

escher-m and others added 2 commits November 13, 2026 20:12
A menu-bar / tray app for hosted dashboards. The gateway stays on our server
(same telemetry as every hosted pilot); the app only connects this computer's
agents to it. The start page's install commands keep working as before.

- squidbrake.com: POST /v1/app/code (Supabase emails a 6-digit code),
  POST /v1/app/connect, GET /v1/app/link/ID (waking / waiting / starting /
  connecting, then the agent key once), POST /v1/app/heartbeat (wakes a
  sleeping dashboard; an app that checked in within a day keeps it awake),
  POST /v1/app/signout. The app gets the start page's untaken agent key, or a
  new one per computer from provision.py. Only ever an agent key.
- provision.py: app_keys() adds one agent key named after the computer.
- desktop.py (`squidbrake app`, `squidbrake login`): icon with status, sign-in
  page on 127.0.0.1 at a random address, wires agents like install.sh, starts
  at login, Open dashboard / Reconnect agents / Quit.
- Installers: native build includes it (pystray + Pillow, extra "app");
  Windows gets a console-less squidbrake-app.exe, a Start menu shortcut and the
  login item; Mac .pkg opens the app after a normal install. MDM / silent
  installs are unchanged.
- Start page: an "App (no terminal)" tab, only when INSIGHTS_APP_DOWNLOADS is set.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant