About pipefy-ai-agents
A skill for configuring conversational AI agents attached to Pipefy pipes. It guides users through discovering events and actions, validating behaviors, and creating or checking agents, including capabilities, LLM providers, and knowledge sources.
Key features
- 01List, create, update, and deactivate AI agents
- 02Discover trigger events and available actions
- 03Validate behavior structures and field identifiers
- 04Configure capabilities and LLM providers
- 05Attach knowledge sources
Use cases
- 01Create an event-triggered conversational agent for a pipe
- 02Validate card-update or card-movement actions
- 03Configure OCR capabilities or knowledge sources
MCP support
Provides AI-agent management guidance for MCP and CLI surfaces; the corresponding surface invokes Pipefy tools for operations.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ pipefy/ ai-toolkit --skill pipefy-ai-agentsAfter installing, type/pipefy-ai-agentsin Claude Code to confirm it loaded.
Bundled filesreferences/cli.mdreferences/mcp.md
Details
From the project READMEAI Agents
Read only the reference for your active surface: MCP or CLI. The workflows below use shared operation names and arguments.
Conversational AI agents attached to pipes. Each agent has an agent-level instruction and 1–5 behaviors, each with its own trigger event, prompt, and actions.
For traditional automations and AI automations (prompt-driven), see pipefy-automations.
Tools
| Operation | Read-only | Purpose |
|---|---|---|
get_ai_agents | Yes | List AI agents for a pipe (repo_uuid = pipe UUID, not numeric id). |
get_ai_agent | Yes | Full agent config including behaviors. |
create_ai_agent | No | Create a new conversational agent (active by default; active=false to start disabled). |
update_ai_agent | No | Full-replace (not patch). Always send complete behaviors. Preserves disabled state. |
delete_ai_agent | No | Destructive; review and approve first. |
toggle_ai_agent_status | No | Explicit activate/deactivate. |
validate_ai_agent_behaviors | Yes | Pre-flight check before create/update. |
Execution logs live in pipefy-observability (get_ai_agent_logs, get_ai_agent_log_details).
Active lifecycle
- Agents are active by default. Create-active clears the API default disabled shell via the configure update (omits
disabledAt). Create-inactive (active=false) setsdisabled_atexplicitly on create and the chained update. - Routine
update_ai_agentpreserves disabled state — it does not intentionally reactivate. Prefer passingdisabled_atfrom a priorget_ai_agent(disabledAt) to skip the preserve re-read; when omitted, the SDK re-reads and re-sends. - Explicit activate/deactivate:
toggle_ai_agent_status. - After create/update, check the response's
disabled_atandactive(activeis true whendisabled_atis null). Onget_ai_agent,disabledAtnull means active;behaviors[].activeis not agent enablement. An agent with no active behavior is disabled by the API regardless of enablement flags.
Creation workflow (discover → validate → create → verify)
Consent: create or suggest an AI agent only when the user explicitly asked for AI / an agent. If AI seems useful but was not requested, ask first — never introduce agents without being asked.
Never guess event IDs, phase IDs, action types, or field IDs.
1 — Get pipe metadata
Call get_pipe(pipe_id) and extract:
uuid→ use asrepo_uuidin all AI-agent tools.phases[].id/phases[].name→ needed formove_cardactions.- Fields via
get_start_form_fields(pipe_id)and/orget_phase_fields(phase_id)→ needed forupdate_cardactions.
2 — Check existing agents
get_ai_agents(repo_uuid) to avoid duplicates. To modify an existing agent, use update_ai_agent (not create). For full config, use get_ai_agent(uuid).
3 — Discover valid trigger events
get_automation_events(pipe_id). Common events:
Event (event_id value) | event_params required | Example |
|---|---|---|
| card_created | None | {} |
| card_moved | {"to_phase_id":"<phase_id>"} | Fires only when card enters that phase. |
| field_updated | {"triggerFieldIds":["<field_id>", ...]} | Fires only when those fields change. |
| manually_triggered | None | User clicks button on card. |
For card_moved and field_updated, you MUST include event_params. Omitting it makes the behavior fire on every occurrence.
4 — Discover valid action types
get_automation_actions(pipe_id). Known actionType values and their required metadata:
Action (actionType value) | metadata required |
|---|---|
| update_card | pipeId + fieldsAttributes (each entry needs fieldId + inputMode) |
| move_card | destinationPhaseId |
| create_card | pipeId + fieldsAttributes |
| create_connected_card | pipeId + fieldsAttributes (requires pipe relation) |
| create_table_record | tableId + fieldsAttributes (table field IDs; no pipeId) |
| send_email_template | emailTemplateId; optional allowTemplateModifications (bool) |
| human_validation | emails (recipient list) and title. The API accepts either one alone but rejects empty metadata |
| mcp_tool | mcpServerId + toolName; optional toolInputs, each with name and source: fixed_value with a value, or card_field with a fieldId |
fieldId values for card actions accept slug or numeric internal_id; for create_table_record they are table field IDs (validate with get_table / get_table_record, not the pipe).
Leave pipeId and tableId out of an action that does not need them. Never send either as an empty string: Pipefy reads it as an id you cannot access and rejects the agent with "references a pipe or table you do not have access to". Any pipeId or tableId you send must be in the same organization, and one where the caller can create cards.
5 — Build the behavior dict
{
"name": "<descriptive name>",
"event_id": "<from step 3>",
"event_params": {},
"actionParams": {
"aiBehaviorParams": {
"instruction": "<prompt for the AI when this event fires>",
"actionsAttributes": [
{ "name": "<action label>", "actionType": "<from step 4>", "metadata": { } }
]
}
}
}
-
Each behavior MUST have at least one action in
actionsAttributes. -
Maximum 5 behaviors per agent.
-
inputModeis required on everyfieldsAttributesentry (omitting it fails model validation). Values:fill_with_ai(AI writes the value into an output field),fixed_value(use the literalvalue),copy_from(valueis a%{…}template copying another field). -
Input field references (
%{field:<internal_id>}in the behaviorinstruction, auto-populated intoreferencedFieldIdson create/update) are needed only when the AI must read card field values, not for everyfill_with_ai(e.g. instruction-only, OCR/attachment, or knowledge-base context). When card inputs are needed and omitted,card.fieldsarrives empty at trigger time and the model may hallucinate. A wrong numeric input id is accepted silently (validate and create/update) and becomes a deadreferencedFieldId; a wrong slug never resolves and is dropped by the digits-only extractor (unresolved token). Either waycard.fieldsstays empty (same hallucination); confirm the id withget_start_form_fields/get_phase_fields. Dotted connected-pipe refs (%{field:<parent>.<child>}) are not forwarded at runtime; to read a connected card field, use a field on the current pipe. -
For
update_card: setdestinationPhaseId: ""when not moving the card.
Example identifiers (fictional)
Use real values from get_pipe / get_start_form_fields for your org. Placeholders below match unit-test fixtures in this repo. The syntax matters (pipeId, fieldId, %{field:<internal_id>}, inputMode) — the example digits do not; substitute each pipe's numeric internal_id and phase id.
| Role | Example value |
|---|---|
| Pipe (numeric repo id) | 987654321 |
Field internal_id | 900000101 |
Destination phase (move_card) | 900000201 |
Target pipe (create_card) | 900000301 |
Metadata examples
// update_card — output field fill_with_ai; input fields referenced in instruction
{ "pipeId": "987654321", "destinationPhaseId": "", "fieldsAttributes": [{ "fieldId": "900000101", "inputMode": "fill_with_ai", "value": "" }] }
// companion instruction (aiBehaviorParams.instruction), not metadata:
// "Read %{field:900000102} (title) and %{field:900000103} (description), then fill the category."
// move_card (no pipeId: leave out what an action does not use)
{ "destinationPhaseId": "900000201", "fieldsAttributes": [] }
// create_card
{ "pipeId": "900000301", "fieldsAttributes": [{ "fieldId": "title", "inputMode": "fill_with_ai", "value": "" }] }
// create_table_record (fieldsAttributes are TABLE field IDs; no pipeId)
{ "tableId": "<table_id>", "fieldsAttributes": [{ "fieldId": "<table_field_id>", "inputMode": "fill_with_ai", "value": "" }] }
// send_email_template
{ "emailTemplateId": "<template_id>", "allowTemplateModifications": false }
// human_validation
{ "emails": ["[email protected]"], "title": "Review this card" }
// mcp_tool (mcpServerId is an MCP server registered on the pipe)
{ "mcpServerId": "<mcp_server_id>", "toolName": "<tool_name>", "toolInputs": [{ "name": "query", "source": "fixed_value", "value": "acme" }, { "name": "email", "source": "card_field", "fieldId": "customer_email" }] }
5b — Optional: capabilities and LLM provider
Inside actionParams.aiBehaviorParams a behavior may also carry:
-
capabilitiesAttributes— advanced tools the behavior can use. Each entry is exactly{ "capabilityType": "<type>", "enabled": true|false }(both keys required, no extra keys — bare strings or{ "type": ... }are rejected).Product name capabilityTypeIDP / Intelligent Document Processing advanced_ocrCalculations & Analysis math_operationsWeb Search web_searchWeb Scraping web_scrapingMax effort max_effortcapabilityTypeis not checked against a fixed set — any value passes through and the API validates the enum on write, so new capabilities work without a toolkit update. Validation checks shape only, not entitlement — a capability may still require organization-level enablement to have any effect, so a green pre-flight does not guarantee the capability is active for the org. -
providerId/systemProviderId— pick the behavior's LLM provider. Set at most one (a behavior resolves to a single active provider). Discover valid IDs withget_llm_providers: each provider carriestype— useproviderIdfor a custom (byom) provider andsystemProviderIdfor a Pipefy-managed (system) one.get_default_llm_providershows what a behavior falls back to when neither is set. IDs are also visible in the organization's AI settings in the Pipefy UI.Bring your own model (custom provider). First probe
validate_llm_provider_access: read access does not prove the strongermanage_ai_providerspermission or eligible plan required for writes. Create a provider withconfiguration_file_path(a local JSON file) and use itsidasproviderId. Forupdate_llm_provider, send the full configuration: retain__REDACTED__placeholders to preserve existing secrets or supply new values to rotate them. Checkget_llm_provider_dependenciesbeforedelete_llm_provider; useset_llm_provider_active_statusfor activation.set_default_llm_providertakes exactly one ofprovider_id/system_provider_id;reset_default_llm_providerclears the default. -
dataSourceIds— knowledge base sources the behavior can draw on. Each ID is a knowledge base item ID fromget_ai_knowledge_bases. Agents also carry an agent-leveldata_source_ids; the two are unioned. See Knowledge bases below for the create → attach flow.
{
"instruction": "Extract totals from the attached invoice.",
"capabilitiesAttributes": [{ "capabilityType": "advanced_ocr", "enabled": true }],
"actionsAttributes": [ /* ... */ ]
}
6 — Validate (recommended for complex behaviors)
validate_ai_agent_behaviors(pipe_id, behaviors) checks:
- Output field IDs (
fieldsAttributes[].fieldId) exist in the pipe - Phase IDs exist
- Pipe relations exist for
create_connected_card - Action types are valid (
KNOWN_AI_ACTION_TYPES;create_table_recordfieldsAttributesare table field IDs, so they are not checked against the pipe and surface a warning to verify withget_table;send_email_templatemetadata runs no pipe field-ID checks) - Behavior structure passes Pydantic validation (including canonical
capabilitiesAttributesshape and at most one ofproviderId/systemProviderId) fieldsAttributes[].fieldIdvalues (outputs) are checked against start-form and phase fields, accepting both slugidand numericinternal_id. Instruction%{field:...}tokens (inputs) are not existence-checked: a missing id/slug still yieldsvalid: true. Slug → numeric rewrite happens only on create/update, not here.- Set
data_source_ids(agent-level) to also check knowledge base membership: it is unioned with each behavior'sdataSourceIdsand checked against the pipe's knowledge bases. Unknown IDs are warnings only (validstays true); if the knowledge base list cannot be read, a single warning is added and the check is skipped.
strict_unknown_action_types (default true): an actionType outside KNOWN_AI_ACTION_TYPES is reported in problems (blocking). Set false to demote unknown action types to warnings only, so valid stays true.
7 — Create the agent
create_ai_agent with name, repo_uuid, instruction, and behaviors. One-call creation is preferred — avoids partial agent shells. Agents are active by default; set active=false to start disabled (see Active lifecycle).
On create/update, slug fieldId values are resolved to numeric internal_id, %{field:<slug>} is rewritten to %{field:<internal_id>}, and referencedFieldIds is auto-populated when applicable. The SDK injects action referenceId values and %{action:<uuid>} placeholders for every surface; do not generate them yourself.
8 — Handle responses
- Success with
agent_uuid→ checkdisabled_atandactiveon the write response to verify agent enablement. - Partial failure (behaviors rejected) → the SDK raises
AiAgentConfigureError; use its.agent_uuidto recover the existing shell. The MCP response carriesagent_uuid. Callupdate_ai_agentwith the full required payload:uuid,repo_uuid(same pipe UUID used on create),name,instruction, and completebehaviors(full-replace, not patch). Do NOT create a second agent. The create shell is often disabled; update preserves that state — calltoggle_ai_agent_statusafter a successful recovery update if you need the agent active. - Failure without UUID → validation or API error. Trust the hint text in the enriched error.
9 — Verify
get_ai_agent(uuid) to confirm behaviors and enablement (disabledAt null means active). Do not treat behaviors[].active as agent enablement; never assume inactive without confirmation.
Knowledge bases (data sources)
Knowledge bases are pipe-scoped data sources an agent draws on. Attach one by putting its ID in a behavior's dataSourceIds (or the agent-level data_source_ids). All knowledge base operations are scoped by the pipe UUID (pipe_uuid), not the numeric pipe ID — get_pipe returns the uuid.
| Operation | Read-only | Purpose |
|---|---|---|
get_ai_knowledge_bases | Yes | List every item on a pipe (plain texts, documents, data lookups); each has an id for dataSourceIds and a type (knowledge_base_plain_texts, knowledge_base_documents, or data_lookups). |
get_ai_knowledge_base_plain_text | Yes | Fetch one plain text with its content. |
create_ai_knowledge_base_plain_text | No | Create a plain text (name, content 1-3500, description 1-900 — all required). |
update_ai_knowledge_base_plain_text | No | Partial update; send at least one of name/content/description. |
delete_ai_knowledge_base_plain_text | No | Destructive; review and approve first. |
get_ai_knowledge_base_document | Yes | Fetch one document's metadata (content is the stored URL, not text). |
create_ai_knowledge_base_document | No | Upload a PDF (name, description 1-900, file_path). .pdf + 20 MiB cap; indexing is asynchronous. |
update_ai_knowledge_base_document | No | Metadata-only update (name/description); no file replacement. |
delete_ai_knowledge_base_document | No | Destructive; review and approve first. |
get_ai_knowledge_base_data_lookup | Yes | Fetch one data lookup; the payload never includes conditions — keep the definition client-side. |
create_ai_knowledge_base_data_lookup | No | Create a data lookup (name, description 1-900, source_repo_id numeric pipe ID, output_fields 1-30, conditions — all required). |
update_ai_knowledge_base_data_lookup | No | Full replacement: resend source_repo_id/output_fields/conditions every call; omitted search_query clears it; only name/description are partial. |
delete_ai_knowledge_base_data_lookup | No | Destructive; review and approve first. |
validate_knowledge_base_access | Yes | Probe read access before writes. |
Flow: validate-access → create plain text → attach
- Probe access —
validate_knowledge_base_access(pipe_uuid). A green result proves read access only (read_ai_agents), never themanage_ai_agentsentitlement writes need. - Create the source —
create_ai_knowledge_base_plain_text(pipe_uuid, name, content, description). Limits fail fast client-side:content1-3500 chars,description1-900 chars (both required). Keep the returnedid. - Attach — add that
idto a behavior'sdataSourceIds(or the agent-leveldata_source_ids) when callingcreate_ai_agent/update_ai_agent. Validate first withvalidate_ai_agent_behaviors(pipe_id, behaviors, data_source_ids=[...])— unknown IDs surface as warnings.
For a PDF document, use create_ai_knowledge_base_document with pipe_uuid, name, description, and file_path at step 2. Only .pdf is accepted, with a 20 MiB cap. Indexing is asynchronous, so the document may not be searchable immediately. Keep the returned id and attach it.
Data lookups: create with an AI-filled condition → attach → update (full replacement)
A data lookup lets the agent search cards in a source pipe by conditions and return selected field values. Same flow as above at step 2, with three rules of its own:
-
Create —
create_ai_knowledge_base_data_lookup(pipe_uuid, name, description, source_repo_id, output_fields, conditions).source_repo_idis the numeric ID of the source pipe (a UUID is accepted by the API but the lookup then breaks when the agent runs it).output_fieldstakes 1-30 field IDs (field slugs plus static fields likeid,title,created_at). Each condition needsfield+operator(opaque backend string, e.g."eq","contains") and is either static (stringvaluerequired) or AI-filled — the AI asks the user for the value at runtime:[{"field": "customer_email", "operator": "eq", "usingFillWithAi": true, "inputName": "Customer email", "inputType": "text", "inputDescription": "The customer's email address"}] -
Attach — keep the returned
idand add it todataSourceIds, exactly as for the other kinds. Also keep the definition you sent: reads never returnconditions, so your copy is the only complete record of the lookup. -
Update replaces everything —
update_ai_knowledge_base_data_lookuprequiressource_repo_id,output_fields, andconditionson every call (the complete condition set, not a delta), and omittingsearch_queryclears it. Onlyname/descriptionkeep their stored values when omitted.
Token normalization & slug resolution
Instructions accept five token aliases — all normalize to canonical %{field:<internal_id>}:
| Form | Behavior |
|---|---|
%{<internal_id>} | Canonical short form. |
{<internal_id>} | Bare; auto-prefixed with %. |
{field:<internal_id>} | Bare-with-prefix; auto-%. |
{field:<slug>} | Bare slug; resolved to numeric when behavior action carries pipeId. |
%{field:<internal_id>} | Canonical full form. |
%{field:<slug>} is rewritten to %{field:<internal_id>} when an action in the behavior supplies pipeId. If the Pipefy UI shows plain text instead of chips in token slots, the payload probably still has non-canonical tokens.
Template params / placeholders
Per behavior you can give template_params (or placeholders) with str → str values and use {{name}} in any string (instruction, metadata IDs, etc.). Optionally set instruction_template instead of aiBehaviorParams.instruction — the final instruction is interpolated and written before the API call (by the MCP tools, the CLI, and the SDK's CreateAiAgentInput / UpdateAiAgentInput). These keys are stripped during validation.
{
"name": "Classify card",
"event_id": "card_created",
"instruction_template": "Read {{field_ref}} and classify the card.",
"template_params": { "field_ref": "%{field:900000101}" },
"actionParams": {
"aiBehaviorParams": {
"actionsAttributes": [
{
"name": "Fill classification",
"actionType": "update_card",
"metadata": { "pipeId": "{{pipe}}", "fieldsAttributes": [{ "fieldId": "{{class_field}}", "inputMode": "fill_with_ai", "value": "" }] }
}
]
}
},
"placeholders": { "pipe": "987654321", "class_field": "900000101" }
}
template_params and placeholders merge (placeholders wins on conflict).
Naming differences (UI vs API)
| Pipefy UI | API / Tool field |
|---|---|
| Description (agent creation step 1) | instruction (agent-level) |
| Instruction / Prompt (per behavior) | actionParams.aiBehaviorParams.instruction |
| Pipe UUID | repo_uuid (from get_pipe().uuid, NOT the numeric id) |
Success criteria
- Agent enablement matches the intended state:
get_ai_agent.disabledAtis null when active;behaviors[].activedoes not establish agent enablement. validate_ai_agent_behaviorsreports no errors before creation.- Agent appears in the Pipefy UI under the pipe's AI settings.
Failure modes
update_ai_agentis full-replace, not patch. Read the agent withget_ai_agent, change what you need, and send the complete behaviors list back. A behavior you leave out is deleted. You can send the read behaviors back as they are; the ids and%{action:…}lines they carry are replaced on save. One exception:get_ai_agentdoes not returneventParams.kindOfSla, so a behavior on an SLA event sent back as read loses its SLA kind. SetkindOfSlaon that behavior'sevent_paramsbefore you send it. Update never reactivates a disabled agent; usetoggle_ai_agent_statusfor that.- A rejected update is not rolled back. Pipefy applies the name and instruction and removes the current behaviors before it saves the new list. When it then rejects the list (
RECORD_NOT_SAVED), the agent is left with no behaviors, or only part of the new list, and stays enabled. Beforeupdate_ai_agent, keep theget_ai_agentresult and runvalidate_ai_agent_behaviors, which checks eachevent_idagainstget_automation_events— warning you when those events cannot be loaded, so an unverifiedevent_idnever reads as a clean result — and validates thehuman_validation/mcp_toolaction metadata. After a failure, callget_ai_agentto see what is left, fix the payload, and send the full list again. The same holds when the update fails with "references a pipe or table you do not have access to": the behaviors are already saved when that error returns. RECORD_NOT_SAVEDdoes not name the cause.validate_ai_agent_behaviorsnow names several of them — an unknownevent_id(when the pipe's automation events load), and ahuman_validationormcp_toolaction with missing metadata — so run it first. The same message still covers payload errors the pre-flight cannot see, so rule those named causes out before you conclude the pipe does not support AI agent behaviors.- Partial-failure recovery. If
create_ai_agentreturns a UUID but reports failure, callupdate_ai_agent(uuid, repo_uuid, name, instruction, behaviors)— all five are required. Reuse the createrepo_uuid; send the full behaviors list. Do NOT create a second agent. Update preserves disabled state; usetoggle_ai_agent_statusto change enablement. - Cross-pipe
PERMISSION_DENIED. Behaviors withcreate_connected_cardor cross-pipecreate_cardrequire the service account to be a member of both source and destination pipes. When it is not, the API returns a barePERMISSION_DENIED. Recovery:get_pipe_members+invite_memberson the destination pipe. - Phase transition rule on
move_card. Destination must be reachable from the source phase (cards_can_be_moved_to_phases). Bothvalidate_ai_agent_behaviorsandcreate_ai_agent/update_ai_agentenrich this error withvalid_destinationsand a hint that transition rules are editable in the Pipefy UI only. - Maximum 5 behaviors per agent. Adding a 6th rejects the whole save.
- Ghost agents. An agent listed by
get_ai_agentsmay return "Agent not found" onget_ai_agent— a Pipefy backend artifact, persists across sessions, do not retry. - GraphQL error hints. When a dedicated read tool returns permission-denied or not-found, the
error.messagemay cite concrete tools (e.g."Use 'get_ai_agents' to list agents..."). Trust the hint; don't improvise alternative flows. - Validation rejections. Common issues: invalid
trigger_event, prompt too long, missing required action config. Read theerrorsfield per behavior.
See also
pipefy-automations— traditional automations and AI automations (different from AI agents).pipefy-observability— agent execution logs and credit usage.- docs/mcp/tools/identifiers.md#ai-agents-and-knowledge-bases — canonical map of which tool/argument expects slug vs
internal_idvs uuid vs numeric id (AI agents scope byrepo_uuid= pipe UUID).