Mind the Front Docs Examples For AI agents llms.txt

Widget catalogue

Every input the widget renders and the declaration that produces it.

An input is derived from the field declaration in submission.properties. A step lists field names; it never names an input kind.

KindDeclarationRenders asChecked before advancing
ChoiceoneOf of const + titlebuttons, or select in a formvalue is one of oneOf
Texttype: "string"input type="text"minLength, maxLength
Phoneformat: "phone"input type="tel"7–15 digits
Emailformat: "email"input type="email"local@domain.tld
Dateformat: "date"input type="date"YYYY-MM-DD
Appointmentformat: "date-time" + schedulegrid of slots by dayslot came from the grid

Applies to every kind:

In the declarationEffect
name in submission.requiredasterisk on the label; step will not advance while empty
placeholderhint inside the empty input
titlethe label, and the row label in summary
theme.primaryColoraccent of buttons, launcher and selected slot
meta.localelanguage of formatted dates and times

Choice

{
  "title": "Service",
  "oneOf": [
    {
      "const": "haircut",
      "title": "Haircut"
    },
    {
      "const": "beard",
      "title": "Beard trim"
    },
    {
      "const": "both",
      "title": "Haircut and beard"
    }
  ]
}

One declaration, two renderings, selected by the step:

StepRendering
"fields": ["service"]a row of buttons, one per option; the click advances the step
"fields": ["property_type", "rooms", "address"]select inside a form with a submit button

submitLabel sets the button text of the form rendering; default is Send.

Text

{
  "title": "Anything we should know",
  "type": "string",
  "maxLength": 200,
  "placeholder": "Optional"
}

Single line. maxLength is enforced as the visitor types; minLength on advance.

Phone

format: "phone": 7 to 15 digits after stripping spaces, +, -, (, ). Anything else is rejected.

{
  "title": "Phone",
  "type": "string",
  "format": "phone",
  "placeholder": "+44 7700 900000"
}

Email

format: "email": one @, a dot in the domain, no spaces.

{
  "title": "Email",
  "type": "string",
  "format": "email"
}

Date

format: "date": a calendar date without time or zone, YYYY-MM-DD.

{
  "title": "Preferred date",
  "type": "string",
  "format": "date"
}

Choose between date and appointment by what the business does with it: date states a preference the owner confirms later, appointment takes a slot.

Appointment

{
  "title": "Appointment time",
  "type": "string",
  "format": "date-time",
  "durationMinutes": 45,
  "timeZone": "Europe/London",
  "schedule": [
    {
      "days": [
        "mon",
        "wed",
        "thu"
      ],
      "from": "10:00",
      "to": "19:00"
    },
    {
      "days": [
        "fri"
      ],
      "from": "10:00",
      "to": "21:00"
    },
    {
      "days": [
        "tue"
      ],
      "from": "15:00",
      "to": "19:00"
    },
    {
      "days": [
        "sat"
      ],
      "from": "11:00",
      "to": "14:00"
    },
    {
      "days": [
        "sat"
      ],
      "from": "15:00",
      "to": "18:00"
    }
  ]
}

format: "date-time" with three required annotations: durationMinutes, schedule, timeZone. Slots are durationMinutes long and cover the next 14 days.

schedule rules:

RuleResult
{ "days": ["mon","wed"], "from": "10:00", "to": "19:00" }same hours on both days
two rules for sat, 11:00–14:00 and 15:00–18:00a break between them
a day absent from every ruleclosed that day
two overlapping rules for one dayrejected by flow-lint
from later than torejected by flow-lint
remaining window shorter than durationMinutesno slot offered in it

from and to are wall-clock time in timeZone; an offset such as 10:00+01:00 is rejected.

Picking a slot does not hold it: free time is the schedule minus the owner's calendar at the moment of asking, and the owner confirms the request.

Screens

Screens produce no values.

ScreenDeclarationBehaviour
messagetext, nexta bot line
summarytitle, fields, actionsrows of collected values, then the actions below
status_trackerentity, titlethe request status: new, confirmed or rejected

summary actions:

ActionEffect
confirmsends the request and goes to next; every required field must be filled by now
editreturns to the step in target, keeping every entered value
restartclears the dialogue and returns to flow.start
{
  "type": "summary",
  "title": "Check your booking:",
  "fields": [
    "service",
    "appointment",
    "name",
    "phone"
  ],
  "actions": [
    {
      "type": "confirm",
      "label": "Book it",
      "next": "status"
    },
    {
      "type": "edit",
      "label": "Change time",
      "target": "appointment"
    },
    {
      "type": "restart",
      "label": "Start over"
    }
  ]
}

Next: assembling these into a config.