Rundunrundun

Template Definition Language (TDL)

TDL is the JSON schema that defines all Rundun checklist templates. It is the anchor for everything — the API, the mobile renderer, AI generation, and webhook payloads all derive from it.

Why TDL exists

Checklists need to work across multiple surfaces: a visual editor on web and mobile, a React Native renderer that shows the right UI control for each step type, an AI generator that creates templates from natural language, and webhook payloads that carry step answers in a predictable shape. TDL is the single source of truth that makes all of this possible.

  • Humans author templates via a visual editor — they never write TDL JSON by hand
  • AI authors and modifies templates by reading and writing TDL JSON directly
  • IDs are always auto-generated — never typed manually
  • The template is snapshotted verbatim when a run is created — future template edits do not affect in-progress runs

Structure

A template is a JSON object with metadata, settings, sections, and steps. Sections are optional — a template with no sections renders as a flat step list.

template
└── sections[]
    └── steps[]
        └── condition (optional)
        └── photo overlay (optional)
        └── config (type-specific)

Minimal complete example

A template with one section, a boolean step, and a photo step:

{
  "id": "t-550e8400-e29b-41d4-a716-446655440000",
  "v": 1,
  "name": "Unit ready check",
  "description": "Quick confirmation before guest arrival",
  "tags": ["STR", "turnover"],
  "settings": {
    "allow_skip": false,
    "signature_on_complete": false,
    "voice": false,
    "est_minutes": 3
  },
  "sections": [
    {
      "id": "g-unt1",
      "title": "Unit condition",
      "description": "Walk through each area before marking ready",
      "steps": [
        {
          "id": "s-cl01",
          "type": "boolean",
          "label": "Is the unit clean and ready for the next guest?",
          "hint": "Check all rooms, bathroom, and kitchen",
          "required": true,
          "photo": false,
          "geo": false,
          "voice_prompt": "Is the unit clean and ready for the next guest?",
          "condition": null,
          "config": {
            "true_label": "Yes, ready",
            "false_label": "No, needs attention"
          }
        },
        {
          "id": "s-ph01",
          "type": "photo",
          "label": "Photo of the living area",
          "hint": "Take a wide shot from the entrance",
          "required": true,
          "photo": false,
          "geo": false,
          "voice_prompt": null,
          "condition": null,
          "config": {
            "min": 1,
            "max": 3,
            "annotate": false
          }
        }
      ]
    }
  ],
  "execution": {
    "scope": "any",
    "identity_required": "none"
  }
}

Top-level fields

Field Set by Description
id System Auto-generated on template creation (t-{uuid})
v System Integer, incremented on each save
name Human / AI Template name shown to creator and executor
description Human / AI Optional subtitle
tags Human / AI For search and categorization
settings Human / AI Template-wide behavior toggles
sections Human / AI Ordered array of section objects
execution Human Who can execute and how identity is captured

Settings fields

Field Type Description
allow_skip boolean Whether non-required steps can be explicitly skipped
signature_on_complete boolean Prompt executor for a final signature after all steps
voice boolean Enable voice guidance (post-MVP — set to false)
est_minutes number Estimated completion time shown to executor

ID conventions

Entity Format Example Scope
Template t-{uuid} t-550e8400-e29b-41d4-a716-446655440000 Global
Run r-{uuid} r-550e8400-e29b-41d4-a716-446655440000 Global
Section g-{4 alphanum} g-unt1 Template-scoped
Step s-{4 alphanum} s-cl01 Template-scoped
Option o-{4 alphanum} o-fu1 Step-scoped
  • g = group (section), s = step, o = option
  • 4 alphanum = 1.6M combinations — sufficient for template-scoped IDs
  • Global resources use UUID to guarantee uniqueness without coordination

Step envelope

Every step shares the same base structure regardless of type:

{
  "id": "s-f1c4",
  "type": "boolean",
  "label": "Front bumper clean?",
  "hint": "Look for dents, scratches, or cracks",
  "required": true,
  "photo": false,
  "geo": false,
  "voice_prompt": "Is the front bumper clean and undamaged?",
  "condition": null,
  "config": {}
}
Field Description
id Auto-generated step ID (s-{4alphanum})
type Step type — determines config shape and UI control
label The question or instruction shown to the executor
hint Optional secondary text shown below the label
required If true, step must be answered to complete the run
photo false (no camera) or { min, max, annotate } (photo overlay)
geo true to capture GPS when the step is answered
voice_prompt Text spoken aloud in voice mode (post-MVP)
condition Show/hide rule based on a prior step's answer — see Conditions
config Type-specific options — see Step types

Execution settings

execution is a top-level object on the template that controls who can execute it:

"execution": {
  "scope": "any",
  "identity_required": "none"
}

scope

Value Effect
"any" Anyone with the link can execute (default)
"org_only" Only org members (any role) can execute

identity_required

Value Effect
"none" Fully anonymous — no sign-in, no name (default)
"name" Executor enters their name. No Rundun account needed.
"email" Executor enters name + email. No Rundun account needed.
"org_member" Must be a signed-in org member. Highest accountability.

scope: "org_only" implies identity_required: "org_member". Any other combination is valid.

Further reading

  • Step types — all 11 step types with config fields and examples
  • Conditions — conditional step visibility
  • Photos — photo overlay, upload flow, and webhook delivery