Data Namespaces (p., s., i., o., steps., submission.)¶
Whenever you write a rule in Validibot — a CEL assertion, a signal data
path, a row rule on a Tabular step — you're reaching into one of six
data namespaces. Each namespace holds a different kind of value, and
you choose which one by the short prefix you put in front of the name:
p., s., i., o., steps., or submission..
If you've ever written p.price > 0 or s.target_eui <= 60 and wondered
what the p and s actually mean, this page is the one-stop explainer.
Validibot tip
You don't have to use the short prefix. p.price and payload.price
mean the same thing. The short forms keep expressions readable; the long
forms are there when you want to be explicit.
The six namespaces at a glance¶
| Short | Long | What it holds | Scope |
|---|---|---|---|
p. |
payload. |
The raw file the submitter sent (JSON, XML, CSV cells, parsed RDF, …) | Whole workflow |
s. |
signal. |
The workflow's named vocabulary — values you've mapped or promoted | Whole workflow |
i. |
input. |
This step's inputs — facts the validator sees before it runs | One step, before its run |
o. |
output. |
This step's outputs — values the validator produced after running | One step, after its run |
steps.<key>.input. / steps.<key>.output. |
— | An earlier step's inputs or outputs, addressed by step key | Whole workflow |
submission. |
— | The submission envelope — metadata and server-stamped facts that live beside the file | Whole workflow |
The teaching analogy: think of each step as a function in a program.
i.*are the function's parameters.o.*is what the function returns.s.*is module-level state shared across functions.p.*is the raw input the program started with.submission.*is metadata about that input — who, when, what type, how big.steps.foo.*is direct access to another function's parameters or return value.
When to reach for each one¶
p.* — the raw submission. Always present. Whatever the submitter
sent, exactly as they sent it. p.price reads the price field of a
JSON submission. For XML, attributes appear with an @ prefix
(m["@Conductivity"]); see the CEL Expressions
page for the XML rules.
s.* — the workflow's vocabulary. Named values any step can
reference. You create them two ways:
- Workflow signal mapping — on the workflow's settings page, pick a
name like
target_eui, point it at a path in the submission, and it's available everywhere ass.target_eui. - Promotion from a step — take an input or output of a particular
step, click Copy to Signal, give it a workflow-wide name. From
that point on, every step can reference it as
s.<your_name>.
If you're writing steps.preflight.output.zone_count in more than one
assertion, that's the cue to promote it — s.zone_count is stabler and
shorter.
i.* — this step's inputs. Values the validator can see at the
start of this step, before its main work runs. For an EnergyPlus step
this is parser-extracted facts about the IDF (i.zone_count,
i.idf_version). For a step with template variables, the resolved
variable values land here. i.* is step-local — i.zone_count in one
step is unrelated to i.zone_count in another.
o.* — this step's outputs. Values the validator produced after
running. For an EnergyPlus step this is the simulation results
(o.site_eui_kwh_m2, o.unmet_heating_hours). For a JSON Schema step
there are usually no outputs — the validator just says pass or fail.
o.* is step-local and temporally bound: only available in
output-stage assertions on the step that produced it. The assertion
editor enforces this — when you're editing an input-stage assertion,
autocomplete won't offer o.* references.
steps.<step_key>.input.* / steps.<step_key>.output.* — direct
access to an earlier step's values by step key. Good for one-off
cross-step references. For values you cite often, promote to s.*
instead.
submission.* — the submission envelope. Context about the
submission that lives beside the file rather than inside it, so it
resolves the same way no matter what was uploaded — JSON, XML, CSV, or
an RDF .ttl graph. Two flavours:
- Submitter-provided (treat as untrusted):
submission.name,submission.short_description, and the free-formsubmission.metadata.<key>bag. Whoever launched the run set these. - Server-stamped (trustworthy):
submission.file_type,submission.size(bytes),submission.uploaded_at(a timestamp). Validibot sets these — a submitter can't forge them.
submission is long-only. There's no single-letter alias because s is
already taken by signals.
When i.* and o.* are empty¶
A natural question: "Why are i.* and o.* sometimes empty?"
A step populates i.* or o.* only when its validator runs a process
that transforms data. Three positions on the spectrum:
- No process (JSON Schema, XML Schema, Basic) — assertions use
p.*and optionallys.*.i.*ando.*are empty. - Process produces outputs only (SHACL, THERM) — the validator
parses or evaluates the payload and emits results. Assertions
primarily use
o.*.i.*is empty. - Process has discrete input and output stages (EnergyPlus, FMU) —
the validator extracts facts from the payload first (
i.*), runs its main work, then emits results (o.*). Both stages are meaningful.
If you open a workflow step and the Inputs or Outputs panel is empty, that's intentional — it accurately reflects what the chosen validator does with your data.
A special case: row.*¶
There's one namespace that doesn't appear in the table above because it
only exists in one place. Inside a row rule on a
Tabular validator step, row.<column> refers
to the current row's value for a declared column (row.min_depth <=
row.max_depth), and the rule runs once per data row.
row.* isn't available anywhere else, and a row rule may only reference
columns declared in the step's schema — typos are caught when you save
the step, not on the next run.
Where to next¶
- CEL Expressions — the full guide to writing rules over these namespaces, including all supported operators, Validibot helpers, and worked examples.
- Tabular Validator — the only place
row.*exists. - Glossary — formal definitions of signal, payload, submission, and friends.