AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Simulator Smart Forms Logic

skill-corezoid-simulator-ai-plugin-simulator-smart-forms-logic · by corezoid

>

No reviews yet
0 installs
33 views
0.0% view→install

Install

$ agentstack add skill-corezoid-simulator-ai-plugin-simulator-smart-forms-logic

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-corezoid-simulator-ai-plugin-simulator-smart-forms-logic)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Simulator Smart Forms Logic? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Smart Form Backend Logic

You orchestrate the Corezoid process(es) that make a Simulator.Company Smart Form interactive. Layout, i18n, styles, and viewModel defaults live in the Smart Form actor itself (see the simulator-smart-forms skill). Everything dynamic — initial viewModel, page transitions, submit handling, notifications, write-backs to actors — runs in Corezoid.

This skill does not author processes itself. Instead it:

  1. Confirms the Corezoid plugin is installed and its skills are available.
  2. Translates the user's intent into precise briefs in the exact format

corezoid-create / corezoid-edit expect (purpose · inputs · expected output · process type · concrete node skeleton).

  1. Invokes the matching Corezoid skill with that brief and lets it run

create-process / push-process / lint-process / run-task.

  1. Provisions an API key (create-api-key for a new one, or find-principal

for an existing apiLogin) and shares the bound process to it (share-object) so the Smart Form runtime can call it.

  1. Finally binds the process to the Smart Form env (createSmartForm or

updateSmartFormEnv) via the simulator MCP server.


0. Preflight — confirm the Corezoid plugin is installed

Before producing any brief, verify the Corezoid plugin is available in this session:

  1. Check whether the create-process, push-process, create-alias,

create-api-key, find-principal, and share-object MCP tools are listed in the tool registry. If they are, the corezoid MCP server is running. (create-api-key / find-principal / share-object are needed by Step E below — provisioning the API key the Smart Form runtime authenticates with.)

  1. Check whether the corezoid-create, corezoid-edit, and (optionally)

corezoid-access skills are reachable (they appear in the available-skills list when installed).

  1. If either is missing, stop and instruct the user (reply in the user's

language):

> "This workflow needs the Corezoid plugin. Install it from > github.com/corezoid/corezoid-ai-plugin > and run /corezoid-init to authenticate, then ask me to continue."

Do not attempt to author .conv.json files yourself or call PAPI directly when the Corezoid plugin is absent.


1. The runtime contract

The platform binds one Corezoid process per env to a Smart Form via the env's procId. That bound process receives a POST whenever a page is rendered or a form submission event fires. It must respond to {{__callback_url}} with the right shape:

| path | Trigger | Required response shape | |---------|---------------------------------------|------------------------------------------------------------| | /get | A page is being opened or re-rendered | { "code": 200, "viewModel": { … } } | | /send | A button clicked or any element with submitOnChange: true changed | { "code": 200, "data": { "changes": [], "notifications": [] } } |

Two distinct /send triggers — always distinguish them:

| Source | body.buttonId | body.buttonData | |---|---|---| | Button click | button's id | {} (empty object) | | submitOnChange element | element's id | { "action": "select"/"check"/…, "value": "newValue" } |

When an element has submitOnChange: true (e.g. a select, radio, or checkbox), the platform fires /send immediately on value change without waiting for a button. body.buttonId is the element's own id and body.buttonData carries the interaction detail (action + value). body.data still contains the full current snapshot of all field values.

Other status codes: 205 re-render whole page; 302 redirect to another page (data.nextPage); 4xx/5xx surfaces an error toast.

> Topology is up to the developer. The bound process may handle both paths > itself in a single graph, or fan out to sub-processes (one per path / page / > buttonId) via api_copy. The contract is the response shape, not the layout. > Ask the user which approach fits the form's complexity before generating briefs.

Sample /get request (incoming)

{
  "__callback_url": "https://cb-apigw.corezoid.com/callback/sync_api/…",
  "body": {
    "context": { "appId": "", "rootActorId": "",
                 "browser": "Chrome", "language": "en", "timeZoneOffset": -180 },
    "page": "index",
    "query": {}
  },
  "path": "/get",
  "sessionData": { "userInfo": { "id": 52731, "login": "user@x.com", "saId": 5501,
                                 "memberGroups": [79693] } }
}

Sample /send request — button click

{
  "__callback_url": "https://cb-apigw.corezoid.com/callback/sync_api/…",
  "body": {
    "buttonId": "submit_btn",
    "buttonData": {},
    "context": { "actorId": "", "rootActorId": "", "appId": "" },
    "data": { "day_comment": "…", "self_score": "4" },
    "formId": "",
    "page": "index",
    "sectionId": "",
    "query": {}
  },
  "path": "/send",
  "sessionData": { /* same as /get */ }
}

Sample /send request — submitOnChange element

