01 · Start here
The Code view edits the same schema as Visual.
There is no secondary export format. Valid JSON becomes the same working document used by Visual, engine lint, and the schema tester. After you commit and release it, the Registry, hosted Flows, and API use that exact immutable body.
You need nested conditions, calculated expressions, temporal overrides, or an exact reviewable document.
You want guided controls for ordinary fields, rules, legal references, calculations, and time periods.
Visual and Code autosave into the repository’s private working draft. Open Changes, review the complete diff, and create a commit with a short “what changed” note. Review and publication use that exact commit. Once released, the version is locked; choose Start next version to continue from it.
Test the schema with the Flow experiences ProseID marks as available. Publication reruns engine and renderer checks against every legal period.
02 · Document structure
Nine roots. One executable release.
The root object describes identity, presentation, execution, and legal time. Unknown additions may survive ordinary JSON parsing but are not automatically part of the supported protocol.
{
"protocol": "proseid/1.0",
"schema_id": "incident_triage",
"version": "1.0.0",
"metadata": { ... },
"definitions": { ... },
"state_model": { ... },
"temporal_map": [ ... ],
"logic_tree": [ ... ],
"attestations": { ... }
}- protocol
- Use
proseid/1.0for new builder documents. - schema_id
- A stable machine identifier. Publishing freezes it with the release.
- version
- An immutable release label, not a legal validity date.
- metadata
- Title, description, controlled jurisdictions, and legal references.
- definitions
- Editable inputs and visible or hidden outputs.
- state_model
- Optional calculated values and their input dependencies.
- temporal_map
- Optional effective-date routing between legal rule sets.
- logic_tree
- Ordered rules that change presentation, set values, or report issues.
- attestations
- Optional rich provider sign-offs. Respondent confirmations normally use an attestation field.
03 · Registry metadata
Describe the interpretation outside the respondent’s answers.
metadata is part of the canonical schema and is frozen per release. ProseID also stores a read-optimized projection for Registry pages, so a catalog result never needs to download a thousand-field document.
titleThe public and hosted title. Required.
descriptionExplain the obligation, decision, or procedure in plain language. Required.
jurisdictionsOne or more controlled values: GLOBAL, EU, EEA, or ISO country codes such as SE and US.
legal_referencesA list of instrument, provision, and optional official HTTPS source_url entries.
Applicable law belongs in metadata. It is chosen by the author, validated at write and publication boundaries, and never delegated to the respondent.
04 · Fields
Definitions are facts, controls, and outcomes.
Each key is the stable field ID used by rules and recorded responses. Labels can change across legal periods; IDs and structural types cannot.
| Type | Hosted control | Use it well |
|---|---|---|
string | Text input or textarea | Set multiline: true for longer answers. |
number | Number input | Supports min, max, and step. |
currency | Money input | A numeric value with money-focused presentation. |
boolean | Yes / no toggle | Also makes the schema checklist-compatible. |
select | Choice list | Requires a non-empty options array. |
date | Calendar-date picker | Values use YYYY-MM-DD, without a time zone. |
attestation | Confirmation toggle | A respondent confirmation, distinct from rich provider sign-offs. |
placeholderAn example of what belongs in an empty control.
infoStable instructions shown behind the information control.
ui_messageContext that appears only after a rule changes the field.
Other supported presentation and validation properties include label, required, value, visible, readonly, min, max, step, min_length, max_length, pattern, and ui_class.
05 · Rules and messages
A rule says when, then preserves why.
logic_tree is ordered. Every rule needs a stable id, a condition under when, and actions under then. Add law_ref at rule level when a branch comes from a precise provision.
{
"id": "notification_required",
"law_ref": "Example Regulation, Article 12",
"when": {
"and": [
{ ">=": [{ "var": "impact_score" }, 3] },
{ "==": [{ "var": "authority_notified" }, false] }
]
},
"then": {
"ui_modify": {
"authority_notified": {
"required": true,
"ui_message": "This impact level requires notification."
}
},
"error_msg": "Notify the authority before completing this Flow."
}
}An error_msg without error_kind is a constraint violation and prevents READY.
Set error_kind to notice when the record may complete while preserving a warning or next step.
06 · Calculated outcomes
Derive an outcome without asking for it.
A calculated value needs a matching definition and a state_model.derived expression. Make the definition readonly; set visible to true when respondents should see the result.
"definitions": {
"impact_score": { "type": "number", "required": true },
"outcome": {
"type": "string",
"label": "Reporting outcome",
"readonly": true,
"visible": true
}
},
"state_model": {
"inputs": ["impact_score"],
"derived": {
"outcome": {
"eval": {
"if": [
{ ">=": [{ "var": "impact_score" }, 3] },
"notification_required",
"document_only"
]
}
}
}
}A schema becomes Determination-compatible only when every temporal period retains at least one visible calculated output and an editable fact.
07 · Legal time periods
Version the release. Route the law by date.
version tells consumers which immutable document they use. temporal_map tells the engine which interpretation applies on the record’s effective_at calendar date.
"temporal_map": [
{
"valid_range": ["2025-01-01", "2025-12-31"],
"logic_version": "rules_2025",
"definition_overrides": {
"impact_score": { "label": "2025 impact score", "max": 5 }
}
},
{
"valid_range": ["2026-01-01", null],
"logic_version": "rules_2026",
"definition_overrides": {
"impact_score": { "label": "Current impact score", "max": 4 }
}
}
]- Ranges are inclusive. Consecutive periods must not overlap or leave a gap.
- Use
nullfor an open beginning or end. - Period overrides may change presentation and constraints, derived expressions, or rich sign-offs—but not field IDs or structural types.
- Give period-specific rules the matching
logic_version. Rules without one run in every period. - Do not add a top-level
valid_from. The completed record preserves the exact date, rule set, and selected range.
08 · Flow compatibility
ProseID calculates compatibility. The JSON does not claim it.
Do not add compatible_surfaces to schema code. Publication runs engine and hosted-renderer checks against every time period, then freezes only the experiences safe across the entire release.
At least one visible field a respondent can edit.
The same editable foundation, shown one relevant question at a time.
An editable fact plus a visible calculated output.
An editable foundation plus a visible yes/no or confirmation control.
A valid executable document, including schemas unsuitable for a hosted Flow.
09 · Operator reference
The supported expression vocabulary.
Every expression object has one operator key. Use arrays for operands and { "var": "field_id" } to read a field or calculated value.
==!=><>=<=
andornot!
if
+-*/
beforeafter
insomeallnone
var
Unknown operators are treated as publication errors. Use the engine-supported vocabulary rather than relying on another JSON-Logic implementation’s extensions.
10 · Common errors
When code does not save or publish.
Unexpected characterThe JSON is malformed. Use the editor’s line and column location; common causes are a trailing comma, a missing quote, or two root objects pasted together.
Metadata needs…Include all four metadata properties and use controlled uppercase jurisdiction codes.
Undefined variableA var references a field or calculated value that does not exist under definitions.
Required field not fillableA required field is hidden or read-only without a default, calculation, or rule that supplies it.
Time-period gap or overlapMake each range meet the next one without sharing a date. For example, end 2025-12-31 and start 2026-01-01.
Hosted value unsupportedAn initial value has the wrong scalar type or a selected default is absent from its options.
11 · Complete example
Paste, rename, and replace the interpretation.
This example intentionally includes Registry metadata, long-form text, a calculated outcome, a checklist control, a temporal rule set, contextual guidance, and a blocking validation rule. Its law is fictional; replace every legal statement and source before publication.
{
"protocol": "proseid/1.0",
"schema_id": "example_incident_triage",
"version": "1.0.0",
"metadata": {
"title": "Example incident-notification triage",
"description": "Determines whether an example incident enters a notification track and records the action taken.",
"jurisdictions": ["GLOBAL"],
"legal_references": [
{
"instrument": "Example Regulation",
"provision": "Article 12",
"source_url": "https://example.com/regulation"
}
]
},
"definitions": {
"incident_summary": {
"type": "string",
"label": "What happened",
"required": true,
"multiline": true,
"placeholder": "Describe the incident and affected service",
"info": "Record operational facts without copying sensitive records into this answer."
},
"impact_score": {
"type": "number",
"label": "Impact score",
"required": true,
"min": 0,
"max": 4,
"step": 1,
"placeholder": "For example: 3"
},
"authority_notified": {
"type": "boolean",
"label": "Authority notified",
"value": false
},
"outcome": {
"type": "string",
"label": "Reporting outcome",
"readonly": true,
"visible": true
}
},
"state_model": {
"inputs": ["impact_score"],
"derived": {
"outcome": {
"eval": {
"if": [
{ ">=": [{ "var": "impact_score" }, 3] },
"notification_required",
"document_only"
]
}
}
}
},
"temporal_map": [
{
"valid_range": ["2026-01-01", null],
"logic_version": "rules_2026"
}
],
"logic_tree": [
{
"id": "notification_required",
"logic_version": "rules_2026",
"law_ref": "Example Regulation, Article 12",
"when": {
"and": [
{ ">=": [{ "var": "impact_score" }, 3] },
{ "==": [{ "var": "authority_notified" }, false] }
]
},
"then": {
"ui_modify": {
"authority_notified": {
"required": true,
"ui_message": "This impact score enters the notification track."
}
},
"error_msg": "Notify the authority before completing this Flow."
}
}
],
"attestations": {}
}