Repository navigation
How it works
VitalAIze has two kinds of machine. The hub runs the board: it reads its own sessions, asks GitHub and your other services for news, keeps everything in a small database, and serves the page your iPad shows. A collector is one of your other machines: it runs no board. It watches its own Claude Code and Codex sessions and streams what the board needs to the hub. One machine can be both, which is the usual setup for your main Mac.

-
Hub to iPad. The board is a live web page on port 4747. Only what changed is sent to the screen. With a
tokenset, each device needs it once (see Settings). - Collectors to hub. Each collector keeps one encrypted link open to the hub, on the hub's port 4748. Both ends prove who they are with certificates: the hub made one for each machine when you connected it. A machine without a valid certificate cannot connect at all. Each time a collector connects, the hub also tells it the board's port. From 0.4.0, a collector whose tries keep failing asks the hub's pairing door, on the board's port, whether it was removed; on an answer of "removed" that the hub signed, it stops trying. See Connecting other machines.
-
Finding the hub. The hub announces itself on your network (with
dns-sdon a Mac, andavahi-publish-serviceon Linux whenavahi-utilsis installed). A new machine looks for it for a few seconds when you connect it. If it finds none, you type the hub's address. -
GitHub. Through the
ghcommand, signed in as you. The board reads each repository's runs, merge queue and pull requests every 30 seconds, and its list of workflow files and its deploy workflows every 2 minutes. A deploy file a repository does not have is not asked for. The archive saves finished runs and every attempt's jobs every 5 minutes. From 0.4.0 it also saves each repository's merged pull requests, and once a day reads whether each repository is public and its default branch. After the board was off, it reads the runs it missed, from the day before its last good round and no further back thanarchive.backfill_days. From 0.4.0 the board also reads each repository's list of self-hosted runners every 2 minutes when the login has admin rights; after GitHub refuses it, once an hour. Once a day the board also asks GitHub for the latest VitalAIze release. -
AWS (optional). Through the
awscommand with read-only profiles: whether dev's database and services are awake, and whether prod runs the same build as dev. The reads only look at settings, so they never wake a sleeping dev. -
New Relic (optional). Its NerdGraph API. The key comes from your keychain (or, on Linux, a file only your user can read) when you typed it in, and otherwise from 1Password with
op read. It is read at start and again when either setting changes, and kept in memory only. - Alerts. See Alerts.
Collectors only talk to the hub. Only the hub talks to the outside.

A collector adds nothing to Claude Code or Codex. It reads what they already write:
-
Claude: the session files in each Claude folder (
~/.claude, and any~/.claude-somethingfolder that holds sessions), andclaude agents --jsonevery 5 seconds, which says which sessions are working, idle or waiting. A background session that ended or was stopped can stay in that list for hours; one with no process, no status and no question waiting is left out. -
Codex: the session files in
~/.codex/sessions, and the notes the Codex hook leaves when a session waits on you (see Codex). A chat the Codex app copied in from a Claude session watched here is not sent a second time.
It looks for new lines every 2 seconds. The first time it starts, it reports sessions from the last 14 days.
Every line passes through one filter before it can leave the machine. Nothing else builds what a collector sends.
Sent to the hub:
- About the machine, once each time it connects: its name, its system, the collector's version, and the paths of the Claude and Codex folders it watches.
- Numbers and times: tokens, cost, context size, how many prompts and turns, lines added and removed, how many tool calls failed.
- Short names: the model, its effort, the Claude Code or Codex version, what started the session, the tool names a session used, the name of your login.
- The session's title, its folder, its git branch, its GitHub repository as
owner/name, and links to its pull requests. - The first prompt and the latest prompt, clipped: 300 characters for Claude, 500 for Codex. The latest prompt changes as you work, so over a live session the start of each prompt is sent once.
- Whether the session is working, idle or waiting on you, and what kind of wait it is.
- From 0.4.0: the name and state (online or busy) of each GitHub runner running on the machine whose folder the collector's user can read, at most 100. Never the runner's folder, its jobs or its logs. The hub marks a runner offline when the collector stops listing it, and the board uses a report only for a runner that ran the repository's jobs in the last day.
Never sent:
- The agent's replies and its thinking.
- What tools were given and what they returned, and the commands a session ran.
- The names and contents of the files a session touched, and its patches.
- Pasted text and images.
- The words of a permission prompt, since they name the command or the file.
One limit: a tool's name is sent, and a name is text someone chose. A tool named after a short secret would get out.
What passed the filter is kept on the collector's disk until the hub says it is stored. If the hub is off or out of reach, the collector keeps trying, a second apart at first and up to a minute apart, and carries on from where the hub left off. It keeps at most 64 MB (collector.outbox_mb). If that fills, it stops reading until the hub is back. Nothing is lost, because the session files still hold everything.
The hub saves what arrives in its database and shows it:
- A live card on the Agents tab while the session works, idles or waits, marked with that machine's name.
- The Archive and Trends, saved every few seconds while the session runs. A session counts once, however it reached the hub. From 0.4.0 the hub takes in but does not save a number that cannot be right, such as a time before 1970 or more than a day ahead of its clock, or one request costing over $10,000.
- If a machine's link closes, or the machine says nothing for 90 seconds, its cards stay with their last status and are marked stale, with a dashed border and a note that says since when. They come back to life when the machine reconnects. The hub takes a card down when the collector says the session ended, or a day after the link closed.
On the hub's own machine nothing is streamed. The board reads the sessions directly:
-
Claude:
claude agents --jsonevery 5 seconds, for each Claude folder. The transcripts in each folder give tokens, cost, lines changed and tools used, read every 30 seconds. -
Codex: the session files in
~/.codex/sessions, read every 5 seconds.
A hub session is saved in the archive once it has been quiet for archive.settle_seconds (2 minutes by default). The first start saves the last archive.backfill_days (14 by default).

