Repository navigation
Settings
You change settings on the machine that runs VitalAIze: in the VitalAIze app on a Mac (Settings), or with bin/vitalaize setup in a terminal on a Mac or Linux. Both save to the same file, settings.json, so either can change what the other saved. Most changes are in use within a few seconds. A few restart VitalAIze, and only then: what the machine does, the board's port and password, turning the New Relic page on or off, saving this machine's Claude sessions, taking collectors and their port, and the two AWS profiles.
If you would sooner write a file, everything can also live in settings.exs. Anything you leave out uses its default, so you only write the parts that differ. The file in the repo, settings.example.exs, is a good start: copy it to settings.exs and change what you need. What the app or vitalaize setup saves goes on top of it.
The file is one Elixir map. Text goes in "double quotes", lists in [square brackets], nil means "not set", and every line inside the map ends with a comma.
The board looks for it in this order:
- the path in the
WALLBOARD_SETTINGSenvironment variable; -
settings.exsin the folder the board was installed to; -
settings.exsin the folder you started it from.
The Mac app keeps settings.exs and settings.json next to its database (see How it works). On Linux, settings.json is in the folder you unpacked.
Tap Settings at the top of the board. It shows every setting and its value, with secrets as dots, but it cannot change them: it says "Settings are shown here and changed on this machine: open the VitalAIze app, or run vitalaize setup in a terminal." The "page" marks in the tables below mean a setting is shown there and can be changed in the app or with vitalaize setup; the rest are in settings.exs only.
The page also lists Connected machines, with a Disconnect button for each, when the hub takes collectors, and the repositories you chose to ignore in the mailbox, each with Ask again. See Connecting other machines.
Without a board password (token), the Settings page opens only in a browser on the machine that runs the board. With one, any device that has signed in with it can open it. On a Linux hub with no screen, set token in settings.exs first.
Changing the board password restarts the board, and every device then needs the new one once, because the key that signs the board's cookie comes from the password.
| Setting | Default | What it does | Page |
|---|---|---|---|
port |
4747 |
The port the board listens on: http://<this machine's address>:<port>/. |
page, restart |
token |
nil |
The board password. With none, anyone on your network can open the board. With one, the first visit from each device needs /?token=<your token> at the end of the address; after that the browser remembers it. Make one with openssl rand -hex 16. |
page, restart |
rotate_seconds |
30 |
Seconds before the board turns to the next tab. 0 stops it. |
page |
timezone |
"America/New_York" |
The time zone for every time on the board. | page |
brand.name |
"Kyroco" |
The name in the header. | page |
brand.logo |
nil |
A path to an .svg or .png logo for the header. With none, the name shows as text. |
|
brand.page2_title |
"Production health · New Relic" |
The New Relic tab's title. | |
updates.check |
true |
Once a day, ask GitHub for the latest release and show a note by Settings when it is newer. false stops the check. |
page |
korium.enabled |
true |
Show the Korium numbers in Trends. | page |
| Setting | Default | What it does | Page |
|---|---|---|---|
role |
"both" |
"both" runs the board and saves this machine's own sessions. "hub" runs the board and keeps only what other machines send. "collector" runs no board: it watches this machine's sessions and streams them to a hub. |
page, restart |
On a hub, these let other machines connect. See Connecting other machines.
| Setting | Default | What it does | Page |
|---|---|---|---|
link.enabled |
false |
Take collectors: let other machines pair with this hub and stream their sessions to it. Needs archive.enabled. |
page, restart |
link.port |
4748 |
The port collectors stream to. It is not the board's port. | page, restart |
On a collector, these say what it watches. A collector has no board, so change the first two in the app or with vitalaize setup; the rest are in settings.exs only.
| Setting | Default | What it does |
|---|---|---|
collector.claude_dirs |
nil |
The Claude folders to watch. nil finds ~/.claude and every ~/.claude-something folder that holds sessions. |
collector.codex_dirs |
nil |
The Codex folders to watch. nil finds ~/.codex. |
collector.dir |
nil |
Where the collector keeps its certificate, its place in each file, and what it has not sent yet. nil is a collector folder where the database would be. |
collector.outbox_mb |
64 |
The most disk, in MB, that unsent events may take. When it is full the collector stops reading until the hub is back. |
collector.backfill_days |
14 |
On the first start, report sessions changed in this many days. |
collector.poll_seconds |
2 |
How often to look for new lines in session files. |
| Setting | Default | What it does | Page |
|---|---|---|---|
claude.config_dirs |
["~/.claude"] |
Every Claude folder you use. Each one is checked with claude agents --json. With more than one, each session shows which account it belongs to. |
page |
claude.poll_seconds |
5 |
How often to check for sessions. Codex uses it too. | |
claude.long_running_minutes |
45 |
A working session gets a ringed, darker dot after this many minutes. | page |
usage.poll_seconds |
30 |
How often to read the transcripts for tokens and cost. | |
usage.days_back |
21 |
How far back to read transcripts. | |
usage.prices |
Anthropic's API list prices, checked 2026-09-28 | Dollars per million tokens, per model: input, output, cache_read, and context (the model's context size in tokens). A model matches the longest name here that it starts with. Add or change one like prices: %{"claude-opus-5-5" => %{label: "Opus 5.5", input: 4.0, output: 20.0, cache_read: 0.20, context: 1_000_000}}. |
| Setting | Default | What it does | Page |
|---|---|---|---|
codex.enabled |
true |
Show and save this machine's Codex sessions. A Codex folder that does not exist is skipped, so this can stay on without Codex. | page |
codex.dirs |
["~/.codex"] |
Every Codex folder you use. | page |
codex.idle_minutes |
120 |
How long an idle Codex session stays on the Agents tab after its last turn. | page |
See Alerts for how to set each one up. All are on the page, and take effect at once.
| Setting | Default | What it does |
|---|---|---|
alerts.phone |
nil |
Messages (Mac only): your phone number. |
alerts.via |
"iMessage" |
"iMessage", or "SMS" for a plain text sent through your iPhone. |
alerts.slack_webhook |
nil |
A Slack incoming webhook address. |
alerts.ntfy_topic |
nil |
An ntfy topic. Make it hard to guess. |
alerts.ntfy_server |
nil |
Your own ntfy server. nil means https://ntfy.sh. |
alerts.pushover_user |
nil |
Your Pushover user key. |
alerts.pushover_token |
nil |
The API token of an app you made at Pushover. Both Pushover settings are needed. |
From 0.4.0. A limit on what your agents use in a day or a week. When a total passes its limit, a strip on the board says so and one alert goes out (see Alerts). Every limit needs archive.enabled. All are on the page, and take effect at once.
| Setting | Default | What it does |
|---|---|---|
budget.claude_dollars |
nil |
Claude spend limit, in dollars at API list prices, as on Trends. nil means no limit. |
budget.claude_dollars_per |
"day" |
"day" or "week". A week starts on Monday. Days follow the time zone of the hub's own clock, as Trends does, not timezone. |
budget.claude_tokens |
nil |
Claude token limit. It counts cache reads and writes too, which are most of it. |
budget.claude_tokens_per |
"day" |
"day" or "week". |
budget.codex_tokens |
nil |
Codex token limit, counted the same way. |
budget.codex_tokens_per |
"day" |
"day" or "week". |
budget.by_messages, budget.by_slack, budget.by_ntfy, budget.by_pushover
|
true |
Which channels get budget alerts. A channel sends only when it is set up under Alerts. |
A limit is a whole number. The app and vitalaize setup take it with commas or spaces, such as $1,500 or 50 000 000.
Read through the gh command, which must be signed in (gh auth login).
| Setting | Default | What it does | Page |
|---|---|---|---|
github.repos |
[] |
The repositories to follow, as "owner/name". The workflow files named in this section (the gate, the deploys and the timeline rows) are the first repository's; another repository names its own (below), or has none. The rest of the section applies to each. Dev and Prod follow the first. Left empty, the board follows github.repo alone. |
page |
github.repo |
"your-org/your-repo" |
The one repository to follow when repos is empty. Files from before several repositories use this. |
|
github.branch |
"main" |
The main branch. | page |
github.poll_seconds |
30 |
How often to read runs, the merge queue and pull requests. | |
github.deploy_poll_seconds |
120 |
How often to read the deploy workflows, and each repository's list of self-hosted runners. That list needs admin rights on the repository; after GitHub refuses it, the board asks again once an hour. | |
github.gate_workflow |
"ci.yml" |
The first repository's workflow file that gates merges. Its latest finished run says whether main is green. | page |
github.gate_check |
"ci" |
The check name on pull requests. | |
github.dev_deploy |
"deploy-staging.yml" |
The first repository's dev deploy workflow file. | page |
github.prod_deploy |
"deploy-production.yml" |
The first repository's prod deploy workflow file. | page |
github.deploy_workflows |
the two deploy files | Deploy workflows to track even when their last run is days old. A file the repository does not have is skipped. | |
github.lanes |
CI, Staging, Production | The first rows of the "last 6 hours" timeline, each with a label and its workflows. A row shows when one of its workflows ran in those hours. Any other workflow that ran gets a row under its own name after these, up to six rows in all. |
Every repository's timeline shows the workflows that ran in it, whatever they are called, with nothing to set. What a repository other than the first does not get by itself is a gate: with none, its Main comes from the runs its pushes to main started (red when the newest run of any of those workflows failed, green when all passed). To give it a gate or deploy workflows of its own:
-
In the app or
vitalaize setup, write them after its name on its line:acme/mobile gate=build.yml dev=deploy-dev.yml prod=deploy.yml. Any of the three can be left out. The first repository's line is its name alone, since its workflows are the three fields below the list. -
In
settings.exs, make its entry a map:
github: %{
gate_workflow: "ci.yml",
repos: [
"acme/api",
%{repo: "acme/mobile", gate_workflow: "build.yml"}
]
}A map in the file can also change anything else in this section for that repository, such as branch or lanes. A gate file the repository does not have counts as no gate.
Each busy repository costs about 600 GitHub calls an hour, and GitHub allows 5,000, so keep it to about six. See How it works.
Off until you name a read-only AWS profile. Then the Dev tile shows Awake, Asleep, Waking or Going to sleep instead of the last deploy.
| Setting | Default | What it does | Page |
|---|---|---|---|
dev_power.aws_profile |
nil |
The AWS profile to read with, from ~/.aws/config. nil turns this off. |
page, restart |
dev_power.region |
nil |
nil uses the profile's own region. |
|
dev_power.database |
nil |
Dev's database. | |
dev_power.cluster |
nil |
Dev's ECS cluster. | |
dev_power.poll_seconds |
60 |
How often to check. |
Off until you name read-only AWS profiles for prod and dev (builds.dev_profile, or dev_power.aws_profile). Then the Prod tile says Current when prod runs the same images as dev, and Behind when dev has a different one.
| Setting | Default | What it does | Page |
|---|---|---|---|
builds.prod_profile |
nil |
The AWS profile for prod. | page, restart |
builds.dev_profile |
nil |
The AWS profile for dev. nil uses dev_power.aws_profile. |
|
builds.region |
"us-east-1" |
The region. | |
builds.repository |
nil |
The ECR repository both environments' images come from. | |
builds.dev |
%{cluster: nil, services: []} |
Dev's ECS cluster and services. | |
builds.prod |
%{cluster: nil, services: []} |
Prod's ECS cluster and services. | |
builds.poll_seconds |
60 |
How often to check. |
| Setting | Default | What it does | Page |
|---|---|---|---|
archive.enabled |
true |
Keep every session in the database, for Archive and Trends. Off also turns off everything that needs the database: collectors, the saved GitHub runs and pull requests (so Shipped and CI minutes on Trends), budget limits, and announcing the board on your network. | |
archive.collect_local |
true |
Save this machine's own sessions. Off makes a hub that only keeps what other machines send. role: "hub" turns it off whatever is set here. |
page, restart |
archive.advertise |
true |
Announce the board on your network, so collectors find it. | |
archive.path |
nil |
Where the database lives. nil picks the usual place (see How it works). |
|
archive.machine |
nil |
This machine's name in the database. nil uses its network name. |
|
archive.backfill_days |
14 |
Days of sessions, GitHub runs and pull requests to save on the first start. It is also the furthest back the board reaches for runs it missed while it was off. | page |
archive.settle_seconds |
120 |
Save a session once it has been quiet this long. | page |
archive.poll_seconds |
60 |
How often to look for sessions to save. | |
archive.github_poll_seconds |
300 |
How often to save GitHub runs, jobs and merged pull requests. Once a day it also reads whether each repository is public and its default branch. | |
archive.github_jobs_per_round |
100 |
At most this many runs get their jobs saved each round (one GitHub call each, or one per 100 jobs for a bigger run). Every attempt's jobs are saved. |
The New Relic tab, read through its NerdGraph API. The checks are set in settings.exs only, so the tab is empty until you write new_relic.checks there.
| Setting | Default | What it does | Page |
|---|---|---|---|
new_relic.enabled |
true |
false removes the tab: the board never asks the keychain, 1Password or New Relic for anything. |
page, restart |
| New Relic API key | none | From 0.4.0. Type your New Relic User API key (it starts with NRAK-) in the app or vitalaize setup. It is kept in your login keychain on a Mac, and in keys/new_relic beside the database on Linux, a file only your user can read; never in settings.json. It is shown only as dots or "set". Type a new one to replace it; empty the field (- in vitalaize setup) to remove it. A typed key wins over 1Password. |
page |
new_relic.api_key_ref |
nil |
Or where the key lives in 1Password, like "op://Private/New Relic/credential", read with 1Password's op command. Used only when no key is typed. The key is read again whenever either changes, with no restart, and kept in memory only. |
page |
new_relic.account_id |
nil |
Your New Relic account number. | page |
new_relic.region |
"us" |
"us" or "eu". |
page |
new_relic.poll_seconds |
60 |
How often to check. | |
new_relic.checks |
[] |
The checks to show. The first is the big one; the rest fill the "More checks" row. Each is %{name: "Heartbeat", monitor: "Name of the synthetic monitor"} or %{name: "Errors today", nrql: "SELECT count(*) FROM TransactionError SINCE today", unit: ""}. |
|
new_relic.slots |
3 |
How many spaces the "More checks" row has, filled or empty. |
The theme section holds every color and font, as CSS values: page, surface, text, text_body, text_muted, border, border_strong, track, accent, alert, info, info_light, ok, warn, warn_deep, radius, font_body, font_display, font_css_url, fonts_dir (your own font files; nil uses the ones that come with the board) and font_faces. theme.dark holds the same color names for dark mode. The defaults are Kyroco's colors; see settings.example.exs for each light value. These are in the file only.
These are not in the app or vitalaize setup, so change them in settings.exs: brand.logo, brand.page2_title, every poll_seconds, usage.days_back and usage.prices, github.repo, github.gate_check, github.deploy_workflows and github.lanes, everything under dev_power and builds except the two profiles, archive.enabled, archive.advertise, archive.path, archive.machine, the two archive.github_ settings, new_relic.checks and new_relic.slots, collector.dir, collector.outbox_mb and collector.backfill_days, and theme.
-
RELEASE_DISTRIBUTIONandRELEASE_COOKIE(environment variables): remote control of a running board is off unless you setRELEASE_DISTRIBUTION. If you do, also setRELEASE_COOKIEto a secret of your own. -
WALLBOARD_ROLE: when set, it wins overrolein the file.
Kyroco VitalAIze · Home · Ask a question · Suggest an idea