ambleloft

Declarative business forms: from skill to multi-step flow

Declare fields, steps and submission in a skill so the host can render a business form in chat. Build a three-step travel expense form and follow its configuration, model calls and submitted data.

PRACTICAL GUIDE

Outcome: Create and import a three-step business form, then verify drafts, navigation and frozen submission data.

Before you begin: Prepare your own skill directory, create the files below and import it into the app. The chat submission example needs no demo extension, SDK or business server.

On this page

01How the form is defined

The developer defines the business entry point in a skill and specifies fields, validation, steps and submission in YAML. The agent discovers and presents the appropriate template. The host renders it, saves drafts, validates entries and handles user clicks. Confirmed data goes to chat or a business operation as configured. The model does not invent the fields for this business form.

  1. 01Developer

    Skill + YAML define the rules

  2. 02Agent

    Discover and present a template

  3. 03Host

    Render, validate, freeze submission

  4. 04Your service

    Handle business logic via extensions

021. Create your skill

Start with a standalone skill you can import. This example requires neither a demo extension nor a business server. Create the two files below, import the travel-expense directory through skill management and enable it. To ship it in an extension, register its relative directory in extension.json, for example "skills": ["skills/travel-expense"].

Code example
travel-expense/
  SKILL.md
  forms/
    travel.yaml

032. Register the template in SKILL.md

Save this as SKILL.md. amble-form-ref must be a top-level fenced code block. Its path is relative to the skill directory and cannot escape it or use symlinks. A top-level amble-form block can contain YAML directly instead. Mentioning a filename in prose does not register a template.

Code example
---
name: travel-expense
description: Collect travel expenses with a three-step form and prepare an application draft.
---
When the user wants to record travel expenses:
1. Call forms_capabilities and check singleClickChat=1 and readSubmission=1.
2. Call forms_list, find this skill's travel-expense template and use its actual returned key.
3. Call forms_present, optionally prefilling facts already provided in chat. Do not redraw the form in Markdown or submit for the user.
4. Wait for the user submission event, then call forms_read_submission with its submissionId.
5. Use the frozen values to prepare an application draft. Sending to chat does not submit to a finance system.

```amble-form-ref
path: forms/travel.yaml
```
View the complete SKILL.md

043. Define the complete three-step form

Save this YAML as forms/travel.yaml. It collects trip details, expenses and confirmation in order. Intermediate steps omit next, so validation leads directly to the next step. Only the final Send application details button sends to chat. The review step contains instructions and a confirmation checkbox; it does not automatically render a summary of earlier fields.

CONFIGURATION ↔ UI ↔ DATA

Try the three-step form

Browser teaching demo of the YAML below. Sample data lives in memory. It calls no host or business service and resets on refresh.

  1. 1Trip
  2. 2Expenses
  3. 3Review
forms/travel.yaml · Trip
  - id: itinerary
    title: Trip
    fields:
      - name: destination
        type: text
        label: Destination
        required: true

Travel expense registration

Step 1 of 3 · Trip

The first two steps update the draft. Confirm the final step to see the frozen data illustration.

Expand the complete YAML · Ready to save
forms/travel.yaml
version: 1
id: travel-expense
title: Travel expense registration
description: Review the details and send them to chat for an application draft.
steps:
  - id: itinerary
    title: Trip
    fields:
      - name: destination
        type: text
        label: Destination
        required: true
  - id: expenses
    title: Expenses
    fields:
      - name: amount
        type: money
        label: Amount
        currency: CNY
        scale: 2
        minimum: "0.01"
        required: true
      - name: note
        type: textarea
        label: Expense note
        required: true
        maxLength: 500
  - id: review
    title: Review
    description: Return to the previous steps to check your entries before sending.
    fields:
      - name: confirmed
        type: checkbox
        label: I have checked my entries
        required: true
submit:
  kind: chat
  label: Send application details
  confirmation: onSubmit
View the complete YAML

05Field and step rules

version is 1 and id is the stable template identifier. A single-step form uses root fields, normalized to a step named main. A multi-step form uses steps; do not include root fields as well. step.id and field.name address data, while title and label are displayed. Supported types are text, textarea, number, money, date, select, checkbox, switch and group-toggle; check forms_capabilities for optional features. Money uses decimal strings, dates use valid YYYY-MM-DD values, and selects submit option.value. Limits are 20 steps, 100 fields in total and 128 KiB of YAML.

Read the field and action reference

064. Have the agent present the form