A new machine shows a six-digit code. The same code appears in the mailbox on the hub's board, and you approve it there. The hub then makes a certificate for that machine. There is no key to copy between the machines. Connecting other machines has the steps and the limits.

-
On the hub's own machine,
claude agents --jsonsays a session is waiting, and the board alerts the first time it sees that. Codex sessions there need you when the Codex hook reports an approval request, or a turn that ended on a question (see Codex). -
On a collector, the collector sees the same thing on its own machine and reports the session as waiting. The hub shows Needs you at once. It sends the alert about 5 seconds later (
claude.poll_seconds) if the session still waits, so a prompt you answer at once does not also reach your phone. - Limits. At most 20 alerts from collectors go out in 10 minutes. After the hub restarts, sessions that were already waiting show Needs you again but do not alert a second time.
- Every channel you set up gets the same short text; see Alerts.
| What | Where |
|---|---|
| The hub's database (sessions, GitHub runs, saved settings) | Mac app: ~/Library/Application Support/VitalAIze/wallboard.db. Built from source on a Mac: ~/Library/Application Support/Wallboard/wallboard.db. Linux: ~/.local/share/vitalaize/wallboard.db. Change it with archive.path. |
| The hub's certificates and its list of connected machines | A link folder next to the database |
| A collector's key and certificate, and what it has not sent yet | A collector folder where the database would be on that machine. Change it with collector.dir. Only your user can read it. |
| The Mac app's settings |
settings.exs next to the Mac app's database |
| The log | Mac app: ~/Library/Logs/VitalAIze/board.log. Built from source on a Mac with scripts/login-item.sh: ~/Library/Logs/wallboard.log. Linux: journalctl --user -u vitalaize. |
| The Codex hook and what it last saw |
~/.codex/vitalaize, cleaned after a week |
The database is SQLite. Nothing in it leaves the hub. A collector has no database.
Each source (Claude, Codex, GitHub, usage, AWS, New Relic) runs on its own timer. If one fails, its panel keeps its last good data, says how old it is and why, and the rest of the board carries on. The next round tries again. Trends say "Loading…" beside a section while its history is still coming in. Every outside program the board runs (gh, claude, aws, op) has a time limit. From 0.4.0, when it passes, the program and everything it started are stopped, so one stuck call cannot hold up the rest.
GitHub allows 5,000 calls an hour. Each repository costs about 600 an hour while two of its runs are going at once, and fewer when it is quiet. For the first couple of hours after you add repositories, the archive also fills in their older runs, at up to about 1,300 more calls an hour, shared by all of them. Six busy repositories plus that fill come to about 4,900 an hour, so with six busy ones the fill can take longer than a couple of hours. Past six, the board may run out of calls.
Kyroco VitalAIze · Home · Ask a question · Suggest an idea