Variables¶
Variables keep credentials, base URLs and counters out of probe scripts. They resolve down the hierarchy, so you define a value once at the level where it is true and every service beneath inherits it.
Scopes¶
Each level has its own prefix, and a script names the scope it reads from explicitly:
| Prefix | Level | Edited in |
|---|---|---|
$o. |
Organization | Infrastructure → Org variables |
$w. |
Workspace | The workspace's Variables tab |
$p. |
Project | The project's Variables tab |
$s. |
Service | The service panel's Variables tab |
A service's script can reference any of its ancestors' scopes — $o.apiToken
reads the organization's variable, $p.baseUrl the project's — which is what
lets you define a value once at the level where it is true and use it from
every service beneath. The prefix is part of the reference, not a search hint:
$p.baseUrl reads the project scope and nothing else, and a $s.baseUrl
defined alongside it is a different variable, not an override. There is no
implicit fallback chain — a reference either names a scope that holds the
variable, or it resolves to nothing.
The Variables tab of any resource shows its own scope alongside the ancestor scopes a script here could reference, but only the resource's own scope is editable — the others are shown read-only, with the level they come from. That is intentional: it lets you see what a script can reach without walking the tree yourself, while keeping the edit in the one place that owns it.
Prefixes address scope, storage is per level
The $o. / $w. / $p. / $s. prefix says which level a reference reads.
The stored variable itself is keyed by its bare name within that level —
the prefix is not part of the stored name.
Types¶
| Type | Encrypted at rest | Visible after saving | Writable by a script |
|---|---|---|---|
| Secret | Yes | Never | No |
| Variable | Yes | On demand, via reveal | No |
| Metric | No | Always | Yes |
Secrets are write-only from the UI's point of view: once saved, nothing can display the value again. Use them for passwords and API tokens, where the inability to read it back is the feature.
Variables are also encrypted, but can be revealed on demand. Use them for things that are sensitive but that you legitimately need to check — a base URL with an embedded key, an account identifier.
Metrics are plaintext, always visible, and — uniquely — a probe script can write to them. That is what makes them metrics rather than settings.
Writeback¶
A script can store a value for the next run:
Note the two forms in that script. The write-back target uses the bare
$name form — write-backs always land at the service scope, so the target
carries no prefix. Reading the value back on the next run uses the scoped
form, $s.lastCount. Writing to a scoped name like "$s.lastCount" does not
do what it looks like — it creates a separate variable rather than updating
lastCount.
A write-back creates the variable as a metric if it does not exist, and only ever overwrites metric variables: a write-back whose name collides with a secret or encrypted variable is skipped with a warning rather than applied.
Values written this way are persisted after the run and injected into the next one. This is what makes change detection possible: compare what you see now against what you stored last time, and alert on the delta rather than on an absolute threshold.
Note the difference from $$ run-scope variables, which live only for the
duration of a single run and are used to pass values between calls in a chain —
see Writing Probes.
Note
Writeback is applied per run, not per call. A value stored anywhere in the script lands once the run completes.
Computed variables¶
Some variables are maintained by the platform and are read-only. They are injected at run time, so a script can use them without you defining anything:
| Variable | Value |
|---|---|
$s.name |
The service's name |
$s.lastStatus |
The status of the previous run |
$s.lastStatusSince |
When the service entered that status |
$s.lastStatusConsecutive |
How many runs in a row have reported it |
$p.name |
The project's name |
$w.name |
The workspace's name |
$s.lastStatusConsecutive is the useful one for alert suppression: it lets a
script stay quiet until a failure has repeated, instead of paging on the first
blip.
Configuration variables¶
A service is seeded with configuration variables — boolean toggles that change
how the platform treats its runs. They can be edited but not deleted. Today the
seeded one is trackBaseline (default off), which enables rolling-baseline
tracking for the service.
Using them in scripts¶
Reference a variable with its scope prefix and name. Secrets are decrypted at dispatch and handed to the agent with the script — they are never written into the script itself, and never stored in the result:
post("$p.baseUrl/login", {
body: json({ email: "$o.apiUser", password: "$o.apiPassword" })
})
.expect(status: 200)
Put values at the level that owns them
A base URL that every service in a project shares belongs on the project, not copied into each service. If you change environments later, you change it once. The same reasoning applies to credentials at the workspace or organization level.