buttonData is non-empty: action describes the interaction type, value is the newly selected value. buttonId is the field's id, not a button.

{
  "__callback_url": "https://cb-apigw.corezoid.com/callback/sync_api/…",
  "__headers": {},
  "body": {
    "buttonId": "project_name",
    "buttonData": {
      "action": "select",
      "value": "energy_efficiency"
    },
    "context": {
      "appId": "0118a16b-bf08-4e13-b3e7-0f97dfa8b6db",
      "browser": "Chrome",
      "language": "en",
      "timeZoneOffset": -180
    },
    "data": {
      "grant_category": "ecology",
      "project_desc": "",
      "project_name": "energy_efficiency"
    },
    "formId": "project_section",
    "page": "index",
    "sectionId": "project_body",
    "query": {}
  },
  "path": "/send",
  "sessionData": {}
}

Sample /get callback (outgoing)

{
  "code": 200,
  "viewModel": {
    "userName": "Alice",
    "submit_btn_visibility": "visible"
  }
}

Sample /send callback

{
  "code": 200,
  "data": {
    "changes": [
      { "id": "submit_btn",  "visibility": "hidden" },
      { "id": "day_comment", "visibility": "hidden" }
    ],
    "notifications": [
      { "title": "Thank you, we received your answer", "type": "success" }
    ]
  }
}

changes[] is a surgical patch — only listed component ids are touched. changeRules (e.g. { "options": { "action": "replace" } }) controls how arrays merge. Full reference: $CLAUDE_PLUGIN_ROOT/docs/user-flows/cdu-page-protocol.md.

Realistic viewModel shape

Every key returned in viewModel must match a {{placeholder}} somewhere in pages//config or in viewModel defaults. A representative payload:

{
  "userName": "Mykhailo Sydoreiko",
  "metric_total_value": "245 min",
  "metric_total_sub": "4.08 hr · daily activity",
  "items_table_body": [
    { "value": "row_1",
      "options": [
        { "title": "[url=https://…]Some entry[/url]", "value": "item_name" },
        { "title": "16min", "value": "item_duration" }
      ] }
  ],
  "submit_btn_visibility": "hidden",
  "self_score_visibility": "disabled"
}

Adding a new metric to the page? Add the matching key here and the matching {{key}} in pages//config.


2. Reusable node fragments

These are the contract-bound JSON shapes any brief should embed verbatim. They are reusable building blocks — you decide how they compose into a single process or several.

2.1 Condition on path (dispatch /get vs /send)

{
  "type": "go_if_const",
  "to_node_id": "",
  "conditions": [
    { "param": "path", "const": "/get", "fun": "eq", "cast": "string" }
  ]
}

A second go_if_const does the same for /send; the trailing go falls through to a default branch.

2.2 Condition on body.page (dispatch per-page)

For a multi-page form, branch on body.page after dispatching by path:

{
  "type": "go_if_const",
  "to_node_id": "",
  "conditions": [
    { "param": "body.page", "const": "index", "fun": "eq", "cast": "string" }
  ]
}

2.3 Condition on body.buttonId (dispatch per-event source for /send)

body.buttonId identifies the source of every /send event — both button clicks and submitOnChange field changes. Use go_if_const on it to route each case:

{
  "type": "go_if_const",
  "to_node_id": "",
  "conditions": [
    { "param": "body.buttonId", "const": "submit_btn", "fun": "eq", "cast": "string" }
  ]
}

2.3a Detect submitOnChange vs button click

When the same /send handler must behave differently depending on whether the user clicked a button or changed a submitOnChange field, branch on body.buttonData.action — it is present and non-empty only for field-change events:

{
  "type": "go_if_const",
  "to_node_id": "",
  "conditions": [
    { "param": "body.buttonData.action", "const": "", "fun": "ne", "cast": "string" }
  ]
}

Alternatively, check the specific field id and action together:

{
  "type": "go_if_const",
  "to_node_id": "",
  "conditions": [
    { "param": "body.buttonId",           "const": "project_name", "fun": "eq", "cast": "string" },
    { "param": "body.buttonData.action",  "const": "",             "fun": "ne", "cast": "string" }
  ]
}

Read the new value from body.data. (the full field snapshot) or from body.buttonData.value (just the newly selected value). Use whichever is cleaner for your logic; both contain the same information for single-select fields.

2.4 Fan-out to a sub-process (api_copy, fire-and-forget)

Use when you want the bound process to delegate work to a separate Corezoid process. The sub-process becomes responsible for the callback.

{
  "type": "api_copy",
  "user_id": ,
  "conv_id": "@",
  "ref": "",
  "mode": "create",
  "group": "all",
  "data": {},
  "data_type": {},
  "err_node_id": ""
}

2.5 Build viewModel (Code Node, api_code)

JavaScript pattern for assembling viewModel from an actor lookup or other sources:

