| 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 ids.
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:
- Resolve the form.
getForm(formId) (or searchForms then getForm). Pass
filter="id,title,sections" to keep it small.
- Map each field you want to set → its
id and class.
- 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>.
{
"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:
- Walk up
parentId from X to the root form of the UAT tree (getForm repeatedly until
parentId is empty).
- Call
createActor with formId = the root.
- Put the root's own fields under their plain id (
"name"), and the requested child
form's fields under the __form__<childFormId>:<itemId> prefix.
createActor(formId=16950, title="Olena Kovalenko", data={
"name": "Olena Kovalenko",
"__form__16951:position": "Senior Backend Engineer"
})
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 ids, 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.