Add Adaptive Card
Add an AdaptiveCardPrompt node to an existing Copilot Studio topic. Use this for all Adaptive Card scenarios — display-only cards, input forms, and confirmation flows.
Instructions
-
Auto-discover the agent directory:
Glob: agents/**/agent.mcs.ymlNEVER hardcode an agent name.
-
Clarify requirements from the user if not specified:
- Which topic should the card be added to?
- Which card type (form, info, confirmation)?
- What fields, labels, and placeholders are needed?
- Which topic variables should receive the submitted values?
-
Read the target topic file to understand its structure and find the correct insertion point.
-
Verify the schema if needed:
bash# Copilot Studio node schema node ${CLAUDE_SKILL_DIR}/../../scripts/schema-lookup.bundle.js summary AdaptiveCardPrompt # Adaptive Cards element schema (v1.6 — the version supported by Copilot Studio) node ${CLAUDE_SKILL_DIR}/../../scripts/schema-lookup.bundle.js ac-summary TextBlock node ${CLAUDE_SKILL_DIR}/../../scripts/schema-lookup.bundle.js ac-summary Input.Text node ${CLAUDE_SKILL_DIR}/../../scripts/schema-lookup.bundle.js ac-search Action -
Select and adapt the template from card-templates.md matching the requested type.
-
Generate unique IDs for all new nodes (format:
<nodeType>_<6-8 random alphanumeric>). -
Insert the node(s) at the correct position in the
actionsarray using Edit. -
Validate the updated topic file:
bashnode ${CLAUDE_SKILL_DIR}/../../scripts/schema-lookup.bundle.js validate <topic-file.yml> -
Inform the user that they must push (VS Code Extension) and publish (Copilot Studio UI) before testing with
/chat-with-agentor/run-tests.
AdaptiveCardPrompt Structure
AdaptiveCardPrompt is the correct node kind for all Adaptive Cards in Copilot Studio. The card JSON is embedded as a multiline YAML literal string under card: |.
yaml- kind: AdaptiveCardPrompt id: adaptiveCardPrompt_m9Kp2x card: | { "type": "AdaptiveCard", "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.5", "body": [...], "actions": [...] } output: binding: fieldId: Topic.MyVariable outputType: properties: fieldId: type: String
Rules:
card: |— the literal block scalar is mandatory. Do not usecard: >or inline the JSON without it.$schemaandversionare required inside the card JSON.- The
output.bindingmaps each card inputidto a topic variable (Topic.VarName, no=prefix). outputType.propertiesmust declare a type for every bound field.- Use plain
binding:— nokind:property inside it. - Every
AdaptiveCardPromptmust haveoutput,outputType, and anAction.Submitbutton — including display-only info cards. Omitting any of these causes VS Code extension errors (MissingRequiredProperty,AdaptiveCardMissingActionSubmit). - For info cards with no meaningful inputs, add an
Action.Submit(e.g. "OK") and bind a dummy acknowledgement variable (Topic.CardAcknowledged, typeString).
Node Comparison
| Node | Use When |
|---|---|
AdaptiveCardPrompt | Any Adaptive Card — with or without input fields |
SendActivity | Plain text messages with optional {} variable interpolation |
Do NOT use SendActivity with an attachments array for Adaptive Cards.
Field Validation
Do NOT use style: "Email" or style: "Tel" for validation — these only change the mobile keyboard and do not validate on submit. Always use regex:
json{ "type": "Input.Text", "id": "email", "label": "Email address", "placeholder": "Enter your email address", "isRequired": true, "regex": "^[a-zA-Z0-9._%+\\-]+@[a-zA-Z0-9.\\-]+\\.[a-zA-Z]{2,}$", "errorMessage": "Enter a valid email address" }
json{ "type": "Input.Text", "id": "mobile", "label": "Mobile number", "placeholder": "Enter your mobile number", "isRequired": true, "regex": "^[+]?[0-9][\\s\\-\\(\\)0-9]{6,14}$", "errorMessage": "Enter a valid mobile number" }
| Approach | Validates on submit? | Notes |
|---|---|---|
regex | Yes — blocks submit if pattern fails | Use for email, phone, any format |
isRequired: true | Yes — blocks submit if empty | Mandatory fields |
style: "Email" | No | Keyboard hint only — never use for validation |
style: "Tel" | No | Keyboard hint only — never use for validation |
Rule: Every
Input.ChoiceSet(and any required input) must have alabelproperty, or the VS Code extension raisesAdaptiveCardInputIsRequiredMissingLabel.
Output Binding
- Card input
idvalues must exactly match the keys inoutput.binding. - Topic variable references:
Topic.VariableName(no=prefix). - Declare every bound field in
outputType.propertieswith its type.
yamloutput: binding: userName: Topic.UserName userEmail: Topic.UserEmail category: Topic.Category outputType: properties: userName: type: String userEmail: type: String category: type: String
Dynamic Text Around Cards
Card JSON is static — Power Fx expressions and {} interpolation do not work inside the card body. Use SendActivity before or after AdaptiveCardPrompt for dynamic content:
yaml- kind: SendActivity id: sendMessage_Rz4Wq1 activity: "Hello {Topic.UserName}, please complete the form below." - kind: AdaptiveCardPrompt id: adaptiveCardPrompt_m9Kp2x card: | { ... }
Card Types Quick Reference
| Type | Has inputs? | Has output? | Template |
|---|---|---|---|
form | Yes | Yes | Form Card |
info | No (dummy acknowledgement) | Yes (always required) | Info Card |
confirmation | Yes (ChoiceSet) | Yes | Confirmation Card |
For full YAML examples of each type, see card-templates.md.


