ROST implementation methodCompass authoring guideInstall the ROST implementation SkillROST implementation evidence and groundingAICOS chat guideResponsibility Graph playbookCharter design playbookCharter authoring deep-diveAgent staffing playbookAdd agents to your Responsibility GraphDesign a custom agentAgent builder guideAgent definition import guideHow agents workTool access and vaultAvailable tools guideCLI and MCP installation guideSkill builder guideAgent Skill authoring guideAgent Skill setup guideAgent reference mapCascade guideSignal guideFriction guideSteward queue guideBilling and pricing guideConfirmations and human gates guideGoverned command capability matrixSettings guideMembers and invites guideNotifications guideLocal runner guideStock agents guideTroubleshooting guideAI model data handling guideSecurity model guideSync rhythm playbookMigration and legal notes
Docs

Signal guide

How to define and read measurables so the company runs on evidence instead of status theater.

operating rhythm

On this page

  • Good measurables
  • What to avoid
  • Operate Signal from CLI or MCP
  • Run Signal without an agent
  • Per-seat budget alerts
  • Import a scorecard from CSV
  • Adopt a measurable template
  • The leadership scorecard grid
  • Auto-fill Signal from a connected source
  • Collect a Signal by judgment (the Signal agent)
  • When to stop for confirmation
  • Agent guidance

Signal is the measurable layer of the operating system. It should show what is healthy, stale, at risk, or broken without requiring humans to compile status by hand.

Good measurables

  • Owned by one seat.
  • Tied to a responsibility or goal.
  • Updated on a useful cadence.
  • Has a target or threshold.
  • Produces an exception when it breaks.

What to avoid

Avoid vanity numbers, manual-only status fields, and metrics nobody can act on. If a measurable goes off track and no seat knows what to do, the Charter is incomplete.

Operate Signal from CLI or MCP

  • Read: rost signal list --json / signal.list / rost_list_signals returns measurables with their latest reading and on/off-track state, plus effective_source — the read-time measured-by (auto when a source binding is active, otherwise agent/human), matching the /signal UI and distinct from the declared source. signal.get / rost_get_signal returns one measurable's full reading history.
  • Add a measurable: measurable.create (scope: seat) defines a measurable a seat owns — name, unit, direction, target, cadence. The seat owns it; readings attach to it afterward.
  • Record a reading: rost status record --measurable-id <id> --value <n> (status.record, scope: seat) writes a status event with the reading. This is not gated. An agent's status.record never downgrades a human-confirmed reading: a routine agent read that lands on a period a human already confirmed leaves the confirmed value and its confirmation intact (invariants #7/#8 — agents recommend; humans decide).
  • Confirm a reading: rost signal confirm / signal.confirm_reading / rost_confirm_signal_reading marks a reading human-verified. signal.correct_reading / rost_correct_signal_reading overwrites a reading with a human-confirmed value.
  • Draft first readings from a connected source: signal.draft_first_readings pulls a measurable's bound source once (read-only, SSRF-guarded — the same pull path as signal.preview) and lands the value as a DRAFT reading for the current period, for a human to confirm. It is strictly for a measurable that has a connected source but has never had a confirmed reading — in ANY period, not just the current one. A measurable that already carries a confirmed reading (even an older one) is rejected with an "already has readings" outcome and no pull happens, so the first-reading flow can never be repurposed as an ongoing draft source; use signal.report to add a current-period datapoint or signal.correct_reading to change a confirmed value instead. The Signal page shows a "Draft first readings" button on the eligible (never-measured) rows so the row stops being a permanent blank. Nothing is published — a human clears the draft with signal.confirm_reading (invariant #7) — and it never fabricates a value: a non-numeric or blocked pull drafts nothing and says so.

Run Signal without an agent

