GNOME Shell extension & operator dashboard
Adds a top-panel button that drops down a single-screen operator dashboard: tailnet peers, local claude sessions, Linear queue, and calendar.
The extension spawns and supervises a small Node.js backend on
127.0.0.1:5175. There is nothing to autostart.
git clone https://github.com/klarum-software/glance.git ~/repos/glance
cd ~/repos/glance
./install/install.shLog out and back in (Wayland requires a session restart to load new extensions), then:
gnome-extensions enable glance@klarum-software.github.ioA dot appears in the top panel. Click it for the dashboard.
~/.config/glance/config.json (optional, all fields have defaults):
{
"port": 5175,
"inboxDir": "/home/you/claude-inbox",
"calendarBin": "/home/you/repos/glance/server/bin/gcal.js",
"linearApiKey": "lin_api_...",
"services": ["orchestrator", "inbox-ui", "work-tmux"],
"meEmails": ["you@example.com"]
}Every field is also overridable via env (GLANCE_PORT, GLANCE_INBOX,
GLANCE_CALENDAR_BIN, GLANCE_GMAIL_BIN, GLANCE_GMAIL_MAX_UNREAD,
GLANCE_LINEAR_SYNC, GLANCE_LINEAR_API_KEY, GLANCE_SERVICES,
GLANCE_ME_EMAILS). See server/config.js.
Create a personal API key at https://linear.app/settings/api (Personal
API keys -> Create key). Paste it into linearApiKey in
~/.config/glance/config.json (or export GLANCE_LINEAR_API_KEY).
The backend's POST /api/sync-linear will fetch your assigned, non-closed
issues directly from the Linear GraphQL API and cache them under
<inboxDir>/.linear-cache/. Click the sync button in the LINEAR column
header to refresh on demand.
If you'd rather sync via an external service (e.g. inbox-ui), set
linearSyncUrl instead. linearApiKey takes precedence when both are
set.
calendarBin is just a path to any Node.js script that, when invoked
as node <calendarBin> list <days>, prints one event per line in the
format:
2026-05-23T10:00:00+02:00 Event title [event-id]
2026-05-25 All-day event [other-id]
Two routes ship out of the box:
Local route (any source). Point calendarBin at your own script.
It can wrap gcalcli, parse a local .ics file, query a private CalDAV
server, read an exported calendar dump, anything. As long as it prints
the line format above on stdout and exits 0, glance is happy. Lowest
friction if you already have a calendar tool authenticated on the box.
OAuth route (Google Calendar, bundled). A two-script helper under
server/bin/ that handles the Google OAuth flow yourself, using your
own Google Cloud Desktop OAuth client (the repo ships no shared
credentials). Full walkthrough:
docs/CALENDAR-SETUP.md. Short version:
- Create an OAuth 2.0 Client ID (Desktop app) at https://console.cloud.google.com, enable the Google Calendar API, add yourself as a test user.
- Run
node server/bin/google-auth.js --calendar(or with no flags to also grant Gmail), paste the client id and secret, complete the browser consent. - Set
calendarBinin~/.config/glance/config.jsonto the absolute path ofserver/bin/gcal.js(the auth helper prints it for you). - Disable/enable the extension. Events appear within a refresh cycle.
Gmail shares the same OAuth client as Calendar (one consent, one token).
Run node server/bin/google-auth.js --gmail (or no flags for both
scopes), then set gmailBin in ~/.config/glance/config.json to the
absolute path of server/bin/gmail.js. The INBOX widget is registered
disabled-by-default; enable it from prefs or the in-dashboard edit mode.
Sender/subject blacklist patterns keep the column focused. Full guide:
docs/GMAIL-SETUP.md.
| Column | Source |
|---|---|
| REMOTE | tailscale status --json + klarum-presence agent on each peer (port 5176) |
| SESSIONS | ps-derived claude process trees + RSS vs total RAM |
| LINEAR | <inboxDir>/.linear-cache/*.json |
| CALENDAR | calendarBin stdout (refreshed every 60s). For Google Calendar, see docs/CALENDAR-SETUP.md |
| INBOX | gmailBin -- unread Gmail with blacklist filter (read/send/summarize/archive). See docs/GMAIL-SETUP.md |
glance/
├── extension/ GNOME extension (GJS)
├── server/ Node.js backend (~600 lines, zero deps)
│ ├── server.js HTTP + state aggregation + actions
│ ├── config.js ~/.config/glance/config.json loader
│ └── platform/ OS adapters
├── public/ Browser dashboard (used by the backend for dev)
├── install/ Installer
└── docs/ ARCHITECTURE, INSTALL, CONTRIBUTING
The per-peer presence agent now lives in its own repository at Klarum-Software/klarum-presence. Install it on each tailnet peer that should appear in the REMOTE column. Glance is a network consumer (HTTP+JSON on port 5176); no in-tree dependency.
See docs/ARCHITECTURE.md.
MIT. See LICENSE.