Ask “Help me record my travel expenses” in chat. After reading the skill, the agent calls forms_capabilities and forms_list, then forms_present with a returned key. The example below shows forms_present arguments; replace the key and prefill only known business information. Prefill is grouped by step ID. Presentation immediately returns {id,status}; it neither waits for input nor means submission is complete.

Code example
{
  "key": "REPLACE_WITH_FORMS_LIST_KEY",
  "prefill": {
    "itinerary": {
      "destination": "Shanghai"
    },
    "expenses": {
      "amount": "120.00"
    }
  }
}

075. Follow the data from entry to submission

User edits create host-persisted drafts. Next validates the current visible fields and records that step’s values. Saving or navigating does not send a chat message. On final submission, the host freezes values, initialValues, touched, the template and source identity, then delivers a message with submissionId to the current chat. The agent calls forms_read_submission to read that frozen record and continue the task.

Code example
SKILL.md + YAML
  → forms_list: discover registered templates
  → forms_present: create and prefill an instance
  → user edits: drafts → step validation
  → final user submission: frozen data + submissionId
  → current chat: forms_read_submission
  → agent: prepare a draft from confirmed data

08Read structured answers

This is a partial excerpt from forms_read_submission, not the full receipt. values contains validated answers by step. initialValues records the supplied creation-time prefill. touched uses stepId.fieldName keys; true means the user edited the field, even if they restored its original value. A missing touched key does not mean the user explicitly disabled anything. deliveryStatus describes delivery, not acceptance by a business system.

Code example
{
  "values": {
    "itinerary": {
      "destination": "Shanghai"
    },
    "expenses": {
      "amount": "120.00",
      "note": "Local transport"
    },
    "review": {
      "confirmed": true
    }
  },
  "initialValues": {
    "itinerary": {
      "destination": "Shanghai"
    },
    "expenses": {
      "amount": "120.00"
    }
  },
  "touched": {
    "expenses.note": true,
    "review.confirmed": true
  }
}

096. Going back, dependencies and confirmation

Going back retains saved drafts. Editing earlier values invalidates affected step results and required confirmations; it does not undo business operations already performed. dependsOn and visibleWhen reference previously declared stepId.fieldName values. Dependent inputs are retained but require review after upstream changes. Hidden fields retain their draft but are excluded from final answers. Arbitrary expressions and remote dynamic options are not supported. This example uses confirmation: onSubmit, so the final click confirms chat delivery. Omitting it uses an additional confirmation; operation permissions are unaffected.

107. Use operations when connecting a business service

A standalone skill can use chat submission. To save a business draft at an intermediate step or submit to a finance service, an extension must declare and implement its own operations in manifest.operations with page in exposeTo. Use next.kind: operation between steps and submit.kind: operation at the end. input.from supports steps.<step>.<field>, earlier results.<step>.<top-level-result-field> and context.projectId. The fragment below replaces submit; it does not provide an executable backend.

Code example
submit:
  kind: operation
  label: Submit expense
  operation: example.expense.submit
  input:
    destination: {from: steps.itinerary.destination}
    amount: {from: steps.expenses.amount}
    note: {from: steps.expenses.note}
  recovery:
    operation: example.expense.lookupSubmission

11Write results and recovery

Write operations require a read-only recovery operation in the same extension. The host injects submissionId and other form identity into InvocationContext.form. The business service deduplicates within the real user, tenant and operation scope. requestId is not a substitute for submissionId. Reconcile unknown outcomes before retrying a write. Recovery returns succeeded with result, notExecuted or unknown. Return notExecuted only when the service can prove no execution occurred and the old request cannot later cause an effect.

Implement business operations

128. Verify your skill

After importing and enabling the skill, verify that forms_list includes its template. If missing, inspect top-level blocks, reference paths and YAML validation errors. Trigger it in chat and check prefill, required fields and navigation across all three steps. The first two steps must not deliver messages. After submission, check frozen values, decimal-string amounts and submissionId. Restart and inspect saved records. Updating or disabling the skill can invalidate old instances and submissions; present a fresh form. Passing this chat example does not verify business-server writes or arbitrary model behavior.

13Editors and collections use a separate contract

The business forms on this page use amble-form and forms_* tools. Selectable data collections and editors use UI templates and ui_* tools, with different flow receipts and submission data. These contracts are not interchangeable. General follow-up questions use the separate input_* tools and are outside this defined business-form workflow.

Continue to editors and collections

Check the result and troubleshoot

Create and import a three-step business form, then verify drafts, navigation and frozen submission data.

Check actual results using this page’s verification steps. For business integrations, inspect UI submission, tool receipts and server records separately.

Open the error reference →
SDK / CLI 0.1.0-alpha.9 · Contract baseline Compatibility and preview notes · Sample source