Docyrus Automation Design
Build an automation with docyrus automation, then validate its trigger/node graph and test that it actually fires. An automation = one trigger (the event) + an ordered graph of action nodes (what runs). This skill is the design workflow; the platform's conceptual catalog of every trigger and node type lives in the docyrus-platform skill (references/automation-and-workflows.md), and the exhaustive CLI flags are available via docyrus automation … --help (command index: docyrus-cli-app). This skill ties them together and records the gotchas that only surface when you actually run the commands.
Workflow
Follow in order. An automation that hasn't been validated and test-run is not done.
-
Confirm app + auth. Every automation belongs to an app.
docyrus auth who --json # confirm session + tenant docyrus apps list --json # find the target appSlug / appIdNo session → stop and ask the user to run
docyrus auth login. -
Design before issuing commands. Decide: the trigger (which event; which data source it watches), then the action nodes in order, each node's type, its condition (does it run?), and its field mappings (what data it writes/sends). Sketch the graph for the user and confirm. See references/trigger-and-node-catalog.md to choose types.
-
Create the automation + its first trigger (one atomic call — see Create). You must pass a
--triggerType; the automation cannot exist without one. -
Add more triggers only if the same actions should fire on multiple events (optional — see Triggers).
-
Add action nodes in order. Simple scalar config goes via flags; all complex config (
data,field_mapping,condition, …) goes via--data/--from-file. Sequence/branch with each node'sparent. See Action nodes. -
Validate the graph — re-read the automation, its triggers, and its nodes; confirm types, conditions, and mappings landed. See Validate.
-
Test — trigger the automation for real (create/modify a record, hit the webhook, or run it manually) and confirm the actions happened; then clean up. See Test.
A full worked example (record-created → conditional notification + child-record creation) with validation and a run is in references/workflow-examples.md. Read it before your first build.
Command cheat-sheet
Selectors: --appId | --appSlug (one of), --automationId, --triggerId, --nodeId. Write commands take --data '<json>' or --from-file ./x.json; explicit flags merge over the JSON. Output: append --json (or --format json).
⚠️
automationhas noslug. Automations are addressed only by--automationId(grab it fromautomation list/create). Enabled/disabled state is the numericstatus(0–5), not a boolean. Per-trigger and per-node on/off is theactiveboolean.
Create an automation
docyrus automation create --appSlug crm \
--name "Notify on new deal" --triggerType recordCreated \
--sourceDataSourceId <deals-data-source-id> --json
--nameand--triggerTypeare required. The create call inserts the automation and its first trigger in one shot. ⚠️ The create response is minimal ({id}— nostatus, notriggers[]). The trigger andstatus:1are there; GET the automation to see them.--triggerTypemust be the camelCase value (recordCreated,recordModified,recordDeleted,recurrence,appEvent,webhook,emailhook,webform,buttonActivation,manualActivation). ⚠️automation createdoes NOT validate or normalize--triggerType— a wrong value likerecord-createdis stored verbatim (no error) and the trigger silently won't fire. (Verified: kebabrecord-createdwas saved asrecord-created, not normalized.) The--typeoncreate-trigger/create-nodeis the kebab form (record-created) and is normalized server-side to the camelCase stored value. So: camelCase for--triggerType, kebab for--type— and the danger with--triggerTypeis silent corruption, not a 422.--sourceDataSourceIdoncreatesets the automation-levelsource_data_source_id(verified) — the first trigger's ownsource_data_source_idstays null. That's fine for record triggers (they use the automation source); to set a trigger's own source explicitly, add it withcreate-trigger --sourceDataSourceId.--statusdefaults to1(enabled);0–5valid.
Triggers
A trigger is created/updated by type (kebab-case --type); it is deleted type-independently.
docyrus automation create-trigger --appSlug crm --automationId <id> \
--type record-modified --sourceDataSourceId <ds-id> \
--modifiedColumns "status,amount" --modifiedColumnsCondition any --json
docyrus automation list-triggers --appSlug crm --automationId <id> --json # derived from the automation
docyrus automation delete-trigger --appSlug crm --automationId <id> --triggerId <tid> --json
Trigger --type (kebab): record-created, record-modified, record-deleted, recurrence, app-event, webhook, emailhook, webform, button-activation, manual-activation. Per-type flags (recurrence schedule, modified-columns, webhook name, …) are in references/trigger-and-node-catalog.md. list-triggers/get-trigger are derived client-side from the automation read — there is no separate trigger GET endpoint.
Action nodes
# scalar config via flags
docyrus automation create-node --appSlug crm --automationId <id> \
--type create-record --name "Create task" --targetDataSourceId <tasks-ds-id> --json
# complex config (mappings/data/condition) via --data
docyrus automation create-node --appSlug crm --automationId <id> \
--type send-notification --name "Ping owner" \
--data '{"data":{"subject":"New deal","message":"{{name}} created"},"condition":{...}}' --json
docyrus automation list-nodes --appSlug crm --automationId <id> --json
docyrus automation update-node --appSlug crm --automationId <id> --nodeId <nid> --type create-record --data '{...}' --json
docyrus automation delete-node --appSlug crm --automationId <id> --nodeId <nid> --json
- Every node takes a
--name. Node--type(kebab):external-action,send-email,send-notification,create-record,update-records,request-approval,request-input,http-request,data-source-query,custom-query,generate-document,ai-prompt,ai-agent,execute-script,wait-for. - Complex objects are never flattened into flags.
data,field_mapping,dynamic_field_mapping,condition,input_template,target_data_source_conditionmust be supplied through--data/--from-file. Per-typedatashapes are in references/trigger-and-node-catalog.md. - Sequencing/branching is by
parent, not array order: set a node'sparentto the UUID of the node it runs after. Root nodes (noparent) run off the trigger. A node'sconditionobject gates whether it runs.
Critical rules
--triggerType(onautomation create) is camelCase (recordCreated) and is not validated — a wrong value is stored verbatim and silently breaks the trigger (no 422).--type(oncreate-trigger/create-node) is kebab-case (record-created) and is normalized server-side. Don't cross them.- Create responses are minimal.
automation create,create-trigger, andcreate-nodeecho little more than{id}—status,triggers[], nodetype/target/mappings come back null/empty in the create response but are persisted. Always GET/list to validate, never trust the create response's blanks. - An automation is born with its first trigger. You cannot create a triggerless automation —
--triggerTypeis required oncreate. - Nodes/triggers require an existing automation. Every node/trigger op first asserts the automation exists (404 otherwise). Create the automation first.
- Complex node config goes in
--data/--from-file, never flags. Flags only carry scalar ids/strings/bools. - Graph order is
parent-linked, not insertion order. Wireparentto control sequence and branches. - Validation failures return HTTP 422 (
"Invalid data received for parameters"), not 400. Service-layer rejections (e.g. external-action schema checks) return 400/404. (See the catalog for the external-action 400/404 rules.) - Unknown JSON keys are NOT rejected (the API runs
whitelist:false) — a mistypeddatakey passes validation and is silently ignored. Spell keys exactly (snake_case top-level; some nesteddataobjects use camelCase — see catalog). statusis an int 0–5, not a boolean. Per-trigger/per-node enable is theactiveboolean.external-actionneeds a realaction_type_id(acore_actionof groupexternalAction); internal node types auto-assign theiraction_type_idfrom the kebab--type.agent tasks/recurring-tasks≠ automations. Scheduling recurring work is therecurrencetrigger here; thedocyrus agent tasksgroup is unrelated (and currently non-functional).- Validate then test, every time. Re-read the graph and fire the trigger once. Delete throwaway records/automations you create.
Validate
After authoring, confirm the graph is exactly what you intended:
docyrus automation get --appSlug <app> --automationId <id> --json— confirmname,status,source_data_source_id, and the embeddedtriggers[].docyrus automation list-triggers --appSlug <app> --automationId <id> --json— confirm each trigger'stype, watched data source, and per-type config (recurrence_*,modified_columns, …).docyrus automation list-nodes --appSlug <app> --automationId <id> --json— confirm every node'sname,parent(sequence),condition,data, andfield_mapping. ⚠️ Every internal node'stypereads back as"action"(the generic node type) — the specific action identity is the auto-assignedaction_type_id, not the kebab--typeyou passed. Useget-nodeto confirmdata/field_mapping/target_data_source_idlanded (the create response omits them).
Detailed "what correct looks like" checklist is in references/workflow-examples.md.
Test
Prove it fires:
- Record/button/manual triggers: create or modify a record in the watched data source (
docyrus ds create …) so the trigger condition matches, then read back the side effects (the created/updated record, a notification, etc.). - Recurrence: confirm the schedule fields; for an immediate check, also attach a
manual-activationtrigger and run it, or lower the interval temporarily. - Webhook/emailhook/webform: confirm the auto-created
tenant_webhook/webform binding exists, then post to it. - Clean up: delete throwaway records, then
docyrus automation delete --appSlug <app> --automationId <id>for any test automation.
Full test playbook is in references/workflow-examples.md.
References
- references/trigger-and-node-catalog.md — Every trigger type and action-node type: when to use it, its scalar flags, and its
data/mapping shape (with key casing). Plus the validation/casing gotchas per type. - references/workflow-examples.md — End-to-end worked automation (trigger + conditional multi-node graph), the validation checklist, and the run/test playbook.
- docyrus-platform →
references/automation-and-workflows.md— the conceptual catalog (what each trigger/node means). docyrus-cli-app — CLI command index;docyrus automation … --helpfor exhaustive flags. Fordata-source-query/custom-querynode payloads and field mappings, see docyrus-api-dev →references/data-source-query-guide.mdandreferences/formula-design-guide-llm.md. For theexecute-scriptnode's in-sandbox SDK (api.queryDSQL +api.ds.*CRUD, injectedrecord/data), see references/trigger-and-node-catalog.md; forapi.queryDSQL syntax see the docyrus-dsql-query-design skill.