> ## Documentation Index
> Fetch the complete documentation index at: https://docs.charmos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Build Input Forms (UI Schema)

The `interface` block in `charm.yaml` defines the JSON Schema for user inputs. The optional `interface.ui` block maps fields to Store form widgets.

For all manifest fields, see the [Manifest Reference](/references/manifest).

## Text inputs

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
interface:
  input:
    type: object
    required: [message]
    properties:
      message:
        type: string
        title: Message
        description: What should the agent do?
  output:
    type: string
```

## Validation rules

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
      depth:
        type: integer
        title: Search Depth
        default: 3
        minimum: 1
        maximum: 5
```

## Built-in UI widgets

Map fields to Store components with `interface.ui`:

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
  ui:
    message: { "ui:widget": "textarea" }
    upload: { "ui:widget": "file" }
```

**Supported built-in widgets today:**

| Widget     | Description                                                                  |
| ---------- | ---------------------------------------------------------------------------- |
| `text`     | Single-line input (default). Shows number spinner if type is integer/number. |
| `textarea` | Multi-line input                                                             |
| `file`     | File upload — runner receives the uploaded file path in inputs               |
| `select`   | Dropdown menu based on the `enum` property in your schema                    |
| `checkbox` | Boolean toggle switch                                                        |
| `slider`   | Slider based on `minimum` and `maximum` schema properties                    |

Legacy templates may use `x-ui-widget` on individual properties; the Store still resolves those for backward compatibility.

Unknown widget names fall back to `text`.

## Access inputs in code

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
def agent(inputs):
    message = inputs.get("message")
    depth = inputs.get("depth", 3)
    return f"Processed: {message} (depth={depth})"
```

File fields are injected by the runner/store pipeline — use the key name from your schema.

## Adding custom UI Widgets (Community Plugins)

If you need a specialized input widget (like a code editor, color picker, or map selector), you can build and share it dynamically using the Charm Community Plugin registry.

1. **Build a React Component**: Your component must implement the `FieldProps` interface and be exported as the default export.
2. **Publish**: Publish your component as an ESM-compatible NPM package.
3. **Register**: Submit a Pull Request to the [charm-community-plugin](https://github.com/CharmAIOS/charm-community-plugin) repository. Add your widget to `widgets/registry.json`.

Once your PR is merged, any agent developer can use your widget instantly by specifying its `id` in their `ui:widget` config. The Charm Store will dynamically download and render your NPM package on the fly—no platform redeploys required!

## Related

* [Extensibility Overview](/guides/extensibility)
* [UI Protocol Reference](/platform/ui-protocol)
* [Output Renderers](/guides/output-renderers)
