# Simulator Smart Forms

> >

- **Type:** Skill
- **Install:** `agentstack add skill-corezoid-simulator-ai-plugin-simulator-smart-forms`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [corezoid](https://agentstack.voostack.com/s/corezoid)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [corezoid](https://github.com/corezoid)
- **Source:** https://github.com/corezoid/simulator-ai-plugin/tree/main/plugins/simulator/skills/simulator-smart-forms
- **Website:** https://simulator.company

## Install

```sh
agentstack add skill-corezoid-simulator-ai-plugin-simulator-smart-forms
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Simulator.Company Smart Form Author

You are a specialist in creating and editing **Smart Forms** (also called CDU,
Script, or Application) on the Simulator.Company platform, using the `simulator`
MCP server plus the `pullSmartForm` / `pushSmartForm` engine tools.

---

## Core Concepts

A **Smart Form** is three things in one:

| Layer | What it is |
|---|---|
| **Actor** | An actor in the `scripts` system form — has `id`, `ref`, `title`, `data.sharedWith` |
| **Versioned project** | A folder/file tree per environment: pages, locale, viewModel, styles, definitions, widgets |
| **Backend binding** | Corezoid credentials per env — dynamic data and control flow come from Corezoid at runtime |

A Smart Form is **not** a data-schema form. Compare:

```
Regular Form (template)        Smart Form (actor + app)
──────────────────────         ───────────────────────
defines field schema           is itself an actor in "scripts" form
actors are instances of it     carries pages/styles/i18n as versioned files
account definitions            Corezoid process supplies runtime data
```

---

## Environments

Every Smart Form always has exactly **two environments**:

| Env | `readonly` | Purpose |
|---|---|---|
| `develop` | `false` | Active editing target |
| `production` | `true` | Live, served to end users |

**Rule:** never write directly to `production`. Edit `develop`, then deploy
`develop → production` via a release. The server rejects writes to readonly envs.

---

## Project File Structure

After `pullSmartForm` the local directory looks like:

```
/
  develop/
    .manifest.json              ← file IDs + SHA-256 hashes (used by pushSmartForm)
    pages/
      index/
        config                  ← Page layout (JSON): { grid, forms[] }
        locale                  ← Page-scoped i18n (JSON): { key: { en: "…", uk: "…" } }
    locale                      ← App-wide i18n (JSON)
    viewModel                   ← Default view-model values (JSON)
    widgets                     ← Widget/control settings (JSON, ctrlSettings)
    definitions/
      button                    ← Reusable component fragment (JSON), used via "$ref": "#/button"
    styles/
      index                     ← Less stylesheet (text/css); compiled → scoped CSS at serve time
  production/
    .manifest.json
    … (same tree, read-only)
```

### File roles

| File | MIME | Purpose |
|---|---|---|
| `pages//config` | `application/json` | Page layout: grid + forms + sections + items |
| `pages//locale` | `application/json` | Page-level i18n strings |
| `locale` | `application/json` | App-wide i18n strings; merged with page locale at serve time |
| `viewModel` | `application/json` | Default values; merged with Corezoid-supplied viewModel at serve time |
| `definitions/` | `application/json` | Reusable component fragments; inlined by `$ref` at serve time |
| `styles/index` | `text/css` | Less source; compiled to scoped CSS (`.cdu-page` scope); `@import "pages//style"` works |
| `widgets` | `application/json` | ctrlSettings for embedded third-party widgets |

---

## Standard Workflow

### Creating a new Smart Form

```
createSmartForm(title="My App", ref="my-app")
→ { actorId: "...", envs: [{id: 1, title: "develop"}, {id: 2, title: "production"}] }
```

`corezoidCredentials` is optional — omit it for static/design-only forms and configure the Corezoid binding later.

Then immediately pull the default skeleton:

```
pullSmartForm(actorId="")
→ downloads all envs to /develop/ and /production/
```

### Edit cycle (existing or newly created form)

```
1.  pullSmartForm(actorId="")
    → downloads all envs to /develop/ and /production/
    → writes .manifest.json (file IDs + hashes) in each env dir

2.  Edit files under /develop/
    (page config, locale, viewModel, styles, definitions)

3.  pushSmartForm(actorId="")
    → walks /develop/, diffs every file/folder against .manifest.json
    → validates new + changed files against the CDU page protocol schema
    → if errors: aborts with { validationErrors: [...] } — fix and retry
    → POSTs new folders (parents first) and new files, then PUTs modified files
    → updates .manifest.json with returned ids + content hashes
    → returns { created: { folders, files }, updated, unchanged, orphanFiles }

4.  Deploy (when ready to publish):
    deploySmartForm(actorId="")
    → deploys develop → production; returns { releaseId, releaseNumber, status }
```

---

## Page Config Format (`pages//config`)

The page `config` is the layout template. Structure: **Page → Grid → Form → Section → Item**.

### Minimal page

```json
{
  "grid": {
    "type": "one_column",
    "components": {
      "center": ["main"]
    }
  },
  "forms": [
    {
      "id": "main",
      "title": "My Form",
      "sections": [
        {
          "id": "body",
          "type": "body",
          "content": [
            {
              "id": "greeting",
              "class": "label",
              "value": "[[hello]]"
            },
            {
              "id": "name",
              "class": "edit",
              "value": "{{defaultName}}",
              "type": "text",
              "placeholder": "Enter your name",
              "required": true
            },
            {
              "id": "submit",
              "class": "button",
              "title": "Submit",
              "type": "default"
            }
          ]
        }
      ]
    }
  ]
}
```

### Grid

```jsonc
{
  "type": "one_column" | "two_column",
  "header": {
    "class": "default" | "stepper",
    "extra": { "steps": ["Step 1", "Step 2"], "active": 1 }
  },
  "components": {
    "header":  [""],
    "left":    [""],
    "center":  [""],
    "right":   [""],
    "footer":  [""],
    "sidebar": [""]
  },
  "styleClass": "custom-grid"
}
```

### Form

```jsonc
{
  "id": "info",
  "title": "Details",
  "styleClass": "card",
  "visibility": "visible",    // "visible" | "disabled" | "hidden"
  "sections": [ /* Section[] */ ]
}
```

### Section

```jsonc
{
  "id": "s1",
  "type": "body",             // "body" | "block" | "modal" | "float"
  "visibility": "visible",
  "header":  [ /* Item[] */ ],
  "content": [ /* Item[] */ ],
  "footer":  [ /* Item[] */ ]
}
```

`block` renders as a grouped card; `modal`/`float` are overlays.

---

## Component Catalogue

Every item has `class` + base fields (`id`, `value`, `visibility`, `required`, `error`,
`errorMsg`, `styleClass`, `row`, `w`). Below are the most common components:

### Input components

| `class` | `value` type | Key `extra` / options |
|---|---|---|
| `edit` | string | `type`: `text` `email` `int` `float` `phone` `multiline` `date` `password` `colorPicker`; `placeholder`, `regexp`, `mask`, `submitOnEnter` |
| `select` | string | `options: [{title, value, visibility, icon, tooltip, avatar, badge, styleClass}]`; `type`: `default` `autocomplete`; `submitOnChange` |
| `multiselect` | string[] | `options: [{title, value, visibility, tooltip}]`; `extra.length` (max) |
| `radio` | string | `options: [{title, value, visibility}]`; `extra.direction`: `row`\|`column` |
| `check` | boolean | checkbox |
| `toggle` | boolean | `title` label on the switch |
| `slider` | number | `extra: { min, max, step }` |
| `phone` | `{countryCode, number}` | `options` (country codes), `regexp` |
| `otp` | object `otp-0…otp-N` | `extra.length` (2–20); `type`: `text`\|`int` |

### Display components

| `class` | Notes |
|---|---|
| `label` | Static text; supports `[[locale]]` and `{{viewModel}}` tokens; BBCode rendered; `align`: `left`\|`center`\|`right` |
| `divider` | Visual separator; no value |
| `image` | `value` = src URL; `extra: {alt, height, width}` |
| `carousel` | `items[]` (slides); `extra: {autoplay, interval}` |
| `timer` | `value` = remaining ms; `extra.duration` |
| `comments` | Comment thread widget; `title` |

### Action components

| `class` | Notes |
|---|---|
| `button` | `title`, `type`: `default` `secondary` `tertiary` `text` `error`; `extra.icon`; submits its form; or `extra.action: 'logout'`; `extra.url` (open URL) |
| `copy` | `value` = text to copy; `title` = button label |

### Data & navigation components

| `class` | Notes |
|---|---|
| `table` | `head: [{id,title}]`, `body: [{: value}]`; `type`: `default` `radio` `check`; `submitOnChange`, `submitOnScroll` |
| `tab` | `options: [{id,title}]`; `value` = selected id; `submitOnChange` |
| `stepper` | `options: [{id,title}]`; `value` = step; `extra.direction` |
| `mainMenu` | Nested navigation; `options` tree |

### File components

| `class` | Notes |
|---|---|
| `file` | Preview/download; `value: FileProps`; `extra: {downloadUrl, auth}` |
| `upload` | File upload; `type`: `default`\|`webcam`; `extra: {accept, minSize, maxSize}` |
| `attachment` | Multi-file viewer; `value: FileProps[]`; `extra.downloadUrl` |
| `signature` | Canvas signature → base64; `extra: {strokeStyle, saveButtonTitle}` |

### Layout wrappers

| `class` | Notes |
|---|---|
| `row` | Horizontal group; `items: Item[]`; `w` sets width |
| `draggable` | Sortable list; `items: Item[]`; `value` = current order |

### Embedded widgets

`class: "widget"` — `type`: `iframe` `onfido` `twilio` `amazonConnect` `webComments`. Each type has its own `extra` schema.

---

## Templating

All substitution is **server-side** — the renderer receives concrete values.

| Syntax | Source | Example |
|---|---|---|
| `[[key]]` | `locale` (app + page merged) | `"[[hello]]"` → `"Hello"` in en |
| `{{key}}` | `viewModel` (default + Corezoid-supplied merged) | `"{{userName}}"` → `"Alice"` |
| `"$ref": "#/button"` | `definitions/button` file | inlined at serve time |
| `contentLoop` | section array expansion | one template → N rows |
| BBCode | `label`/`button` titles | `[b]bold[/b]`, `[color=#f00]red[/color]` |

### locale file format

```json
{
  "hello": { "en": "Hello", "uk": "Привіт" },
  "submit": { "en": "Submit", "uk": "Надіслати" }
}
```

### viewModel file format

```json
{
  "defaultName": "Anonymous",
  "maxItems": 10
}
```

### definitions fragment format

```json
{
  "class": "button",
  "title": "[[submit]]",
  "type": "default"
}
```

Used in config as `{ "$ref": "#/button" }` — the whole object is replaced.

---

## Change Protocol (POST 200 response)

When Corezoid returns `code: 200`, the server sends `changes[]` — surgical patches
to the live page without a full re-render:

```jsonc
[
  {
    "id": "name",             // item / section / form id
    "class": "edit",          // component class (for item changes)
    "value": "Alice",
    "visibility": "visible",
    "error": false,
    "required": true
  },
  {
    "id": "status",
    "options": [{"id":"a","title":"Active"},{"id":"i","title":"Inactive"}],
    "changeRules": {
      "options": { "action": "replace" }   // concat | unshift | delete | replace | merge
    }
  }
]
```

`code: 205` → re-render a whole page (can switch to a different `pageId`).
`code: 302` → redirect to `nextPage`.

---

## Creating a Smart Form from Scratch

Use the `createSmartForm` MCP tool — it calls `POST /papi/1.0/applications/` internally
and returns the actor ID plus both env IDs ready for use.

```
createSmartForm(
  title="My App",
  ref="my-app",
  description="Optional",          // optional
  sharedWith="userList",            // optional, default userList
  apiLogin="...",                   // optional — set Corezoid binding later if omitted
  apiSecret="...",
  procId="...",
  companyId="..."
)
→ { actorId: "...", ref: "my-app", title: "My App",
    envs: [{ id: 12, title: "develop", readonly: false },
           { id: 13, title: "production", readonly: true }],
    next: "run pullSmartForm(actorId=...) to download the initial file tree" }
```

`sharedWith` values: `userList` | `allWorkspaceUsers` | `allRegisteredUsers` | `anyone`.

Corezoid credentials are optional at creation time and can be configured later.

After creation always run `pullSmartForm` to download the default file skeleton before editing.

---

## Working with Releases

### Deploy develop → production

```
deploySmartForm(actorId="")
→ { actorId, sourceEnv: "develop", targetEnv: "production",
    releaseId, releaseNumber, status: "active" }
```

`sourceEnv` and `targetEnv` default to `develop` and `production`; pass them explicitly
to deploy between non-standard envs.

### List releases

```
listReleases(actorId="")           // production releases (default)
listReleases(actorId="", env="develop")
→ { actorId, env, releases: [{ id, release_number, status, created_at, … }] }
```

### Diff two releases

```
diffReleases(actorId="", releaseId="5", vsReleaseId="3")
→ { added[], removed[], modified[] }
```

Compared by `source_hash` — no file bytes transferred. Use before a rollback to preview
what will change.

### Rollback to a previous release

```
rollbackRelease(actorId="", releaseId="3")
→ { actorId, rolledBackTo: "3", newReleaseId, releaseNumber, status: "active" }
```

Rollback is **forward-only**: a new `active` release is created whose content equals
the target release. History is never rewritten.

**Retention:** 5 releases per env (objects). Older release manifests remain for audit;
only objects are GC'd. A release outside the 5-release window cannot be rolled back.

---

## File History

```
// List versions of a file (fileId from .manifest.json)
getFileHistory(actorId="", fileId=12345)
getFileHistory(actorId="", fileId=12345, limit=20, offset=0)
→ list of { versionId, operation, createdAt, … }

// Fetch source of a specific version
getFileVersion(actorId="", fileId=12345, versionId="")
→ { source: "…full file content…" }

// Restore file to a prior version (creates a new version; run pullSmartForm to refresh local)
rollbackFile(actorId="", fileId=12345, versionId="")

// List soft-deleted objects in an env
listTrash(actorId="")              // develop (default)
listTrash(actorId="", env="production")
→ list of { objectId, title, objType, deletedAt, … }

// Restore a deleted object
restoreFromTrash(actorId="", objectId="")
```

All writes create a before-state history row (`operation`: `create`|`update`|`move`|`rename`|`delete`).
Retention: 50 versions per file.

---

## Key Rules for Authoring

1. **Edit only `develop`** — the server rejects writes to `production` (readonly env).
2. **Run `pullSmartForm` before editing** — establishes `.manifest.json` needed by `pushSmartForm`.
3. **Server stores `source` opaque** — no structural validation of `config`, `viewModel`, or `locale` JSON at save time. Validate page JSON against the CDU protocol before pushing.
4. **Missing `$ref` resolves to `{}`** — a `definitions/button` reference to a non-existent fragment silently produces an empty object at serve time. Always verify definition names.
5. **System files are protected** — `is_system` files (`styles/index`, `pages/index/config`, etc.) cannot be renamed or deleted. Edit their content freely; rename/delete will fail.
6. **CSS is Less** — `styles/index` is compiled with Less at serve time, wrapped in `.cdu-page {}`. Use Less syntax; `@import "pages//style"` imports page-level stylesheets.
7. **Dynamic data comes from Corezoid** — the Smart Form files define layout and defaults; Corezoid processes supply runtime `viewModel` values and control flow (`code` 200/205/302).
8. **Deploy is a two-phase snapshot** — T1 locks the target env and takes a snapshot; T2 materialises it. A failed T2 is compensated automatically.

---

## Typical Session Example

```
// 1. Pull all files to develop/
pullSmartForm(actorId="69bbd03e-0d4c-4122-9234-e06ffe9ca1eb")
→ { envs: [{ env: "develop", dir: "…/develop", files: 11 }, { env: "production", … }] }

// 2. Edit pages/index/config — add a new label item to the body section

// 3. Push changes (also creates new pages/folders if you added them locally)
pushSmartForm(actorId="69bbd03e-0d4c-4122-9234-e06ffe9ca1eb")
→ { created: { folders: 0, files: 0 }, updated: 1, unchanged: 10, orphanFiles: [] }

// Adding a new page? Just create the files locally an

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [corezoid](https://github.com/corezoid)
- **Source:** [corezoid/simulator-ai-plugin](https://github.com/corezoid/simulator-ai-plugin)
- **License:** MIT
- **Homepage:** https://simulator.company

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-corezoid-simulator-ai-plugin-simulator-smart-forms
- Seller: https://agentstack.voostack.com/s/corezoid
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
