Simulator.Company actor (record) specialist. Use when the user wants to create, update, read, search, or filter the *instances* of a form template (a.k.a. Account Template records) — i.e. data-bearing actors — and needs the `data` value protocol right. Activate when the user says "create an actor", "add a record", "create a record from this template", "fill in a form", "update actor data", "find actors where field = …", "filter actors by balance", "создай актор", "заполни шаблон", or "добавь ...
Installs into .claude/skills of the current project.
Are you the author of Simulator Actors?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/corezoid-simulator-actors)
---
name: simulator-actors
description: >
Simulator.Company actor (record) specialist. Use when the user wants to create,
update, read, search, or filter the *instances* of a form template (a.k.a.
Account Template records) — i.e. data-bearing actors — and needs the `data`
value protocol right. Activate when the user says "create an actor", "add a
record", "create a record from this template", "fill in a form", "update actor
data", "find actors where field = …", "filter actors by balance", "создай актор",
"заполни шаблон", or "добавь запись". ALSO use this skill when the user asks what
**processes / functions / Corezoid processes** an actor has or can call, or about an
actor's **shared API keys / available functions** — call `getCorezoidProcesses`:
"what processes/functions can this actor call", "actor's connected processes",
"actor's API keys", "available functions of the actor", "які процеси/функції доступні
актору", "процеси актора", "функції актора", "ключі доступу актора", "какие
процессы/функции у актора", "процессы актора", "доступные функции актора". For
graph/flowchart STRUCTURE (links, layers, FlowchartBlock diagrams) use `simulator-graph`;
for designing the template itself use `simulator-forms`.
---
> **Curated tool names (v2 server):** `createActor`, `getActor`, `getActorByRef`,
> `updateActor`, `setActorStatus`, `deleteActor`, `searchActors`, `filterActors`,
> `searchLayerActors`, `getSystemActor`, `getCorezoidProcesses`. Call them by these exact names.
>
> **`getCorezoidProcesses(actorId)`** is THE tool for any question about an actor's
> **processes / functions / available API integrations** — it returns the Corezoid processes
> shared to the actor via its access API keys (what that actor can call). If the user asks
> "what functions/processes does this actor have", "what can this actor call", or about the
> actor's shared API keys, call `getCorezoidProcesses` — do not guess or use a graph-traversal tool.
>
> **`getSystemActor`** resolves the system "twin" actor of a workspace entity — pass
> `objType="user"`, `objId="<userId>"` to get the actor representing a user (so you can attach
> accounts to it or move value between users). Find the `userId` first with `searchUsers` /
> `getUsers`. Money movement between users then goes through their twin actors' accounts via
> **transfers** — see `simulator-finance`.
# Simulator.Company Actor (Record) Specialist
You create and manage **actors** — the *instances* of a form template (Account
Template). An actor's field values live in its `data` object. Getting the `data`
shape right is the whole job, so this skill exists to make that mechanical.
> **Relationship to the other skills**
> - **`simulator-forms`** designs the *template* (`sections`/fields). Read it / a form
> first to learn the field `id`s.
> - **`simulator-actors`** (this skill) creates/edits the *records* of that template.
> - **`simulator-graph`** handles graph *structure* — links, layers, FlowchartBlock
> diagrams. If the user wants to wire actors together or place them on a layer, defer there.
> - **`simulator-finance`** handles accounts/transactions on actors.
## Workspace Context Check (MANDATORY FIRST STEP)
Verify `accId` is known before any tool call. If not provided, ask:
> Ask the user — **in their own language** (English, Ukrainian, or Russian) — which workspace to work in, i.e. for the Workspace ID (`accId`).
`createActor` can also resolve a `formName` to its id, but only with a workspace set.
---
## The golden rule: `data` is keyed by field `id`
An actor's `data` is keyed by each form field's **`id`** (`item_<digits>`) — **not** by
the field `title` and **not** by its secondary `key`. So the first step of *every* actor
create/update is:
1. **Resolve the form.** `getForm(formId)` (or `searchForms` then `getForm`). Pass
`filter="id,title,sections"` to keep it small.
2. **Map each field you want to set** → its `id` and `class`.
3. **Build `data`** using the per-class value shapes below.
### Value shape by field class
| Form field class / source | Value in `data` |
|---|---|
| `edit` text / password / email / phone | string — `"dsdf@fsdf.com"` |
| `edit` int / float | number — `1` |
| `check` | boolean — `true` |
| `radio` | the selected option's `value` (string) — `"o2"` |
| `select` (static `options`) | array of chosen option object(s) — `[{"color":"#863434","title":"one","value":"s1"}]` |
| `select` → `layer`/`actorFilter`/`actorsBag`/`actors`/`formFilter` | `[{"type":"actor","title":…,"value":"<actor UUID>"}]` (formFilter = the actors of a given form) |
| `select` → `forms` | `[{"type":"form","title":…,"value":<form id number>}]` |
| `select` → `currencies` | `[{"type":"currency","title":…,"value":<currency id number>}]` |
| `select` → `accountNames` | `[{"type":"accountName","title":…,"value":"<account-name UUID>"}]` |
| `select` → `workspaceMembers` | `[{"type":"workspaceMembers","title":…,"value":<user id number>}]` |
| `select` → `api`/`corezoidSyncApi` | array of synced options (`[]` until synced) |
| `multiSelect` | array — `[{"title":"one","value":"…"},{"title":"two","value":"…"}]` |
| `calendar` | `{"startDate":…,"endDate":…,"timeZoneOffset":-180,"sendInvite":false}` (unix **seconds**) |
| `upload` | array of file refs (`[]` when empty) |
| `label` / `button` / `image` | **no entry** — display-only |
> The `type` discriminator only appears on **dynamic** `select` values. Static
> `select`/`multiSelect` values carry just `{title,value,color?}`. For a dynamic
> `select`, the `value` must be a real referenced id (actor UUID / currency id /
> account-name UUID / user id) — resolve it first (e.g. `getCurrencies`,
> `getAccountNames`, `searchActors`) rather than guessing.
> **Geolocation (top-level, not `data`).** An actor carries an optional position independent
> of its form fields: `geoPosition` — `{"lat": <number>, "lon": <number>}` in WGS84 decimal
> degrees, or `null` to clear — and `geoName` — a location name string, or `null`. Both are set
> on `createActor`/`updateActor`. Latitude is hard-bounded to -90..90 (out of range is rejected),
> longitude outside ±180 wraps cyclically, and coordinates round to 6 decimals; `lat`/`lon` are
> set as a pair.
Full reference: `$CLAUDE_PLUGIN_ROOT/docs/entities/actors.md` and `…/forms.md`.
### Multiform actors (`__form__<formId>:<itemId>`)
An actor can instantiate **several forms at once** (a *multiform* actor; the linked form
tree is called a **UAT**). Its `data` then carries fields from more than one form, namespaced
by a key prefix:
- Fields of the actor's **root** `formId` (the one you pass to `createActor`/`updateActor`) →
the **plain** field `id`, e.g. `"name"`.
- Fields owned by **another** form → **`__form__<thatFormId>:<itemId>`**.
```json
// data for an actor created under its root form, with one field from form 16951
{
"name": "Kulo Oleksandr",
"__form__16951:position": "Software engineer"
}
```
The prefix changes only the **key** — the value still follows the per-class shapes above.
Notes:
- To learn `<thatFormId>`'s field ids, `getForm(<thatFormId>)` just like the root form.
- **Discover the tree** with `getFormsTree(accId, formId)` / `getLinkedForms(typeLink, formId)`
(see `simulator-forms`) to find which forms a multiform actor spans before writing its `data`.
- Attaching the *set* of forms to an actor (`PUT /actors/actor_forms`) is still **not** a curated
tool — but you can already write/read multiform `data` via `createActor`/`updateActor`/`getActor`.
#### Creating under the tree when asked for a CHILD (leaf) form
In a UAT workspace, an actor can only be created under the **root** form of the tree — not
under an arbitrary leaf. So when the user says *"create an actor for form X"* and
`getForm(X)` returns a **non-empty `parentId`** (X is a nested/child form), do **not** call
`createActor(formId=X, …)` — the backend rejects it with **`400: Form <id> is not UAT`**.
Instead:
1. **Walk up `parentId`** from X to the root form of the UAT tree (`getForm` repeatedly until
`parentId` is empty).
2. **Call `createActor` with `formId` = the root.**
3. Put the **root's own fields** under their plain id (`"name"`), and the **requested child
form's fields** under the `__form__<childFormId>:<itemId>` prefix.
```json
// Request: "create an actor for form Employee (16951)", where Employee.parentId = People (16950)
// → create under the ROOT People (16950), not under Employee:
createActor(formId=16950, title="Olena Kovalenko", data={
"name": "Olena Kovalenko", // People (root) field
"__form__16951:position": "Senior Backend Engineer" // Employee (child) field
})
```
> **Do NOT** flip the child form to `uat` status via `setFormStatus` to "work around" the
> error — that mutates the shared template for everyone. Use the **root** form as the
> `formId` instead.
---
## Create an actor
```
createActor(
formId=42, # or formName="Car" (resolved via the workspace)
title="Toyota Camry 2023",
color="#409547", # optional
ref="car-toyota-camry-2023", # optional, unique per form
contextLayerId="<layer UUID>", # optional — place it on a layer
data={
"item_make": "Toyota",
"item_model": "Camry",
"item_year": 2023,
"item_active": true,
"item_cond": [ {"title":"excellent","value":"c1"} ],
"item_owner": [ {"type":"workspaceMembers","title":"Alex Kulo","value":1} ]
})
```
- Provide **`formId`** (number) or **`formName`** (string, resolved to its id).
- Omit fields you are not setting; never invent `item_*` keys not present in the form.
- Display-only fields (`label`/`button`/`image`) get no `data` entry.
## Read an actor
```
getActor(actorId="<UUID>", filter="id,title,data") # by UUID
getActorByRef(formId=42, ref="car-…", filter="id,title,data") # by (form, ref)
```
Use `filter` to fetch only the fields you need — actor `data` can be large.
## Update an actor
```
updateActor(
formId=42, actorId="<UUID>",
data={ "item_year": 2024, "item_active": false }) # only these keys change
```
`updateActor` is a **partial** update of `data` — keys you include are replaced, the rest
are untouched. You can also set `title`/`description`/`color`/`status`/`ref`. To clear a
multi-value field, send `[]`.
**Re-key by `ref`.** `updateActor(formId, actorId, ref="…")` sets or changes the actor's
external reference — a stable business key, **unique per form** — the same key `createActor`
accepts, but now editable after creation. Then address the actor by its key instead of its
UUID: `getActorByRef(formId, ref)`. Omit `ref` to leave it unchanged.
**Embed a smart form (script) in an actor.** Set `appId` (on `createActor` / `updateActor`)
to a Smart Form (CDU/Script app) actor id — the actor's card then renders/runs that smart
form; `appSettings` `{autorun, expired, users, groups, fullWidth}` tunes it. See
`simulator-smart-forms`.
**Rich `description` (BBCode).** An actor's `description` renders **BBCode** — chips like
`[actor=<otherActorId>]Label[/actor]` (nested actor card) and `[application=<smartFormId>]Label[/application]`
(smart-form chip), plus formatting (`[b]`, `[color=…]`, `[h2]`, `[ul][*]…[/ul]`, `[url=…]`) and
`[md]…[/md]` for markdown. Fetch the environment's exact tag set with **`getBbcodeTags`**.
**BBCode is processed only OUTSIDE `[md]` blocks.** The reverse matters too: a `description` is rendered as **BBCode by default, not markdown**, so any markdown you write (`##`, `-`, `**bold**`, tables) MUST be wrapped in `[md]…[/md]` or it shows as literal text — applies to every `createActor`/`updateActor` `description`, Events actors (chats/meetings/tasks) included (e.g. `description="[md]## Agenda\n- item[/md]"`). See `docs/entities/reactions.md` → "Embedding".
## Holes — empty placeholder nodes
A **hole** is an empty placeholder slot on a graph, rendered as a hollow node: it marks a
position in the structure that is **not yet filled**. A hole becomes a normal actor once it is
filled with data — ideal for laying out a template / "company DNA" graph up front and turning
each slot into a real actor as the data arrives.
```
createActor(formId=3279, title="Budget", hole=true) # create a hole
updateActor(formId=3279, actorId="<UUID>", hole=true) # turn an existing actor into a hole
updateActor(formId=3279, actorId="<UUID>", hole=false) # fill it — hole → normal actor
```
- `hole` is a top-level **boolean** on `createActor` / `updateActor`; omit it → default `false`.
- It is independent of `status` and `data` (a hole can still carry a `title`). `hole=false`
alone flips a hole back to a normal node.
- Place a hole on a layer like any node (e.g. `manageLayerActors` — see `simulator-graph`).
## Status & delete
```
setActorStatus(actorId="<UUID>", status="verified")
deleteActor(actorId="<UUID>") # irreversible — confirm with the user first
```
---
## Search & filter
### `searchActors` — free-text across the workspace
```
searchActors(accId="ws_xxx", query="camry", limit=20, filter="id,title,formId")
```
Best for "find the actor named …". Run before `createActor` to avoid duplicates.
### `filterActors` — list/rank a form's actors, optionally by an account balance
```
# All actors of a form, newest first
filterActors(formId=42, orderBy="updated_at", withStats=true)
# Data-field filter on the actor data
filterActors(formId=42, q="status=active", status="verified,pending")
# Rank by an account's CURRENT balance, scoped to one anchor actor's neighbours
filterActors(
formId=42,
linkedToActorId="<anchor UUID>", # only actors linked to this one (both directions)
accountNameId="<account-name UUID>",
currencyId=9,
amountFrom=1000, # balance >= 1000
orderBy="balance", orderValue="DESC",
withStats=true)
# Only the CHILD actors of a node (e.g. expand/collapse a node's children)
filterActors(formId=42, linkedToActorId="<anchor UUID>", linkedToActorDirection="children")
# ...or only its parents: linkedToActorDirection="parents"; omit / "both" = either direction (default)
```
- `q` filters on actor **data** fields; `search` does full-text on the title; `status`
filters by status.
- Balance filtering is **current balance only**. For turnover over a period, read each
actor's accounts with `getAccounts(actorId, from, to)` (a `simulator-finance` task).
- Returned balances are real decimal values — do **not** divide by `10^precision`.
### `searchLayerActors` — search within one layer
```
searchLayerActors(actorId="<layer UUID>", query="camry")
```
---
## End-to-end example
```
# 1. Resolve the template and its field ids
searchForms(accId="ws_xxx", q="Car") → formId 42
getForm(formId=42, filter="id,title,sections") → field ids: item_make, item_year, …
# 2. Avoid a duplicate
searchActors(accId="ws_xxx", query="Camry 2023")
# 3. Create the record
createActor(formId=42, title="Toyota Camry 2023",
data={ "item_make":"Toyota", "item_model":"Camry", "item_year":2023 })
# 4. (optional) attach an account — see simulator-finance
createAccount(actorId="<new UUID>", nameId="<aname>", currencyId=1, accountType="fact")
```
## Reference Documents
| Path | When to read |
|---|---|
| `$CLAUDE_PLUGIN_ROOT/docs/entities/actors.md` | Actor `data` protocol + per-class value shapes |
| `$CLAUDE_PLUGIN_ROOT/docs/entities/forms.md` | Field-class catalogue / dynamic select sources |
| `$CLAUDE_PLUGIN_ROOT/docs/entities/search.md` | Search & filter internals |
## Tips
- Always `getForm` first — `data` keys are the form's field `id`s, not titles.
- If a form has a `parentId`, it's a **leaf** of a UAT tree — create the actor under the **root** form and put the leaf's fields under `__form__<childId>:<field>`. Symptom of using the wrong root: `400: Form <id> is not UAT`.
- Dynamic-`select` values reference real ids; resolve them, don't guess.
- `createActor` accepts `formName` (resolved in the active workspace) when you don't have the id.
- `updateActor` is partial; `deleteActor` is irreversible — confirm first.
- For wiring actors into a graph (links/layers/flowcharts) use `simulator-graph`.
- `getCorezoidProcesses(actorId)` lists the Corezoid processes shared to an actor via its access API keys — i.e. the functions/processes that actor can call.