Configuration
Settings live in the store once an installation is seeded; the config/*.json files in the repository are the generic defaults a new installation starts from, and each has a README beside it that explains why the file exists. What the Tower may edit in each file is declared once, in scripts/config-registers.mts, and this page is generated from that declaration. Each editable entry is either a list of rows (a site's data sources, a recurring cost) or a single value.
config/beads.json
Its README: config/beads.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Task projects (task-hub-spokes) — one task project per site. Rows live at /spokes of config/beads.json (array, keyed by asset); edited from /settings.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
asset | Site | asset-id | yes | the site this project belongs to | — |
prefix | Task prefix | string | yes | 2–8 lowercase letters, e.g. demo | up to 8 characters; matches ^[a-z]{2,8}$ |
database | Database | string | yes | start with a lowercase letter; use lowercase letters, digits or underscores | up to 32 characters; matches ^[a-z][a-z0-9_]*$; defaults to prefix |
repo | Repository | string | no | legacy checkout metadata; local repository access is configured on the host | up to 200 characters; fixed once written |
config/counters.json
Its README: config/counters.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Site counter cards (asset-counters) — one site's counter cards. Rows live at /assets of config/counters.json (object, keyed by asset-id); edited from Add a site, then the site's Settings tab (Card totals). Rows are added and removed whole; no field inside one is set through the register.
config/domain-costs.json
Its README: config/domain-costs.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Domain orders (domain-costs) — one prepaid domain order. Rows live at /domains of config/domain-costs.json (array, keyed by domain); edited from /financials.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
domain | Domain | string | yes | lowercase, a name not a URL: example.com | up to 253 characters; matches ^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$; fixed once written |
asset | Site | asset-id | yes | the site that carries the cost | — |
kind | Order | enum | yes | what was bought | one of registration, renewal, transfer |
paidUsd | Paid (USD) | number | yes | as charged on the receipt | at least 0 |
paidOn | Paid on | date | yes | the receipt date | — |
config/entities.json
Its README: config/entities.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Entities (entities) — one legal entity, and the sites it owns. Rows live at /entities of config/entities.json (array, keyed by slug); edited from /settings.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
slug | Id | string | yes | lowercase-with-dashes: acme-holdings | up to 40 characters; matches ^[a-z0-9]+(?:-[a-z0-9]+)*$; fixed once written |
name | Name | string | yes | as on its paperwork | up to 80 characters |
form | Legal form | string | no | as the paperwork spells it: LLC, Ltd, sole proprietor | up to 40 characters |
jurisdiction | Registered in | string | no | where it is registered: US-DE, Poland | up to 40 characters |
assets | Sites | string-list | no | the site ids this entity owns | — |
config/ga4-custom-dimensions.json
Its README: config/ga4-custom-dimensions.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Sites with registered dimensions (ga4-event-params-assets) — one site's registered-dimension declaration, holding its list. Rows live at /assets of config/ga4-custom-dimensions.json (object, keyed by asset-id); edited from the site's Data sources tab. Rows are added and removed whole; no field inside one is set through the register.
Registered event parameters (ga4-event-params) — a parameter registered as a GA4 custom dimension. Rows live at /assets/{asset}/eventParams of config/ga4-custom-dimensions.json (array, keyed by param); edited from the site's Data sources tab.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
param | Parameter | string | yes | as the site sends it, e.g. message | up to 40 characters; matches ^[A-Za-z][A-Za-z0-9_]*$ |
config/integrations.json
Its README: config/integrations.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Site data sources (asset-integrations) — one site's data sources. Rows live at /assets of config/integrations.json (object, keyed by asset-id); edited from Add a site (/assets/new). Rows are added and removed whole; no field inside one is set through the register.
Site data sources (asset-lane) — one data source on one site. Rows live at /assets/{asset} of config/integrations.json (object, keyed by lane-id); edited from the site's Data sources tab.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
status | Posture | enum | yes | set up, or skipped with a reason | one of live, degraded, needs-setup, skipped, not-applicable |
note | Reason | string | no | one line: why skipped, or what blocks it | up to 90 characters |
ref | Source pointer | string | no | which credential reaches this site — a convention or placeholder, never a secret | up to 200 characters |
since | Since | date | yes | when this posture was recorded, YYYY-MM-DD | — |
mediavineSiteId | Mediavine site | string | no | copy the site id from Mediavine | up to 160 characters; matches ^[A-Za-z0-9+/=_-]+$ |
mediavineEnabled | Automatic Mediavine sync | boolean | no | collect yesterday at 6:10 a.m. Pacific; disabling preserves saved revenue | — |
revenueHolidayCalendar | Revenue forecast holiday calendar | enum | no | holidays compared with this site’s traffic | one of none, US, CA, US,CA |
stripeAccountId | Stripe account | string | no | the acct_ id from Stripe’s account settings | up to 64 characters; matches ^acct_[A-Za-z0-9]+$ |
propertyId | GA4 property id | string | no | digits only, e.g. 123456789 | up to 20 characters; matches ^[1-9][0-9]{4,14}$ |
siteUrl | Site | string | no | use sc-domain:example.com or https://example.com/ | up to 253 characters; matches `^(?:sc-domain:[a-z0-9][a-z0-9.-]*.[a-z] |
locationCode | Location | integer | no | DataForSEO's numeric location code — 2840 is the United States, the portfolio baseline | 1 to 99999999 |
languageCode | Language | enum | no | DataForSEO's language code — 'en' is the portfolio baseline | one of en, es, fr, de, pt, it, nl, pl |
host | PostHog region | enum | no | us or eu | one of us, eu |
projectId | PostHog project id | string | no | the number in the project's URL (us.posthog.com/project/424242), digits only | up to 12 characters; matches ^[1-9][0-9]{0,11}$ |
funnels | Funnels | posthog-funnels | no | 2 to 10 steps each, in order | — |
Data-source catalog (data-source-catalog) — one data source the product can collect. Rows live at /catalog of config/integrations.json (array, keyed by id); edited from none — it ships with NoticeOS and changes with a product update.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
id | Id | string | yes | lowercase-with-dashes: bing-webmaster | up to 40 characters; matches ^[a-z0-9]+(?:-[a-z0-9]+)*$; fixed once written |
label | Label | string | yes | what the product calls it | up to 80 characters; fixed once written |
scope | Scope | enum | yes | whether it collects for a site, for the OS, or both | one of property, portfolio, both; fixed once written |
layer | Layer | enum | yes | whose failure a red cell reports | one of os, provider, property; fixed once written |
credential | Credential | enum | yes | whether one credential can serve more than one site | one of shared, per-property; fixed once written |
docRef | Doc | string | yes | the doc section that explains it | up to 200 characters; fixed once written |
config/pull.json
Its README: config/pull.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Site metrics endpoints (asset-pull) — one site's own metrics endpoint. Rows live at / of config/pull.json (array, keyed by asset); edited from Add a site, then the site's Settings tab (Fetch from an endpoint). Rows are added and removed whole; no field inside one is set through the register.
config/recurring-costs.json
Its README: config/recurring-costs.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Recurring costs (recurring-costs) — one unmetered subscription, booked every month it runs. Rows live at /costs of config/recurring-costs.json (array, keyed by id); edited from /financials.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
id | Id | string | yes | lowercase-with-dashes: claude-code | up to 64 characters; matches ^[a-z0-9]+(?:-[a-z0-9]+)*$; fixed once written |
label | Label | string | yes | what the charge is called on the statement | up to 80 characters |
asset | Site | asset-id | yes | who carries it — the OS for anything portfolio-wide | — |
family | Family | enum | yes | the ledger group it books under | one of inference, api, infra, operator, os-overhead |
amountUsdPerMonth | USD / month | number | yes | the recurring charge | at least 0; fixed once written |
from | From | month | yes | first month to book, YYYY-MM | — |
to | To | month | no | last month to book, YYYY-MM | — |
note | Note | string | no | copied onto each month's cost | up to 400 characters |
config/serp-panel.json
Its README: config/serp-panel.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Sites buying a tracked panel (serp-panel-assets) — one site's tracked-query panel, holding its terms. Rows live at /assets of config/serp-panel.json (object, keyed by asset-id); edited from the site's Growth tab. Rows are added and removed whole; no field inside one is set through the register.
Tracked queries (serp-panel-queries) — one tracked term, and the bet it measures. Rows live at /assets/{asset}/queries of config/serp-panel.json (array, keyed by query); edited from the site's Growth tab.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
query | Query | string | yes | verbatim, as a searcher types it | up to 120 characters |
label | Bet | string | no | the bet this term counts toward | up to 60 characters; candidates suggest |
config/signal-panels.json
Its README: config/signal-panels.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Panel refresh roster (signal-panels) — whether a site stays on the standing panel-refresh cadence. Rows live at /assets of config/signal-panels.json (object, keyed by asset-id); edited from the site's Growth tab.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
enabled | Daily refresh | boolean | yes | rebuilt daily at no provider cost | — |
reason | Reason | enum | yes | why it is on or off | one of live-lanes, no-lane-yet, not-applicable |
task | Task | string | no | the id of the task that tracks this decision | up to 40 characters; matches ^[a-z]{2,8}-[a-z0-9]+(?:\.[0-9]+)*$ |
since | Since | date | no | when the decision was taken, YYYY-MM-DD | — |
Panel history window (panel-refresh-window) — days of history each refresh reads (Days). One value at /refresh/windowDays of config/signal-panels.json, edited from /settings; integer, 1 to 365.
Panel freshness bar (panel-freshness-bar) — how old a source may get before it reads stale (Days). One value at /refresh/freshnessMaxAgeDays of config/signal-panels.json, edited from /settings; integer, 1 to 365.
config/tower.json
Its README: config/tower.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Where each site shows (site-display) — where one site shows and the icons it uses. Rows live at /sites of config/tower.json (object, keyed by asset-id); edited from Sites → Arrange, Settings → Sites, and the site's Settings tab (Identity, Where it shows).
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
list | Home and Sites list | boolean | no | a row on Home and on the Sites page | — |
tv | TV | boolean | no | every widget on the TV | — |
work | Work this week | boolean | no | a row in the TV's Work this week | — |
lightIcon | Light icon | url | no | drawn on light screens in place of the one read | up to 2048 characters |
darkIcon | Dark icon | url | no | drawn on dark screens and the TV in place of the one read | up to 2048 characters |
config/value-events.json
Its README: config/value-events.README.md.
What the Tower may edit here
Generated by pnpm generate from scripts/config-registers.mts, the one declaration of every list and single value the Tower may edit; scripts/config-docs.test.mjs fails when this block is stale.
Sites declaring value events (value-events-assets) — one site's value-event declaration, holding its list. Rows live at /assets of config/value-events.json (object, keyed by asset-id); edited from the site's Data sources tab. Rows are added and removed whole; no field inside one is set through the register.
Value events (value-events) — one GA4 event this site calls a value event. Rows live at /assets/{asset}/valueEvents of config/value-events.json (array, keyed by event); edited from the site's Data sources tab.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
event | GA4 event | string | yes | verbatim as the site emits it (calculation_complete, never "Calculation complete") | up to 40 characters; matches ^[A-Za-z][A-Za-z0-9_]*$ |
Product use stages (product-use-stages) — saved event counts shown in Product use. Rows live at /assets/{asset}/productUseStages of config/value-events.json (array, keyed by eventName); edited from the site's Data sources tab.
| Field | Label | Type | Required | Hint | Rule |
|---|---|---|---|---|---|
eventName | GA4 event | string | yes | the saved event name | up to 40 characters; matches ^[A-Za-z][A-Za-z0-9_]*$ |
label | Label | string | yes | the stage heading | up to 60 characters |
group | Group | enum | yes | the display group | one of primary, sharing, supporting |
compareTo | Compare to event | string | no | another declared event volume | up to 40 characters; matches ^[A-Za-z][A-Za-z0-9_]*$ |
comparisonLabel | Comparison label | string | no | the independent-volume comparison heading | up to 60 characters |