const viewModel = data?.viewModel || {};
const eventData = data?.event_actor?.data || {};

viewModel.userName          = eventData.user_name || "";
viewModel.metric_total_value = `${eventData.total_min ?? 0} min`;

if (eventData.status === "complete") {
  viewModel.submit_btn_visibility = "hidden";
  viewModel.self_score_visibility = "disabled";
} else {
  viewModel.submit_btn_visibility = "visible";
  viewModel.self_score_visibility = "visible";
}

data.viewModel = viewModel;

2.6 Build changes + notifications (Code Node)

data.changes.push(
  { "id": "submit_btn",  "visibility": "hidden" },
  { "id": "day_comment", "visibility": "hidden" }
);
data.notifications.push({
  "title": "Thank you, we received your answer",
  "type": "success"
});
data.responseData = { changes: data.changes, notifications: data.notifications };

2.7 Final callback API node (/get)

{
  "type": "api",
  "method": "POST",
  "url": "{{__callback_url}}",
  "rfc_format": true,
  "content_type": "application/json",
  "extra":      { "code": "200", "viewModel": "{{viewModel}}" },
  "extra_type": { "code": "number", "viewModel": "object" },
  "extra_headers": { "content-type": "application/json; charset=utf-8" },
  "err_node_id": "",
  "version": 2
}

2.8 Final callback API node (/send)

Identical shape, with data in place of viewModel:

{
  "type": "api",
  "method": "POST",
  "url": "{{__callback_url}}",
  "rfc_format": true,
  "content_type": "application/json",
  "extra":      { "code": "200", "data": "{{responseData}}" },
  "extra_type": { "code": "number", "data": "object" },
  "extra_headers": { "content-type": "application/json; charset=utf-8" },
  "err_node_id": "",
  "version": 2
}

2.9 Complete process skeleton (bound, single-process topology)

The fragments above (§2.1–2.8) are pieces; this is how they wire together in the most common topology — a single bound process that owns both /get and /send. Use this as the default starting shape and only depart from it when the form's complexity demands a multi-process layout (see §3).

> Why this matters. The single most common failure when writing a Smart-Form > backend is forgetting that /send has two sources — a button click and > any submitOnChange field change — and processing both as a real submit. The > form then tries to persist a half-filled record on every field interaction. The > skeleton below makes that second fork explicit.

2.9.1 Flowchart
                          ┌───────┐
                          │ Start │
                          └───┬───┘
                              │
                  ┌───────────▼───────────┐
                  │ Condition on `path`   │   (§2.1)
                  └─┬───────────────────┬─┘
                    │                   │
               path=/get            path=/send
                    │                   │
         ┌──────────▼─────────┐  ┌──────▼──────────────────────┐
         │ Build viewModel    │  │ Extract                     │
         │ (api_code)  §2.5   │  │  data.buttonAction =        │
         └──────────┬─────────┘  │  body.buttonData.action     │
                    │            │  (api_code, safe ?? "")     │
                    │            └──────┬──────────────────────┘
                    │                   │
                    │       ┌───────────▼───────────────────┐
                    │       │ Condition on buttonAction     │   (§2.3a)
                    │       │  ""        ─→ real submit     │
                    │       │  "select"  ─→ submitOnChange  │
                    │       │  "check"   ─→ submitOnChange  │
                    │       │   …                           │
                    │       └─┬───────────────────────┬─────┘
                    │         │                       │
                    │    real submit           submitOnChange
                    │    (buttonId =           (lightweight
                    │     submit_btn,          ack: empty
                    │     dispatch §2.3)        changes[])
                    │         │                       │
                    │   ┌─────▼────────┐       ┌──────▼─────────┐
                    │   │ Persist /    │       │ Build empty    │
                    │   │ call CREATE  │       │ sendResponse   │
                    │   │ ACTOR / api  │       │ Data           │
                    │   │ (api_rpc /   │       │ (api_code §2.6)│
                    │   │  api §2.6)   │       └──────┬─────────┘
                    │   └──────┬───────┘              │
                    │          │ ok                   │
                    │   ┌──────▼─────────┐            │
                    │   │ Build success  │            │
                    │   │ sendResponse   │            │
                    │   │ Data (api_code)│            │
                    │   └──────┬─────────┘            │
                    │          │                      │
                    │          │   ┌── on err ────────┤
                    │          │   │                  │
                    │   ┌──────▼───▼─────┐            │
                    │   │ Build error    │            │
                    │   │ sendResponse   │            │
                    │   │ (notification) │            │
                    │   └──────┬─────────┘            │
                    │          │                      │
         ┌──────────▼───┐   ┌──▼──────────────────────▼──┐
         │ Callback     │   │ Callback to                │
         │ to           │   │ {{__callback_url}}         │
         │ {{__callback_│   │ POST { code:200,           │
         │   url}}

…

## 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.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.