SKILL.md
As tools abaixo aparecem com os nomes que o MCP da Clickmax registra. Se o seu cliente de IA prefixar nomes de tool (
mcp<servidor>,mcp<servidor>, ou outro), use o nome já prefixado que aparecer na sua lista de tools.
When this applies
Use this skill when the user wants to operate a Clickmax automation flow: list/find one, inspect its graph, create/edit/connect/delete steps, configure entry events, validate, or change lifecycle mode. A one-off "create/send an email to my leads" request is this skill too — build a minimal flow with a trigger + flowssendemail step. Do NOT reinterpret it as a landing page: a checkout button, dark theme, or urgency tone the user asks for are the email template's CTA/colors/font (flowssendemail's style params), never page markup.
Not this skill:
- Funnel page graph, offers, pages, traffic routing ->
clickmax-funnels - A page — even one the user calls "email" — that isn't sent as a message (a landing/sales page, a page to share a link to) ->
clickmax-page-editing - Building the cohort that will feed the flow -> resolve that with the relevant CRM/sales skill first, then come back to wire the automation
- Channel copy authoring in isolation -> create the message content first, then reference real ids here
Key assumptions
- Scope = one workspace; never ask for workspace id
- Granular step writes only work while the flow is
draft/template - The graph is steps connected by each step output
target; there is no separate edge object - The entry is a single
triggerstep; a flow has at most one trigger step - Trigger start/exit events live at flow level (
triggerStart/triggerExit), not inside arbitrary step fields - Standalone flows use flow-level trigger events; funnel-embedded flows (
funnelIdset) are started/exited by funnel workflow nodes instead - Two ways an automation relates to a funnel. (1) EMBEDDED — the funnel's
workflownode owns it: link/create it from the funnel side withfunnelsworkflowflow_set, which syncs the funnel's triggers onto the flow and makes it show in the funnel canvas. This is what "an automation linked to the funnel" means — build it from the funnels skill (create the funnel workflow node BEFORE the flow, then link). (2) STANDALONE SCOPED — an ordinary flow whose trigger is narrowed by afunnelId/pageIdconstraint; it reacts to that funnel's events but is NOT part of the funnel graph. Never hand-set a flow'sfunnelIdor hand-craft funnel triggers — the funnel workflow node's link tool does that; settingfunnelIdalone leaves an orphan (list badge shows, funnel canvas empty) - Step ids are server-generated; always read real ids from create output or
flowsstructureget - When the user is inside the flow builder, the currently-open flow (its
flowId+ every step with full content + the edges between them) is published to screen context underflows3.builder; read it before asking which flow/step the user means, and target edits at thatflowId. IfselectedStepIdis set, that is the node the user has focused on the canvas — prefer it when they say "this step/node" or open the assistant from a node without naming one. Thelabelsmap resolves the entity UUIDs inside step inputs (tags, lists, products) to human names — read names from there so you never echo a raw UUID back to the user - Destructive deletes require explicit confirmation unless the user already made deletion explicit
- Read [lifecycle and safety](references/lifecycle-and-safety.md) when deciding between draft edits, activation, closure, archive, or destructive delete.
- Read [step types](references/step-types.md) when choosing which step type/action/input shape fits the requested automation.
- Read [email authoring](references/email-authoring.md) before writing an email step's content — the default slot template only ever recolors, never truly restyles; a genuinely designed email needs
customHtml. - Read [WhatsApp templates](references/whatsapp-templates.md) before writing a WhatsApp step — free-form text only reaches contacts inside the 24h window, so every other trigger needs an approved template.
- Read [trigger events](references/trigger-events.md) when mapping user intent to flow entry events + constraints.
- Read [examples](references/examples.md) when you need a concrete build/branch/inspect pattern.
Thought process
- Classify the request: read/list/inspect/validate vs create/edit/connect vs lifecycle/destructive.
- Resolve
flowIdfirst. Ifflows3.builderscreen context is present, use itsflowId(the user is editing that flow); otherwise find an existing flow by name, or create one indraft. - Check whether the flow is editable before planning step writes.
- Build trigger-first: create or inspect the entry trigger, then downstream steps, then connections, then validate.
- Prefer
flowsstructuregetas the canonical compact graph view before connecting, deleting, or diagnosing. - Activate only after validation passes and the user explicitly wants the flow running on real contacts.
Execute guide
- For a new flow, use
flowscreatefirst, then add the singletriggerstep withflowsstepcreate, then create downstream steps, connect them withflowsstepconnect, and finish withflowsvalidate. Shortcut:flowsstepcreateand everyflowssend*tool accept an inlinetarget— wire a step's output to the next step id in the SAME create call instead of a separateflowsstepconnectround-trip; only useflowsstepconnectfor connecting steps after the fact (e.g. rewiring, or connecting a conditional'strue/falsebranches). category(onflowscreate/flowsupdate) is a FIXED ENUM, not free text — one ofatendimento,vendas,suporte,marketing,cobranca,onboarding,retencao,pesquisa,agendamento,qualificacao,feedback,notificacao,integracao,teste,outro. Pick the closest match from this exact list; guessing a plausible-sounding word outside it (e.g.recuperacao) fails validation. It's optional — omit it entirely if none fit well.- For an existing flow, check editability with
flowsgetmode, inspect the current graph withflowsstructureget, apply only the neededflowsstep*mutations, and validate again before any lifecycle change. - Use
flows_updateonly for flow metadata such as name/category; it does not edit the step graph. - Read the valid
actionnames and theirinputfields fromflowsactionscatalog, and aconditional's validstatements[].typeand its fields fromflowsconditionalscatalog, BEFORE writing any non-message step. These are the only authoritative sources for those shapes — the catalogs also markcomingSoonactions that cannot be used yet. Never guess anaction, astatement.type, or aninputkey. An invented key inside an otherwise validinputis not rejected — it is simply never read by the engine (removeFromOtherPipelinesonassignOpportunityis exactly this, written by the flows3 drawer and consumed by nobody), so the step reports created and configures nothing. The shapes worth memorizing (and theassignOpportunityopportunityIdtrap) are in [step types](references/step-types.md).
- Read the valid entry/exit events from
flowstriggerscatalogbefore suggesting or setting a trigger — it returns each event's friendlylabel,description, and thescopesit can be narrowed by; pick the exacteventNameand never invent one. See [trigger events](references/trigger-events.md). - Use
flowssteptriggers_setonly when changing entry events, and send the completetriggerStart/triggerExitarrays that should remain on the flow. - For a flow linked to a funnel workflow node, keep flow-level trigger arrays empty unless the user is intentionally converting it into a standalone automation; wire entry/exit from the funnel skill instead.
- Use
flows_listto find candidate flows by name before asking for confirmation on ambiguous matches. - Use
flowsstructuregetas the canonical graph view before connecting, deleting, or diagnosing steps. - Use
flowsvalidatebefore activation and surfacehasEntryTrigger,danglingTargets,orphanStepIds, andincompleteChannelSteps(channel steps — email/telegram/WhatsApp — missing their sender id:emailSenderSignatureId,telegramBotId, orgupshupAppIdundernumberStrategy: 'fixed'), not justvalid. Resolve anyincompleteChannelStepsbefore activating — withemailsendersignatureslist/channelinstanceslist, thenflowsstepupdate— rather than retryingflows_activateunchanged: a channel step without a real sender id fails on every single send no matter what activation itself currently checks, so never treat a clean validation as a substitute for having resolved the sender at creation. - For branching, connect each branch explicitly with the correct
handle, such astrue/falsefor conditionals.
- WhatsApp steps are TEMPLATE-first.
flowssendwhatsappREJECTSformat: 'text'unlessnumberStrategy: 'context', because free-form text only delivers inside the 24h customer-care window and only a flow started by the contact's own inbound WhatsApp message guarantees that window is open. Every other trigger (funnel, tag, schedule, checkout) takes a template. Order to follow, cheapest first: 1)gupshuptemplateslistfor an existingapprovedtemplate that already says what the user wants; 2) for a generic use case (OTP, order update, reminder),gupshuptemplatelibrarylist+gupshuptemplatelibrarycreate— Meta pre-vetted, near-instant approval; 3) otherwise author one withgupshuptemplatescreate, show the exact copy to the user, and only thengupshuptemplatessubmit. See [WhatsApp templates](references/whatsapp-templates.md). - Never stall the build waiting for Meta. A template still
pendingcan already be wired into the step — create the automation, then tell the user plainly that WhatsApp starts sending once Meta approves the template (hours to days) and that everything else runs immediately.
- Minimal build pattern: [create -> trigger -> action](references/examples.md#create---trigger---action)
- Linear automation pattern: [trigger -> delay -> sendmessage](references/examples.md#trigger---delay---sendmessage)
- Branch pattern: [conditional -> true/false branch](references/examples.md#conditional---truefalse-branch)
- Read-only diagnostics: [inspect -> validate](references/examples.md#inspect---validate)
Report
- Write every user-facing reply in plain business language: use entity names (never UUIDs), never show code, tool names, or internal field names (
triggerStart,triggerExit,eventName,tagId). Those are for your own reasoning, not the reply — e.g. say "this flow now starts when the VIP tag is applied", not the event name or id. - For list/find: compact candidate table (
name,mode,category), not full raw graph dumps - For create/build/edit: confirm what changed in user terms (which trigger, which steps, what happens next) — not step ids or edge internals
- When summarizing one specific created/read automation in a visual card, use the automation/flow name as the large headline/value. Put node count, status, channel mix, and similar build metrics in pills, sub-metrics, or
value-suffix, not as the main headline. - For validate: always surface
hasEntryTrigger,danglingTargets,orphanStepIds, andincompleteChannelSteps, even whenvalid=true. WhenincompleteChannelStepsis non-empty, say plainly that the listed message step(s) have no real sender configured (which channel/step, in user terms — never the raw field name) and that the flow will not deliver until that's resolved, then offer to fix it (list the workspace's numbers/bots/sender signatures and set the one the user picks) - For lifecycle: explain the new mode in user terms (
active= processing real contacts;closed/archived= stopped) - Cap long step/edge lists; summarize rather than dumping giant payloads
Warnings
flows_createneeds a realprojectId; resolve it, never invent itflows_updateis metadata-only and does not edit the graphflows_deleteremoves the flow and all steps permanentlydelay/timeoutnumericwhenvalues are hours, not minutes or daysflowssteptriggers_setedits the entry/exit events independently: send only the side you are changing (triggerStartortriggerExit) and omit the other to keep it; an explicit[]clears a side, and the array you do send replaces that side. Use the exacteventNamefrom the [trigger events](references/trigger-events.md) catalog — an unknown/guessed name silently never fires. Scope with the entity id the catalog lists for that event (e.g.tagId,offerId)- Conditional,
collect, andtimeoutbranches depend on correcthandlewiring; missing branch targets usually show up as dangling targets or orphaned paths - Unknown
actionnames or wronginputshapes are rejected; fix the payload, do not assume partial success gupshuptemplatessubmitsends the template to Meta for review — external and practically irreversible (a rejected or low-quality submission affects the number's quality rating). Confirm the exact final copy with the user before calling it; never submit content you authored on your own, and never submit "to see if it passes".gupshuptemplatescreatevalidates the template against Meta's rules before saving and returns EVERY violation at once. Fix them all in the next call instead of retrying the same payload — the error text says what to change.- Message personalization uses single-brace lead tokens —
{name},{email},{telephone}— never{{name}}or{{lead.name}}; an unknown/misformatted key is delivered to the lead literally. Use them as fact, do not ask the user which format applies (GupShup/WhatsApp templates are the only exception: positional{{...}}paramMapping). See [step types](references/step-types.md). - Never echo a raw UUID to the user. Step inputs store tags/lists/products by id; resolve them to names via the
flows3.builderlabelsmap (or the matchingclickmax-tags/list/product lookup tool when an id is absent fromlabels). A UUID in your reply is a bug — report "the tag Black Friday", not its id. - Never wire a step's
target(viaflowsstepconnector the inlinetargetonflowsstepcreate/flowssend*) back to the flow'striggerstep id. The trigger is the entry point only; any step pointing back at it makes the worker reprocess the automation from the start forever (infinite loop). The backend rejects this with a 400 — treat that error as confirmation the graph you were building was wrong, not something to retry.
Anti-patterns
- Asking the user for workspace id or a hidden platform id
- Guessing
flowIdor step ids instead of resolving them - Editing steps on non-editable modes instead of stopping and explaining the constraint
- Treating
valid=trueas publish-ready while ignoring dangling targets or orphan steps - Activating a flow without explicit user intent to start real processing
- Creating a second flow to retry after a step/connect/trigger error — keep editing the same
flowIdand fix the failing call; recreating leaves duplicate half-built automations - Guessing a trigger
eventName(e.g.contactcaptured) instead of reading the exact one fromflowstriggers_catalogfirst - Guessing an
actionname, aconditionalstatements[].type, or an action'sinputkeys instead of readingflowsactionscatalog/flowsconditionalscatalogfirst - Passing an opportunity/card id as
assignOpportunity'sopportunityId— that field is the PIPELINE id - Writing a
delaywith a unit field ({ type: 'days', when: 3 }); there is no unit, a numericwhenis always HOURS - Hand-setting a flow's
funnelId(or hand-crafting funnel triggers) to "link" it to a funnel — an embedded automation is linked from the funnel'sworkflownode viafunnelsworkflowflow_set(funnels skill);funnelIdalone leaves an orphan (badge shows, funnel canvas empty) - Connecting any step's output back to the
triggerstep id — infinite loop, always rejected by the backend