sg-template-schema
This skill should be used when the user asks to "create template schema", "create nocode form", "nocode form", "sg nocode", "generate schema from variables.tf", "convert terraform to schema", or needs help creating input_schema.json and ui_schema.json for StackGuardian templates.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install hllvc-dotfiles-sg-template-schema
Repository
Skill path: .claude/skills/sg-template-schema
This skill should be used when the user asks to "create template schema", "create nocode form", "nocode form", "sg nocode", "generate schema from variables.tf", "convert terraform to schema", or needs help creating input_schema.json and ui_schema.json for StackGuardian templates.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: hllvc.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install sg-template-schema into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/hllvc/dotfiles before adding sg-template-schema to shared team environments
- Use sg-template-schema for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: sg-template-schema
description: This skill should be used when the user asks to "create template schema", "create nocode form", "nocode form", "sg nocode", "generate schema from variables.tf", "convert terraform to schema", or needs help creating input_schema.json and ui_schema.json for StackGuardian templates.
version: 0.1.0
---
# StackGuardian Template Schema Generator
This skill helps create JSON Schema files (`input_schema.json` and `ui_schema.json`) for StackGuardian no-code forms. The primary use case is converting Terraform `variables.tf` to JSON Schema, but it also supports generic workflow step templates.
## Overview
StackGuardian uses two schema files to generate no-code forms:
1. **input_schema.json** - JSON Schema defining the data structure, types, validation, and defaults
2. **ui_schema.json** - UI configuration defining widgets, placeholders, descriptions, and layout
## Quick Reference: Terraform to JSON Schema
| Terraform Type | JSON Schema |
|----------------|-------------|
| `string` | `"type": "string"` |
| `number` | `"type": "number"` |
| `bool` | `"type": "boolean"` |
| `list(T)` | `"type": "array", "items": {...}` |
| `map(T)` | `"type": "object", "additionalProperties": {...}` |
| `object({...})` | `"type": "object", "properties": {...}` |
| `optional(T, default)` | Field with `"default"` (not in `required`) |
## Required vs Optional Fields
- **Required**: Variables without `default` or `optional()` wrapper
- **Optional**: Variables with `default = value` or using `optional(type, default)`
In JSON Schema:
- Required fields go in the `"required": [...]` array
- Optional fields get a `"default"` value
## Validation Mapping
| Terraform Validation | JSON Schema |
|---------------------|-------------|
| `can(regex("pattern", var.x))` | `"pattern": "pattern"` |
| `contains(["a", "b"], var.x)` | `"enum": ["a", "b"]` |
| `var.x >= N` | `"minimum": N` |
| `var.x <= N` | `"maximum": N` |
| `length(var.x) >= N` | `"minLength": N` |
## Enhanced Input Schema Features
### Title Field
Add `"title"` directly in properties for cleaner display:
```json
"aws_region": {
"title": "AWS Region",
"type": "string",
"enum": ["us-east-1", "eu-central-1"]
}
```
### Enum with Display Names
Use `enumNames` for user-friendly labels while keeping real values:
```json
"api_uri": {
"type": "string",
"enum": ["https://api.app.stackguardian.io", "https://api.us.stackguardian.io"],
"enumNames": ["EU1 - Europe", "US1 - United States"]
}
```
### Conditional Dependencies
Show/hide fields based on boolean toggle:
```json
"dependencies": {
"create_storage": {
"oneOf": [
{
"properties": {
"create_storage": { "enum": [true] },
"storage_size": { "type": "integer" }
}
},
{
"properties": {
"create_storage": { "enum": [false] },
"existing_bucket": { "type": "string" }
},
"required": ["existing_bucket"]
}
]
}
}
```
### Conditional Fields with allOf/if-then
Show/hide fields based on enum selection (e.g., OS family):
```json
"os": {
"type": "object",
"required": ["family"],
"allOf": [
{
"if": { "properties": { "family": { "const": "amazon" } } },
"then": {
"properties": {
"family": { "type": "string", "enum": ["amazon", "ubuntu"] },
"update_os": { "type": "boolean", "default": true }
}
}
},
{
"if": { "properties": { "family": { "not": { "const": "amazon" } } } },
"then": {
"properties": {
"family": { "type": "string", "enum": ["amazon", "ubuntu"] },
"version": { "type": "string", "minLength": 1 }
},
"required": ["version"]
}
}
]
}
```
**IMPORTANT**: When using `allOf` with `if/then`, do NOT add `additionalProperties: false` at the parent object level - it breaks form rendering.
## UI Schema Quick Reference
| Use Case | UI Schema |
|----------|-----------|
| Boolean toggle | `"ui:widget": "checkbox"` |
| Dropdown select | `"ui:widget": "select"` |
| Inline radio | `"ui:widget": "radio", "ui:options": {"inline": true}` |
| Multiline text | `"ui:widget": "textarea", "ui:options": {"rows": 3}` |
| Array of strings | `"items": { "ui:placeholder": "value" }` |
| Section title | `"ui:title": "Section Name"` |
| Help text | `"ui:description": "Helpful text..."` |
| Input hint | `"ui:placeholder": "example value"` |
## Field Ordering Guidelines
Follow these ordering rules for consistent schemas:
1. **Top-level field order:**
- If `stackguardian` config exists: place it first, then `aws_region`
- If no `stackguardian` config: place `aws_region` at the top
- Then other configuration objects in logical order
2. **Inside `stackguardian` object:**
- `api_uri` (API Region) first
- `api_key` second
- `org_name` third
3. **Network subnet ordering:**
- `private_subnet_id` before `public_subnet_id` (private takes precedence)
4. **Sensitive fields:**
- Do NOT use `"ui:widget": "password"` for API keys or tokens
- Use plain text input - the platform handles masking
## StackGuardian API Key Pattern
API keys in StackGuardian templates must accept both direct keys and secret references:
- **Direct API keys**: `sgo_*` (organization) or `sgu_*` (user)
- **Secret references**: `${secret::SECRET_NAME}` where SECRET_NAME contains alphanumeric characters, underscores, or hyphens
### Input Schema
```json
"api_key": {
"title": "API Key",
"type": "string",
"pattern": "^(sg[uo]_.*|\\$\\{secret::[a-zA-Z0-9_-]+\\})$",
"minLength": 1
}
```
### UI Schema
```json
"api_key": {
"ui:placeholder": "sgu_*** or ${secret::SECRET_NAME}",
"ui:description": "Your organization's API key (sgo_*/sgu_*) or a secret reference (${secret::SECRET_NAME})"
}
```
## Workflow
To create schemas from Terraform variables.tf:
1. Read the variables.tf file to understand all variables
2. Create input_schema.json:
- Do NOT include `"$schema"` key - StackGuardian forms don't require it
- Map each variable to JSON Schema type
- Convert nested objects recursively
- Add validation constraints (pattern, enum, minimum, etc.)
- List required fields (those without defaults)
- Use `"additionalProperties": false` for strict object validation
- **Exception**: Do NOT use `additionalProperties: false` on objects with `allOf`/`if-then` conditional logic
- Follow field ordering guidelines above
3. Create ui_schema.json:
- Mirror the structure of input_schema.json for nested objects
- Add `ui:title` and `ui:description` for object sections
- Use `ui:description` from Terraform `description` field
- Add `ui:placeholder` hints based on expected format
- Select appropriate widgets for each field type
- Add warnings for destructive options (using markdown)
- Do NOT use `"ui:widget": "password"` for sensitive inputs
## Two Schema Styles
### Terraform Module Style (nested objects)
Use `ui:title` on object properties to create visual sections:
```json
{
"network": {
"ui:title": "Network Configuration",
"ui:description": "Configure VPC and subnet settings",
"vpc_id": { "ui:placeholder": "vpc-***" }
}
}
```
### Workflow Step Template Style (flat with dependencies)
Use `ui:order` and JSON Schema `dependencies` for conditional fields:
```json
{
"ui:order": ["action", "option1", "option2"],
"action": { "ui:widget": "radio" }
}
```
## Reference Documentation
For detailed patterns and examples, see:
- `references/terraform-to-schema-mapping.md` - Complete type conversion rules
- `references/ui-schema-patterns.md` - UI widget patterns and examples
- `examples/private-runner/` - Terraform module style with nested objects
- `examples/runner-group/` - Conditional dependencies with oneOf
- `examples/kubernetes/` - Workflow step template style schemas
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/terraform-to-schema-mapping.md
```markdown
# Terraform to JSON Schema Mapping
This reference documents how to convert Terraform variable definitions to JSON Schema for StackGuardian no-code forms.
## Basic Types
### String
```hcl
variable "name" {
type = string
default = "default-value"
}
```
```json
"name": {
"type": "string",
"default": "default-value"
}
```
### Number
```hcl
variable "count" {
type = number
default = 10
}
```
```json
"count": {
"type": "number",
"default": 10
}
```
For integers specifically (whole numbers):
```json
"count": {
"type": "integer",
"default": 10
}
```
### Boolean
```hcl
variable "enabled" {
type = bool
default = true
}
```
```json
"enabled": {
"type": "boolean",
"default": true
}
```
## Collection Types
### List
```hcl
variable "availability_zones" {
type = list(string)
default = ["us-east-1a", "us-east-1b"]
}
```
```json
"availability_zones": {
"type": "array",
"items": {
"type": "string"
},
"default": ["us-east-1a", "us-east-1b"]
}
```
### Map
```hcl
variable "tags" {
type = map(string)
default = {}
}
```
```json
"tags": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"default": {}
}
```
### Set
Sets are converted to arrays with `uniqueItems: true`:
```hcl
variable "allowed_ips" {
type = set(string)
}
```
```json
"allowed_ips": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true
}
```
## Object Types
### Simple Object
```hcl
variable "network" {
type = object({
vpc_id = string
subnet_id = string
})
}
```
```json
"network": {
"type": "object",
"properties": {
"vpc_id": { "type": "string" },
"subnet_id": { "type": "string" }
},
"required": ["vpc_id", "subnet_id"],
"additionalProperties": false
}
```
### Object with Optional Fields
```hcl
variable "config" {
type = object({
name = string
port = optional(number, 8080)
enabled = optional(bool, true)
})
}
```
```json
"config": {
"type": "object",
"properties": {
"name": { "type": "string" },
"port": { "type": "integer", "default": 8080 },
"enabled": { "type": "boolean", "default": true }
},
"required": ["name"],
"additionalProperties": false
}
```
### Nested Objects
```hcl
variable "database" {
type = object({
instance = object({
class = string
size = number
})
backup = object({
enabled = bool
retention = optional(number, 7)
})
})
}
```
```json
"database": {
"type": "object",
"properties": {
"instance": {
"type": "object",
"properties": {
"class": { "type": "string" },
"size": { "type": "number" }
},
"required": ["class", "size"],
"additionalProperties": false
},
"backup": {
"type": "object",
"properties": {
"enabled": { "type": "boolean" },
"retention": { "type": "integer", "default": 7 }
},
"required": ["enabled"],
"additionalProperties": false
}
},
"required": ["instance", "backup"],
"additionalProperties": false
}
```
## Validation Patterns
### Regex Pattern
```hcl
variable "ami_id" {
type = string
validation {
condition = can(regex("^ami-[a-z0-9]+$", var.ami_id))
error_message = "Must be a valid AMI ID."
}
}
```
```json
"ami_id": {
"type": "string",
"pattern": "^ami-[a-z0-9]+$"
}
```
### Optional Field with Pattern
For optional fields with a default of `""`, the pattern must allow empty strings:
```hcl
variable "subnet_id" {
type = string
default = "" # Optional, can be empty
validation {
condition = var.subnet_id == "" || can(regex("^subnet-.*$", var.subnet_id))
error_message = "Must be a valid subnet ID or empty."
}
}
```
```json
"subnet_id": {
"type": "string",
"pattern": "^(|subnet-.*)$",
"default": ""
}
```
**Note**: Use `^(|pattern.*)$` to allow empty string OR the pattern. Without this, empty defaults will fail validation.
### Enum (contains)
```hcl
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Must be dev, staging, or prod."
}
}
```
```json
"environment": {
"type": "string",
"enum": ["dev", "staging", "prod"]
}
```
### Minimum/Maximum
```hcl
variable "instance_count" {
type = number
validation {
condition = var.instance_count >= 1 && var.instance_count <= 10
error_message = "Must be between 1 and 10."
}
}
```
```json
"instance_count": {
"type": "integer",
"minimum": 1,
"maximum": 10
}
```
### String Length
```hcl
variable "name" {
type = string
validation {
condition = length(var.name) >= 3 && length(var.name) <= 64
error_message = "Name must be 3-64 characters."
}
}
```
```json
"name": {
"type": "string",
"minLength": 3,
"maxLength": 64
}
```
### Array Length
```hcl
variable "subnets" {
type = list(string)
validation {
condition = length(var.subnets) >= 1
error_message = "At least one subnet required."
}
}
```
```json
"subnets": {
"type": "array",
"items": { "type": "string" },
"minItems": 1
}
```
## Complex Map Types
### Map of Objects
```hcl
variable "ingress_rules" {
type = map(object({
port = number
protocol = string
cidr_blocks = list(string)
}))
default = {}
}
```
```json
"ingress_rules": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
},
"protocol": {
"type": "string",
"enum": ["tcp", "udp", "icmp"]
},
"cidr_blocks": {
"type": "array",
"items": { "type": "string" },
"minItems": 1
}
},
"required": ["port", "protocol", "cidr_blocks"],
"additionalProperties": false
},
"default": {}
}
```
## Required Fields Detection
**Required** (no default, not optional):
```hcl
variable "vpc_id" {
type = string # Required - no default
}
```
**Optional** (has default):
```hcl
variable "region" {
type = string
default = "us-east-1" # Optional - has default
}
```
**Optional in object** (uses optional()):
```hcl
variable "config" {
type = object({
required_field = string # Required
optional_field = optional(string, "") # Optional
})
}
```
## Root Schema Structure
```json
{
"type": "object",
"properties": {
// ... all variables as properties
},
"required": [
// ... variables without defaults
]
}
```
**Note**: Do NOT include `"$schema"` key - StackGuardian forms don't require it.
## Title Field
Add `"title"` directly in properties for cleaner UI display:
```hcl
variable "aws_region" {
description = "The target AWS Region"
type = string
default = "eu-central-1"
}
```
```json
"aws_region": {
"title": "AWS Region",
"type": "string",
"default": "eu-central-1"
}
```
## Enum with Display Names (enumNames)
Use `enumNames` to show user-friendly labels while keeping real values:
```json
"api_uri": {
"title": "API Region",
"type": "string",
"enum": [
"https://api.app.stackguardian.io",
"https://api.us.stackguardian.io"
],
"enumNames": [
"EU1 - Europe",
"US1 - United States"
],
"default": "https://api.app.stackguardian.io"
}
```
The `enum` array contains the actual values stored, while `enumNames` provides display labels.
## Conditional Dependencies
Use `dependencies` with `oneOf` to show/hide fields based on a boolean toggle:
**Terraform:**
```hcl
variable "create_storage_backend" {
type = bool
default = true
}
variable "existing_s3_bucket_name" {
description = "Required when create_storage_backend = false"
type = string
default = ""
}
variable "force_destroy_storage_backend" {
description = "Only relevant when create_storage_backend = true"
type = bool
default = false
}
```
**JSON Schema:**
```json
{
"properties": {
"create_storage_backend": {
"title": "Create Storage Backend",
"type": "boolean",
"default": true
}
},
"dependencies": {
"create_storage_backend": {
"oneOf": [
{
"properties": {
"create_storage_backend": { "enum": [true] },
"force_destroy_storage_backend": {
"title": "Force Destroy Storage Backend",
"type": "boolean",
"default": false
}
}
},
{
"properties": {
"create_storage_backend": { "enum": [false] },
"existing_s3_bucket_name": {
"title": "Existing S3 Bucket Name",
"type": "string"
}
},
"required": ["existing_s3_bucket_name"]
}
]
}
}
}
```
When `create_storage_backend` is `true`, shows `force_destroy_storage_backend`.
When `create_storage_backend` is `false`, shows and requires `existing_s3_bucket_name`.
## AWS Regions Enum
Standard AWS regions list for region selection fields:
```json
"aws_region": {
"title": "AWS Region",
"type": "string",
"enum": [
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2",
"af-south-1",
"ap-east-1",
"ap-south-1",
"ap-south-2",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-3",
"ap-southeast-4",
"ap-southeast-5",
"ap-northeast-1",
"ap-northeast-2",
"ap-northeast-3",
"ca-central-1",
"ca-west-1",
"eu-central-1",
"eu-central-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"eu-south-1",
"eu-south-2",
"eu-north-1",
"il-central-1",
"me-south-1",
"me-central-1",
"sa-east-1"
],
"default": "eu-central-1"
}
```
## Conditional Fields with allOf/if-then
Use `allOf` with `if/then` to show/hide fields based on enum selection:
```hcl
variable "os" {
type = object({
family = string
version = optional(string, "")
update_os_before_install = bool
})
validation {
condition = contains(["amazon", "ubuntu", "rhel"], var.os.family)
error_message = "Must be amazon, ubuntu, or rhel."
}
}
```
```json
"os": {
"type": "object",
"required": ["family"],
"allOf": [
{
"if": {
"properties": {
"family": { "const": "amazon" }
}
},
"then": {
"properties": {
"family": {
"type": "string",
"enum": ["amazon", "ubuntu", "rhel"],
"default": "amazon"
},
"update_os_before_install": {
"type": "boolean",
"default": true
}
}
}
},
{
"if": {
"properties": {
"family": {
"not": { "const": "amazon" }
}
}
},
"then": {
"properties": {
"family": {
"type": "string",
"enum": ["amazon", "ubuntu", "rhel"],
"default": "amazon"
},
"version": {
"type": "string",
"minLength": 1
},
"update_os_before_install": {
"type": "boolean",
"default": true
}
},
"required": ["version"]
}
}
]
}
```
**CRITICAL**: Do NOT use `additionalProperties: false` at the parent object level when using `allOf`/`if-then` - it breaks form rendering.
## Best Practices
1. Do NOT include `"$schema"` key - StackGuardian forms don't require it
2. Use `"additionalProperties": false` for object types to prevent typos
- **Exception**: Do NOT use on objects with `allOf`/`if-then` conditional logic
3. Use `"integer"` for whole numbers, `"number"` for decimals
4. Extract regex patterns from Terraform validation conditions
5. Convert `contains()` validations to `"enum"`
6. Preserve default values from Terraform
7. Mark variables without defaults as required
8. Add `"title"` for cleaner field labels in the UI
9. Use `enumNames` when enum values are technical (URLs, IDs) but need friendly display
10. Use `dependencies` with `oneOf` for conditional field visibility based on boolean toggle
11. Use `allOf` with `if/then` for conditional fields based on enum selection
```
### references/ui-schema-patterns.md
```markdown
# UI Schema Patterns
This reference documents UI schema patterns for StackGuardian no-code forms.
## Structure Overview
The UI schema mirrors the structure of the input schema, adding UI-specific properties at each level.
```json
{
"ui:title": "Form Title",
"ui:description": "Form description",
"field_name": {
"ui:widget": "...",
"ui:placeholder": "...",
"ui:description": "..."
},
"nested_object": {
"ui:title": "Section Title",
"nested_field": {
"ui:description": "..."
}
}
}
```
## Widget Types
### Text Input (Default)
No widget specification needed for standard text input:
```json
"name": {
"ui:placeholder": "Enter name",
"ui:description": "The display name for this resource"
}
```
### Checkbox (Boolean)
```json
"enabled": {
"ui:widget": "checkbox",
"ui:description": "Enable this feature"
}
```
### Select Dropdown (Enum)
```json
"region": {
"ui:widget": "select",
"ui:placeholder": "Select a region",
"ui:description": "AWS region for deployment"
}
```
### Radio Buttons (Small Enum)
For 2-4 mutually exclusive options:
```json
"action": {
"ui:widget": "radio",
"ui:options": {
"inline": true
}
}
```
### Textarea (Multiline)
For SSH keys, certificates, YAML content:
```json
"ssh_public_key": {
"ui:widget": "textarea",
"ui:placeholder": "ssh-rsa AAAAB3...",
"ui:options": {
"rows": 3,
"resize": "vertical"
},
"ui:description": "Your SSH public key"
}
```
### Hidden Field
```json
"internal_id": {
"ui:widget": "hidden"
}
```
## Array Fields
For array fields (Terraform `list(T)`), use proper array UI with `items` configuration instead of textarea:
### Array of Strings
**Input Schema:**
```json
"additional_versions": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
},
"default": []
}
```
**UI Schema:**
```json
"additional_versions": {
"ui:description": "Additional versions to install. Click + to add more.",
"items": {
"ui:placeholder": "1.5.7"
}
}
```
This renders as a dynamic list with add/remove buttons, much better UX than a textarea requiring JSON input.
### Array of Objects
**Input Schema:**
```json
"ingress_rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"port": { "type": "integer" },
"protocol": { "type": "string", "enum": ["tcp", "udp"] }
}
}
}
```
**UI Schema:**
```json
"ingress_rules": {
"ui:description": "Define ingress rules",
"items": {
"port": { "ui:placeholder": "80" },
"protocol": { "ui:widget": "select" }
}
}
```
### Anti-pattern: Textarea for Arrays
**Do NOT use textarea for arrays:**
```json
// BAD - requires users to type JSON manually
"versions": {
"ui:widget": "textarea",
"ui:placeholder": "[\"1.4.6\", \"1.5.7\"]"
}
```
**Use proper array UI instead:**
```json
// GOOD - renders as dynamic list with add/remove buttons
"versions": {
"items": {
"ui:placeholder": "1.4.6"
}
}
```
## Section Grouping
### Object with Title
Use `ui:title` to create visual sections for nested objects:
```json
"network": {
"ui:title": "Network Configuration",
"ui:description": "Configure VPC and subnet settings",
"vpc_id": {
"ui:placeholder": "vpc-***",
"ui:description": "Your VPC ID"
},
"subnet_id": {
"ui:placeholder": "subnet-***"
}
}
```
### Top-Level Title
```json
{
"ui:title": "AWS Private Runner Setup",
"ui:description": "Configure and deploy a StackGuardian Private Runner on AWS"
}
```
## Field Ordering
### Top-Level Ordering
For workflow step templates, use `ui:order` to control field sequence:
```json
{
"ui:order": [
"action",
"namespace",
"resource_type",
"options",
"advanced"
]
}
```
Fields not in `ui:order` appear after listed fields in their original order.
### Nested Object Ordering
You can also use `ui:order` within nested objects to control field order inside sections:
```json
{
"ui:order": [
"stackguardian",
"aws_region",
"network",
"storage"
],
"stackguardian": {
"ui:title": "StackGuardian Configuration",
"ui:order": ["api_uri", "api_key", "org_name"],
"api_uri": {
"ui:widget": "select",
"ui:description": "Select your platform region"
},
"api_key": {
"ui:placeholder": "sg(u|o)_***"
},
"org_name": {
"ui:placeholder": "your-org-name (optional)"
}
}
}
```
This ensures fields within the `stackguardian` section appear in the order: `api_uri`, then `api_key`, then `org_name`.
## Placeholder Patterns
Use placeholders to show expected format:
```json
// AWS Resource IDs
"vpc_id": { "ui:placeholder": "vpc-***" }
"subnet_id": { "ui:placeholder": "subnet-***" }
"ami_id": { "ui:placeholder": "ami-***" }
// IP/CIDR
"ip_address": { "ui:placeholder": "192.168.1.1" }
"cidr_block": { "ui:placeholder": "10.0.0.0/16" }
// Kubernetes
"namespace": { "ui:placeholder": "default" }
"release_name": { "ui:placeholder": "my-release" }
// Optional with hint
"override_name": { "ui:placeholder": "override name (optional)" }
```
## Description Patterns
### Standard Description
```json
"instance_type": {
"ui:description": "The EC2 instance type (min 4 vCPU, 8GB RAM recommended)"
}
```
### Warning Description
Use emoji and bold for important warnings:
```json
"force_destroy": {
"ui:widget": "checkbox",
"ui:description": "**Warning:** This will permanently delete all data. Cannot be undone."
}
```
### Detailed Description
For complex fields:
```json
"create_network": {
"ui:widget": "checkbox",
"ui:description": "Whether to create NAT Gateway and route tables. Defaults to false for enterprise environments with existing infrastructure. Check this box if you need the module to create NAT Gateway and routing."
}
```
## Dynamic Objects (Maps)
For `additionalProperties` (map types):
```json
"tags": {
"ui:options": {
"addable": true,
"removable": true,
"orderable": false
},
"ui:description": "Resource tags as key-value pairs",
"additionalProperties": {
"ui:placeholder": "tag value"
}
}
```
### Complex Map Values
For maps with object values:
```json
"helm_set": {
"ui:options": {
"addable": true,
"removable": true
},
"ui:description": "Helm chart value overrides",
"additionalProperties": {
"ui:widget": "textarea",
"ui:options": {
"rows": 1,
"resize": "vertical"
}
}
}
```
## Conditional Display
For workflow step templates with conditional fields, combine input schema `dependencies` with UI schema:
**Input Schema:**
```json
{
"dependencies": {
"action": {
"oneOf": [
{
"properties": {
"action": { "enum": ["apply"] },
"dry_run": { "type": "boolean" }
}
},
{
"properties": {
"action": { "enum": ["delete"] },
"force": { "type": "boolean" }
}
}
]
}
}
}
```
**UI Schema:**
```json
{
"action": {
"ui:widget": "radio",
"ui:options": { "inline": true }
},
"dry_run": {
"ui:widget": "checkbox",
"ui:description": "Simulate without making changes"
},
"force": {
"ui:widget": "checkbox",
"ui:description": "Force deletion without confirmation"
}
}
```
## Enum with Display Names
When using `enum` + `enumNames` in input schema:
**Input Schema:**
```json
"version": {
"type": "string",
"enum": ["1.28", "1.27", "1.26"],
"enumNames": ["v1.28 (latest)", "v1.27", "v1.26"]
}
```
**UI Schema:**
```json
"version": {
"ui:widget": "select",
"ui:placeholder": "Select version"
}
```
## Complete Terraform Module Example
```json
{
"ui:title": "AWS EC2 Instance",
"ui:description": "Deploy an EC2 instance with configurable settings",
"instance_type": {
"ui:description": "EC2 instance type"
},
"ami_id": {
"ui:placeholder": "ami-***",
"ui:description": "Amazon Machine Image ID"
},
"network": {
"ui:title": "Network Settings",
"ui:description": "Configure networking",
"vpc_id": {
"ui:placeholder": "vpc-***",
"ui:description": "VPC to deploy into"
},
"subnet_id": {
"ui:placeholder": "subnet-***"
},
"public_ip": {
"ui:widget": "checkbox",
"ui:description": "Assign public IP address"
}
},
"storage": {
"ui:title": "Storage Configuration",
"volume_type": {
"ui:widget": "select",
"ui:description": "EBS volume type"
},
"volume_size": {
"ui:description": "Volume size in GB (minimum 8)"
}
},
"tags": {
"ui:title": "Resource Tags",
"ui:options": {
"addable": true,
"removable": true
}
}
}
```
## Best Practices
1. Always add `ui:description` from Terraform `description` field
2. Use `ui:placeholder` to show expected format
3. Use `ui:widget: "checkbox"` for all boolean fields
4. Use `ui:widget: "select"` for enum fields with 5+ options
5. Use `ui:widget: "radio"` with `inline: true` for 2-4 options
6. Group related fields in objects with `ui:title`
7. Use markdown in descriptions for emphasis and warnings
8. Add `ui:title` and `ui:description` at object level for sections
9. For array fields, use `items` configuration - never use `textarea` for arrays
```