A human can run the whole loop from the Signal page. The page opens answer-first — one computed line ("2 of 14 measurables need attention," or "All 14 measurables on target" when nothing needs you) with only the exception rows fully visible; healthy measurables collapse to a single "N on target" count you can expand. Every create/edit action lives behind the one "+ Add" button, which opens a drawer with four segments: Log reading records a human reading (the same signal.correct_reading path, or a row's own "Log reading" button seeds the drawer to that measurable), New measurable creates one against a seat (the measurable.create path, plus adopting from the template catalog), Sources, and CSV import. You do not need an agent to keep Signal current.

Per-seat budget alerts

The Signal page shows a seat-cost strip: each seat's trailing 30-day agent run spend. On top of that you can set a per-seat soft budget alert — a spend threshold in USD. When a seat's 30-day spend approaches its threshold (at 80%) or crosses it, a visible alert appears in the cost strip on the scorecard. This alert is advisory only: it never blocks a run or pauses an agent (hard budget enforcement is a separate, later capability). Set a threshold from the cost strip by choosing an agent seat and entering an amount, or leave the amount blank to clear it. Thresholds are per tenant and per seat; setting one records a durable event.

Import a scorecard from CSV

To move off a spreadsheet or another operating tool, open the Signal page's "+ Add" drawer and choose the "CSV import" segment (the signal.import command, also available on CLI/MCP). Each row becomes a measurable owned by the seat whose name matches the row's owner, with its target, unit, direction, cadence, and trailing readings. Import is idempotent — re-importing upserts by period — and a row whose cadence conflicts with an existing measurable is reported and skipped, not overwritten.

Adopt a measurable template

Not sure which measurables to track? measurable_template.list returns a starter catalog grouped by function (Sales, Finance, Operations, Marketing, HR), each with a unit, direction, cadence, suggested target, and source-readiness metadata when a known source path exists. Finance templates are explicit: platform billing usage baselines can use safe platform metadata, while tenant customer MRR, QuickBooks AR aging, and QuickBooks gross margin stay blocked until tenant-owned billing/accounting reads ship. measurable_template.adopt instantiates one against a seat — the same write path as measurable.create, so the created measurable is a plain human-owned Signal you log against afterward. Adoption is a human act; the suggested target is just a starting point you can override.

The leadership scorecard grid

The default /signal view is exception-first — it surfaces what is off track, at risk, or pending, so the team never stares at a wall of green. For a leadership review or the familiar weekly scorecard grid, toggle the trailing-grid view (scorecard.grid): rows are the measurables for a cadence (the classic 13-week weekly view, plus monthly, quarterly, and annual), columns are the trailing periods, and each cell is colour-coded against its target and direction. An empty period reads "no data", never a fabricated zero. The grid also surfaces the Org-Checkup measurables — charter coverage, measurable freshness, aging open issues, and peak steward load — computed on read from the operating data, so the scorecard is never empty even before a single reading is logged.

Auto-fill Signal from a connected source

Once a measurable's number lives in a connected system, you can teach ROST the exact deterministic pull once and let it keep the measurable current. The flow is discover -> preview -> bind -> bind_confirm:

  • integration.discover returns non-secret metadata for a connected source and a recipe skeleton to author against.
  • signal.preview runs a candidate recipe live but read-only against an allowlisted HTTPS source, returns the extracted value, and issues a short-lived preview_token. It never mutates and never stores a secret in the recipe — the credential is resolved from the connection at execution.
  • signal.bind persists the validated recipe as an inert draft binding. It requires the preview_token from a preview of the same recipe, so nothing is bound that was not first seen working.
  • signal.bind_confirm is human-only. It activates the binding (draft -> active); an agent that calls it produces a pending confirmation instead. Only after a human confirms does the scheduled pull begin writing confirmed readings.

Discovery always returns a recipe_presets array; it is empty when ROST does not recognize a safe source type. Today the proven self-filling path is Baserow REST through integration.connect_rest: a tenant admin creates or rotates the Baserow connection through the command/vault path, then Signal runs integration.discover -> signal.preview -> signal.bind -> signal.bind_confirm against that connected source. Baserow discovery now offers two first-class presets: baserow.row-field (read one scalar field from a row) and baserow.filtered-count (count rows matching a condition). The filtered-count builder takes a table id, field key, comparison operator, and comparison value and assembles a validated rest_for_signals recipe whose value_path is the response count; the field key and operator are allowlisted (they form the query-parameter name) and the comparison value is percent-encoded, so nothing the operator types can inject into the URL. The human still supplies the real table, field, operator, value, and host — presets and the builder are starter recipes, not secret stores. Google Sheets Signal pulls are not live yet: Google uses OAuth JSON credentials and remains withheld from REST presets until the pull executor extracts and refreshes the Google access token instead of treating the stored credential blob as a bearer token. A preset includes a label, cadence, required metadata, a draft rest_for_signals recipe, and the host allowlist to preview with. The human still fills in the real Baserow table/row/field or exact REST URL and value path before running signal.preview; presets are starter recipes, not secret stores.

Recipes are validated data, never code: a read-only GET, a closed set of non-secret headers, and a restricted scalar path to the value. Every fetch passes one SSRF guard (HTTPS only, a steward-confirmed host allowlist set at bind, and a runtime check that the host does not resolve to a private address). The preset output never contains nango:// handles, vault refs, tokens, or static credential headers. Deterministic pulls write integration-sourced readings on the measurable's cadence.

In the web app, the same workflow lives on /signal in the "+ Add" drawer's "Sources" segment. It shows each measurable's setup state — manual, agent draft, source draft, or auto-filled — plus the latest safe pull outcome when one exists. Choose a connected source, discover its non-secret metadata, preview a GET URL and value path, bind the working preview as a draft, then confirm the draft before scheduled pulls can write readings. The UI never displays credential material, vault refs, raw response bodies, or recipe secrets; if no connected source exists, connect one from Settings first.

A source binding can inform a measurable without automatically changing a Cascade goal. The proven Leiluna Baserow binding uses informs. Use drives_status only after a second business anchor confirms that this exact measurable should compute a childless goal's status; otherwise the Signal should stay visible as evidence and exception context, not an automatic goal-status driver.

Collect a Signal by judgment (the Signal agent)

Some measurables cannot be a deterministic pull — the number lives in a PDF, in messy records that need reconciling, or is a judgment estimate of progress. For those, mark the measurable agent-sourced and let a per-seat Signal agent read it. The agent proposes each reading with signal.report (scope: seat): one draft reading for one of its OWN seat's agent-sourced measurables, with a value and a short note citing the source. The reading lands unconfirmed, exactly like a deterministic draft — a human clears it with signal.confirm_reading. signal.report refuses any measurable not owned by the acting seat and any measurable whose source is not agent, and it never confirms its own reading. Deliver it as the stock/signal-collector template (a read-only agent whose only durable grant is signal.report) or run the collect-seat-signals how-to from an occupant agent. When the agent cannot read a number confidently — ambiguous or conflicting sources — it escalates instead of guessing.

When to stop for confirmation

signal.correct_reading is human_required; overwriting a recorded measurable is a human judgment. signal.confirm_reading is none, so a seat can confirm its own readings directly. measurable.create is none — defining a measurable is not gated. An agent records readings with evidence; a human corrects when a value is wrong.

Agent guidance

Agents may record readings when the Charter allows it. Agent-reported readings should include enough evidence for a human to trust the number. Broken or stale Signal should become Friction when action is needed.

Version

2026-07-20.2

Used by

  • human
  • cli
  • mcp
  • in app agent

API

/api/reference/files/signal-guide