itential-json-forms skill
Build and manage structured input forms with static, REST-bound, and cascading dropdowns for IAP manual triggers and workflows.
- GitHub stars
- 18
- Files
- 12
- Last commit
- Nov 5, 2026
- License
- GPL-3.0
- Allowed tools
- —
What does the itential-json-forms skill do?
itential-json-forms builds and manage structured input forms with static, REST-bound, and cascading dropdowns for IAP manual triggers and workflows.
Summary generated from the skill's SKILL.md.
About the itential-json-forms skill
Developers building structured input panels for IAP manual triggers and workflows can use this skill to create and manage JSON forms. It allows for the generation of forms containing static dropdowns with hardcoded values, REST-bound dropdowns that pull live data from IAP endpoints, and cascading dropdowns where one field's selection dynamically updates the options in another.
An agent should load this skill when it needs to define or update form schemas, validate form structures without saving them, or list existing forms. The skill relies on four cooperating schemas: struct for UI rendering, schema for data validation, uiSchema for widget hints, and bindingSchema for live-data connections. It provides specific tools for managing these definitions, including endpoints for bulk deletion, full replacement updates, and a validation service that checks for errors and warnings. Users can also discover bindable endpoints via a dedicated method-options tool to ensure REST-bound fields function correctly.
What an agent can do with it
- 1Build cascading field dependenciesDevelop a form where selecting a site automatically filters the available devices in a second dropdown.
- 2Validate form integrityCheck a new form definition for schema errors and warnings before committing it to the server.
- 3Sync dropdowns with live dataConfigure a dropdown to fetch real-time inventory or configuration data from an IAP endpoint.
Written from the skill's SKILL.md. Every use case is checked against a quote from it.
How to install the itential-json-forms skill
Each command copies the skill folder into the client's skills directory. Restart the client or start a new session to load it.Install the itential-json-forms skill in Plugin
/plugin marketplace add itential/builder-skills /plugin install itential-builder@itential-builder
Install the itential-json-forms skill in Claude Code
~/.claude/skills/itential-json-forms/SKILL.md
$ npx degit itential/builder-skills/skills/itential-json-forms ~/.claude/skills/itential-json-formsInstall the itential-json-forms skill in Claude Code (project)
.claude/skills/itential-json-forms/SKILL.md
$ npx degit itential/builder-skills/skills/itential-json-forms .claude/skills/itential-json-formsInstall the itential-json-forms skill in Codex
~/.agents/skills/itential-json-forms/SKILL.md
$ npx degit itential/builder-skills/skills/itential-json-forms ~/.agents/skills/itential-json-formsInstall the itential-json-forms skill in Gemini CLI
~/.gemini/skills/itential-json-forms/SKILL.md
$ npx degit itential/builder-skills/skills/itential-json-forms ~/.gemini/skills/itential-json-formsInstall the itential-json-forms skill in Claude.ai
npx degit itential/builder-skills/skills/itential-json-forms itential-json-forms && zip -r itential-json-forms.zip itential-json-forms # claude.ai → Customize → Skills → + → Create skill → Upload a skill → itential-json-forms.zip
SKILL.md
View on GitHubJSON Forms (itential-json-forms)
JSON Forms are reusable form definitions stored in the json-forms application. They drive structured input panels across IAP — manual triggers in Operations Manager, the JsonForms/ShowJsonForm manual task, and any workflow surface that prompts a user for typed input.
A form is a single document with four cooperating schemas — struct (UI rendering), schema (data contract / validation), uiSchema (per-field widget hints), and bindingSchema (live-data binding for REST dropdowns). Get the relationships wrong and the form will render but break silently at runtime.
Customization
Before using this skill, check custom/org/, custom/team/ and custom/dev/
in this skill's own folder. Read every .md file found — any folder may be
empty or absent. Apply them on top of everything below; where a file overrides a
specific rule here, follow the override. More specific wins: dev > team > org >
this document. No customization may weaken this skill's safety
rules or put credentials in committed files.
Bundled files: paths in this skill that start with assets/ or scripts/ are
relative to this skill's own folder. When you read one, or pass one to a shell
command (which runs from the user's working folder), use this skill's folder +
that relative path — e.g. <this skill's folder>/assets/helpers/create/create-workflow.json.
Concepts
struct— the UI definition.struct.typeis always"array";struct.items[]is the list of fields.customKeyon each field becomes the property key inschemaand the variable key when the form's data is consumed.schema— the data contract.schema.properties.<customKey>must exist for every field instruct.items[](and stay in sync with the field's type, enum values, etc.).schema.requiredlists mandatorycustomKeys.uiSchema— per-customKeywidget hints: placeholder text,ui:widgetoverrides, disabled flags. Required for cascading dropdowns (see below).bindingSchema— empty{}for static-enum forms; see REST-bound dropdowns below for the mirroring requirement when a field is REST-bound.- Static vs. REST-bound dropdowns — static dropdowns hardcode the list via
enum/enumNames. REST-bound dropdowns pull options live from an IAP endpoint at form-render time. - Cascading dropdowns (aka field dependency in the Studio UI) — a REST-bound dropdown whose URL path parameter is filled from another field's current value. The dependent field re-fetches when the source field changes.
API Reference
| Method | Endpoint | Description |
|---|---|---|
| GET | /json-forms/forms |
List all JSON forms |
| GET | /json-forms/forms/{id} |
Fetch a single form |
| POST | /json-forms/forms |
Create a JSON form |
| POST | /json-forms/validate |
Validate a form without saving it — body {"asset": {<the form>}} (see Validate below) |
| PUT | /json-forms/forms/{id} |
Update a JSON form (full replacement — see Update below) |
| DELETE | /json-forms/forms |
Bulk delete — body {"ids":["...","..."]}. There is no per-id DELETE endpoint; per-id calls 404. |
| GET | /automation-studio/json-forms/method-options |
Canonical list of bindable endpoints (same list Studio shows in its dropdown picker) |
Create a JSON Form
POST /json-forms/forms
Choose the helper that matches your form's dropdown needs:
| Use case | Annotated scaffold (fill in the blanks) | Real export (read to see the actual shape) |
|---|---|---|
| Static-enum dropdowns only (hardcoded option lists) | assets/helpers/create/create-json-form.json |
assets/helpers/assets/json-form-example-static-enum.json — real Cisco IOS "Port Turn Up" form, 8 fields incl. static dropdown, number updown widgets, ipv4 format validation |
| REST-bound dropdowns (live data from IAP endpoints) | assets/helpers/create/create-json-form-rest-bound.json |
assets/helpers/assets/json-form-example-rest-bound.json — real Cisco IOS "Compliance" form, one REST-bound dropdown pulling tree names live from GET /configuration_manager/configs |
| Cascading dropdowns (field dependency) | assets/helpers/create/create-json-form-rest-bound.json (Inventory Manager Site/Device cascade worked example) |
(no real cascading export on hand yet — the scaffold is hand-built but follows the same field shapes as the two real exports above) |
| Array-of-objects field (a list of rows, each with its own fields) | assets/helpers/create/create-json-form-array-field.json |
(no real export on hand yet — hand-built; every field, including the nested ones, has its own nodeId) |
The scaffolds are annotated with _comment_* fields to fill in; the real exports are genuine POST /json-forms/forms payloads pulled from a live platform (IDs/timestamps/createdBy stripped since the server assigns those on create) — read one when you want to see exactly what a working form looks like end-to-end, not just the shape.
Static-enum dropdowns
enum/enumNames arrays appear in both struct.items[i] and schema.properties.<customKey> — they must stay in sync.
struct.items[i].enum/enumNamesare arrays of{id, label, value}objects.schema.properties.<customKey>.enum/enumNamesare flat string arrays of the same values (not objects).
Leave bindingSchema: {} for static-enum forms.
REST-bound dropdowns
When options should reflect live platform state (devices, inventories, projects, templates) instead of a hardcoded list, the dropdown pulls from a GET against an IAP endpoint at render time. Three things must line up:
struct.typeMUST be"array"(not"object"). The static-enum scaffold uses"array"too — keep it.bindingSchema.properties.<customKey>must mirror every REST-bound field. Studio reverse-engineersbindingSchemafromstructin the GUI, but the server does not — leavingbindingSchema: {}produces dropdowns that render but never fetch.- Endpoint discovery:
GET /automation-studio/json-forms/method-optionsreturns the canonical list of bindable endpoints — the same list Studio shows in its dropdown picker.
Per-field shape in struct.items[i]:
{
"type": "string",
"title": "Site",
"binding": true,
"rel": "collection",
"targetPointer": "/enum",
"method": "GET",
"base": "/inventory_manager",
"href": "/v1/inventories",
"sourcePointer": "/result/data",
"sourceKeyPointer": "/name",
"customKey": "site"
}
base + hrefis the endpoint.sourcePointeris a JSON pointer into the response, walked to the array of items.sourceKeyPointeris the per-item field that becomes BOTH the value and the label.labelKeyPointeris unused — both columns come fromsourceKeyPointer.
Cascading dropdowns (aka field dependency)
The Studio UI labels this pattern field dependency; the form JSON calls it cascading. Same feature, two names. A REST-bound dropdown whose URL path parameter is filled from another field's value (e.g., dropdown 2 lists devices from the inventory selected in dropdown 1):
- The dependent dropdown's
hrefstays as a TEMPLATE with placeholders:/v1/inventories/:inventoryIdentifier/nodes. Path params use:namecolon syntax, NOT{name}curly braces. - A
variablesarray maps each placeholder to a JSON pointer into form data:[{"name": "inventoryIdentifier", "reference": "/site"}]substitutes:inventoryIdentifierwith whatever value the field whosecustomKeyissitecurrently holds. - The same
variablesarray must appear in both places:struct.items[i].variablesbindingSchema.properties.<dependentKey>.binding:hyperSchema.links[0].variables
- Both the source and the dependent field need
ui:widget: "DependencyWidget"inuiSchema— without it, the runtime will not re-fetch when the source changes.
Validate a form before saving
POST /json-forms/validate
Send the form wrapped in asset: {"asset": {<the form>}} — without the wrapper every form fails. Returns {"isValid": true|false, "errors": [], "warnings": []}; check both errors and warnings. It saves nothing, so call it as often as needed, with or without the read-only fields (id, created, createdBy, lastUpdated, lastUpdatedBy). It catches a missing top-level nodeId but not a missing nested one (see Common Gotchas).
Update a JSON Form
PUT /json-forms/forms/{id}
- Body MUST be wrapped in
{"options": {...}}. - Include ALL fields the form already has:
created,createdBy,lastUpdated,lastUpdatedBy,name,description,struct,schema,uiSchema,validationSchema,bindingSchema,version. - This is a full replacement — omitting any field clears it.
Delete JSON Forms
Bulk-only:
DELETE /json-forms/forms
Body: {"ids": ["<id1>", "<id2>", ...]}
Per-id calls (DELETE /json-forms/forms/<id>) return 404 — the endpoint does not exist.
Wiring to a Manual Trigger
A JSON Form is consumed by an Operations Manager manual trigger that hands the user's form input to a workflow as job variables. See builder-agent for the trigger creation details.
Critical flag — legacyWrapper: false: The default is true, which wraps form field values under a formData object and breaks the mapping to workflow job variables. Set legacyWrapper: false so each form field maps directly to a workflow input variable by name (i.e., field customKey: "device_name" → job variable device_name).
Required trigger fields: name, type ("manual"), enabled, actionType ("automations"), actionId, formId, legacyWrapper.
Helper for the wired-up trigger: assets/helpers/create/create-ops-manager-trigger-manual.json.
Common Gotchas
struct.typeis"array", not"object". Forms with"object"render empty.bindingSchemamirroring is mandatory for REST-bound fields. Studio hides this in the GUI; an API-created form needs bothstruct.items[i]ANDbindingSchema.properties.<customKey>populated, or the dropdown renders and never fetches.:namecolon syntax inhref, not{name}. Curly-brace placeholders are silently ignored.enum/enumNamesflat-vs-object asymmetry. Instruct.items[i]they're{id, label, value}objects; inschema.properties.<customKey>they're flat string arrays.DependencyWidgetrequired on BOTH ends of a cascade. Easy to remember to set it on the dependent field and forget the source — without the source-side widget the dependent won't re-fetch.labelKeyPointeris a red herring. Don't bother setting it; both label and value come fromsourceKeyPointer.- Bulk DELETE has no per-id alternative. Always send
{"ids":[...]}to/json-forms/forms. - Every field needs its own
nodeId, including fields nested inside an array field'sitems. Use a unique UUID per field. WithnodeIds missing on nested fields, the create and update calls andPOST /json-forms/validateall accept the form, but saving it in the form designer fails withInvalid form struct: must NOT have additional properties. The validator flags a missing top-levelnodeIdonly, so check every nested field yourself.
See Also
builder-agentfor workflows that consume form output, manual-trigger wiring, and project-level component management.- Helper files in
assets/helpers/:assets/helpers/create/create-json-form.json— static-enum scaffoldassets/helpers/create/create-json-form-rest-bound.json— REST-bound + cascading scaffold (Inventory Manager Site/Device cascade worked example)assets/helpers/create/create-json-form-array-field.json— array-of-objects scaffold (every field, including nested ones, has anodeId)assets/helpers/create/create-ops-manager-trigger-manual.json— manual trigger that consumes a formassets/helpers/assets/json-form-example-static-enum.json— real export, static-enum (Cisco IOS Port Turn Up)assets/helpers/assets/json-form-example-rest-bound.json— real export, REST-bound (Cisco IOS Compliance)
Files in this skill
12itential-json-forms skill questions
How do I install the itential-json-forms skill in Claude Code?
Run npx degit itential/builder-skills/skills/itential-json-forms ~/.claude/skills/itential-json-forms. Claude Code loads skills from ~/.claude/skills (all projects) or .claude/skills (one project) and uses a skill when its description matches the task.
Which clients can use the itential-json-forms skill?
Any client that reads the Agent Skills format: Claude Code, Codex, Gemini CLI and claude.ai (upload as a ZIP). Scripts in the skill run only where the client allows code execution.
How do I create a cascading dropdown (field dependency)?
Use a REST-bound dropdown where the href uses colon syntax for path parameters (e.g., :name) and a variables array maps placeholders to form data. Both the source and dependent fields must have the DependencyWidget set in the uiSchema.
Why is my REST-bound dropdown rendering but not fetching data?
This usually happens because the bindingSchema does not mirror the REST-bound fields defined in the struct. For API-created forms, you must populate both.