From 3100c68e006c5d1efc79db4734a0f5fa0fc37a98 Mon Sep 17 00:00:00 2001 From: danielmoraisg Date: Thu, 2 Jul 2026 18:12:31 -0300 Subject: [PATCH 1/3] fix(sdk): accept both key spellings in automation extra_input and fix --extra help CreateAutomationInput/UpdateAutomationInput mix naming styles: most fields are snake_case (action_params, event_id) but a few are camelCase (schedulerCron, responseSchema, searchFor). The CLI --extra help claimed camelCase, so the documented form was rejected by the API. PipefyClient.create_automation/update_automation now rewrite top-level extra_input keys to the API field names via a pure alias map (nested payloads pass through verbatim), so both spellings work from the CLI and MCP surfaces. Help text and docstrings now name the API fields instead of claiming camelCase. Closes #275 --- .../cli/src/pipefy_cli/commands/automation.py | 12 +- .../cli/tests/fixtures/cli_help_golden.txt | 14 ++- .../src/pipefy_mcp/tools/automation_tools.py | 12 +- .../sdk/src/pipefy_sdk/automation_input.py | 52 +++++++++ packages/sdk/src/pipefy_sdk/client.py | 11 +- .../sdk/tests/services/test_pipefy_facade.py | 43 +++++++ packages/sdk/tests/test_automation_input.py | 109 ++++++++++++++++++ 7 files changed, 243 insertions(+), 10 deletions(-) create mode 100644 packages/sdk/src/pipefy_sdk/automation_input.py create mode 100644 packages/sdk/tests/test_automation_input.py diff --git a/packages/cli/src/pipefy_cli/commands/automation.py b/packages/cli/src/pipefy_cli/commands/automation.py index 2e8fe310..60cbda39 100644 --- a/packages/cli/src/pipefy_cli/commands/automation.py +++ b/packages/cli/src/pipefy_cli/commands/automation.py @@ -104,7 +104,11 @@ def automation_create( extra: str | None = typer.Option( None, "--extra", - help="Optional JSON object: extra CreateAutomationInput fields (camelCase).", + help=( + "Optional JSON object: extra CreateAutomationInput fields, using the API " + "field names (e.g. action_params, event_params). camelCase aliases such " + "as actionParams are accepted and rewritten." + ), ), json_out: bool = typer.Option( False, @@ -137,7 +141,11 @@ def automation_update( extra: str = typer.Option( ..., "--extra", - help="JSON object: fields to patch (UpdateAutomationInput, camelCase).", + help=( + "JSON object: fields to patch, using the UpdateAutomationInput API field " + "names (e.g. action_params, event_params). camelCase aliases such as " + "actionParams are accepted and rewritten." + ), ), json_out: bool = typer.Option( False, diff --git a/packages/cli/tests/fixtures/cli_help_golden.txt b/packages/cli/tests/fixtures/cli_help_golden.txt index e821bff4..1c8303b1 100644 --- a/packages/cli/tests/fixtures/cli_help_golden.txt +++ b/packages/cli/tests/fixtures/cli_help_golden.txt @@ -597,7 +597,13 @@ Usage: pipefy automation create [OPTIONS] │ --extra TEXT Optional JSON object: │ │ extra │ │ CreateAutomationInput │ -│ fields (camelCase). │ +│ fields, using the API │ +│ field names (e.g. │ +│ action_params, │ +│ event_params). │ +│ camelCase aliases such │ +│ as actionParams are │ +│ accepted and rewritten. │ │ --json -j Print machine-readable │ │ JSON to stdout. │ │ --help Show this message and │ @@ -816,8 +822,10 @@ Usage: pipefy automation update [OPTIONS] AUTOMATION_ID │ * automation_id TEXT Automation rule id. [required] │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ -│ * --extra TEXT JSON object: fields to patch │ -│ (UpdateAutomationInput, camelCase). │ +│ * --extra TEXT JSON object: fields to patch, using the │ +│ UpdateAutomationInput API field names (e.g. │ +│ action_params, event_params). camelCase aliases │ +│ such as actionParams are accepted and rewritten. │ │ [required] │ │ --json -j Print machine-readable JSON to stdout. │ │ --help Show this message and exit. │ diff --git a/packages/mcp/src/pipefy_mcp/tools/automation_tools.py b/packages/mcp/src/pipefy_mcp/tools/automation_tools.py index d0421e84..5da1e5da 100644 --- a/packages/mcp/src/pipefy_mcp/tools/automation_tools.py +++ b/packages/mcp/src/pipefy_mcp/tools/automation_tools.py @@ -366,8 +366,10 @@ async def create_automation( Use ``get_automation_events`` and ``get_automation_actions`` on ``pipe_id`` first to obtain valid ``trigger_id`` and ``action_id``. Optional ``extra_input`` merges API fields for - ``CreateAutomationInput`` (camelCase keys). Use ``update_automation`` with ``active: false`` - to disable a rule after creation. + ``CreateAutomationInput``, using the API field names (``action_params``, ``event_params``, + ``condition``, ``schedulerCron``, ...); top-level camelCase aliases like ``actionParams`` + are accepted and rewritten. Use ``update_automation`` with ``active: false`` to disable a + rule after creation. For ``card_moved`` rules with action ``move_single_card``, when ``extra_input`` includes ``event_params.to_phase_id`` (or ``toPhaseId``) and ``action_params.to_phase_id`` (or @@ -415,7 +417,7 @@ async def create_automation( action_id: Action type ID from ``get_automation_actions``. active: When True (default), the rule is created **enabled**. Set False to start disabled. If ``extra_input`` includes ``active``, that value wins. action_repo_id: Pipe ID where the action executes (destination pipe). Defaults to ``pipe_id``. Required for cross-pipe actions. - extra_input: Optional extra fields for the mutation input (camelCase keys). + extra_input: Optional extra fields for the mutation input (API field names; top-level camelCase aliases accepted). debug: When True, append GraphQL codes and correlation_id to errors. """ pid, pid_err = validate_tool_id(pipe_id, "pipe_id") @@ -576,7 +578,9 @@ async def update_automation( ) -> dict[str, Any]: """Update an existing traditional automation (partial ``UpdateAutomationInput``). - Optional ``extra_input`` holds fields to change (camelCase keys). Call ``get_automation`` + Optional ``extra_input`` holds fields to change, using the ``UpdateAutomationInput`` API + field names (``action_params``, ``event_params``, ...); top-level camelCase aliases like + ``actionParams`` are accepted and rewritten. Call ``get_automation`` first when patching ``action_params`` — especially ``field_map`` for ``update_card_field`` rules (same shape as ``create_automation``: numeric ``fieldId``, ``inputMode``, ``value``, ``card_id``, ``fields_map_order``). diff --git a/packages/sdk/src/pipefy_sdk/automation_input.py b/packages/sdk/src/pipefy_sdk/automation_input.py new file mode 100644 index 00000000..59164ad1 --- /dev/null +++ b/packages/sdk/src/pipefy_sdk/automation_input.py @@ -0,0 +1,52 @@ +"""Key normalization for traditional automation mutation inputs. + +``CreateAutomationInput`` and ``UpdateAutomationInput`` mix naming styles: +most fields are snake_case (``action_params``, ``event_id``) but a few are +camelCase (``schedulerCron``, ``responseSchema``, ``searchFor``, +``clientMutationId``). Callers routinely guess the wrong spelling, so the +client accepts either and rewrites top-level keys to the API's field names +before sending. Nested payloads are passed through verbatim: their key casing +is part of each param's own contract (``action_params.taskParams`` is +legitimately camelCase inside a snake_case field). +""" + +from __future__ import annotations + +from typing import Any + +_API_NAME_BY_ALIAS = { + "actionId": "action_id", + "actionParams": "action_params", + "actionRepoId": "action_repo_id", + "eventId": "event_id", + "eventParams": "event_params", + "eventRepoId": "event_repo_id", + "schedulerFrequency": "scheduler_frequency", + "client_mutation_id": "clientMutationId", + "response_schema": "responseSchema", + "scheduler_cron": "schedulerCron", + "search_for": "searchFor", +} + + +def normalize_automation_input_keys( + extra_input: dict[str, Any] | None, +) -> dict[str, Any] | None: + """Rewrite top-level automation input keys to the API's field names. + + Keys already using the API spelling and unknown keys pass through + unchanged. When both spellings of a field are present, the API-name key + wins and the alias is dropped. Returns a new dict; ``None`` stays ``None``. + """ + if extra_input is None: + return None + normalized: dict[str, Any] = {} + for key, value in extra_input.items(): + api_name = _API_NAME_BY_ALIAS.get(key, key) + if api_name != key and api_name in extra_input: + continue + normalized[api_name] = value + return normalized + + +__all__ = ["normalize_automation_input_keys"] diff --git a/packages/sdk/src/pipefy_sdk/client.py b/packages/sdk/src/pipefy_sdk/client.py index cdedbd46..6106bf80 100644 --- a/packages/sdk/src/pipefy_sdk/client.py +++ b/packages/sdk/src/pipefy_sdk/client.py @@ -7,6 +7,7 @@ from httpx import Auth from pipefy_sdk.ai_pipe_validation import resolve_and_populate_field_refs +from pipefy_sdk.automation_input import normalize_automation_input_keys from pipefy_sdk.automation_preflight import ( validate_automation_field_map_field_ids, validate_traditional_automation_move_transition, @@ -654,12 +655,16 @@ async def create_automation( action_repo_id: Pipe ID where the action executes. Defaults to ``pipe_id``. For cross-pipe actions (``create_connected_card``, ``move_card_to_pipe``), pass the **destination** pipe ID. - extra_input: Extra ``CreateAutomationInput`` keys; ``active`` here overrides the ``active`` argument. + extra_input: Extra ``CreateAutomationInput`` keys, using the API field names + (``action_params``, ``event_params``, ``schedulerCron``, ...). Top-level + camelCase/snake_case aliases are rewritten to the API names before sending; + ``active`` here overrides the ``active`` argument. Raises: AutomationPreflightError: When the move-card transition or ``field_map`` destination ``fieldId`` is invalid. """ + extra_input = normalize_automation_input_keys(extra_input) await validate_traditional_automation_move_transition( self, trigger_id, action_id, extra_input ) @@ -707,8 +712,12 @@ async def update_automation( ) -> UpdateAutomationMutationResult: """Update a traditional automation (optional ``extra_input`` uses UpdateAutomationInput field names). + Top-level camelCase/snake_case aliases in ``extra_input`` are rewritten to the API + field names before sending, as in :meth:`create_automation`. + Does not run ``field_map`` or move-transition preflight (those run on ``create_automation`` only). """ + extra_input = normalize_automation_input_keys(extra_input) return await self._automation_service.update_automation( automation_id, **(extra_input or {}) ) diff --git a/packages/sdk/tests/services/test_pipefy_facade.py b/packages/sdk/tests/services/test_pipefy_facade.py index d276d670..2b155cef 100644 --- a/packages/sdk/tests/services/test_pipefy_facade.py +++ b/packages/sdk/tests/services/test_pipefy_facade.py @@ -842,3 +842,46 @@ async def test_pipefy_client_invite_members_propagates_value_error(mock_settings "1", [{"email": "x", "role_name": "m"}], ) + + +@pytest.mark.unit +@pytest.mark.asyncio +async def test_automation_extra_input_camel_aliases_reach_service_as_api_names(): + """`extra_input` camelCase aliases are rewritten to the API field names (issue #275).""" + automation_service = AsyncMock() + automation_service.create_automation = AsyncMock( + return_value={"ok": "create_automation"} + ) + automation_service.update_automation = AsyncMock( + return_value={"ok": "update_automation"} + ) + client = PipefyClient.__new__(PipefyClient) + client._automation_service = automation_service + + await client.create_automation( + "p1", + "Rule", + "card_created", + "move_single_card", + extra_input={ + "actionParams": {"to_phase_id": "42"}, + "eventParams": {"to_phase_id": "7"}, + }, + ) + automation_service.create_automation.assert_awaited_once_with( + "p1", + "Rule", + "card_created", + "move_single_card", + action_repo_id=None, + active=True, + action_params={"to_phase_id": "42"}, + event_params={"to_phase_id": "7"}, + ) + + await client.update_automation( + "a1", extra_input={"actionParams": {"card_id": "%{id}"}} + ) + automation_service.update_automation.assert_awaited_once_with( + "a1", action_params={"card_id": "%{id}"} + ) diff --git a/packages/sdk/tests/test_automation_input.py b/packages/sdk/tests/test_automation_input.py new file mode 100644 index 00000000..8eecf3b6 --- /dev/null +++ b/packages/sdk/tests/test_automation_input.py @@ -0,0 +1,109 @@ +"""Unit tests for automation mutation input key normalization.""" + +from __future__ import annotations + +import pytest + +from pipefy_sdk.automation_input import normalize_automation_input_keys + + +@pytest.mark.unit +def test_none_returns_none(): + assert normalize_automation_input_keys(None) is None + + +@pytest.mark.unit +def test_empty_dict_returns_empty_dict(): + assert normalize_automation_input_keys({}) == {} + + +@pytest.mark.unit +def test_camel_aliases_map_to_snake_api_names(): + extra = { + "actionParams": {"to_phase_id": "42"}, + "eventParams": {"to_phase_id": "7"}, + "actionId": "move_single_card", + "eventId": "card_moved", + "actionRepoId": "301", + "eventRepoId": "300", + "schedulerFrequency": "daily", + } + assert normalize_automation_input_keys(extra) == { + "action_params": {"to_phase_id": "42"}, + "event_params": {"to_phase_id": "7"}, + "action_id": "move_single_card", + "event_id": "card_moved", + "action_repo_id": "301", + "event_repo_id": "300", + "scheduler_frequency": "daily", + } + + +@pytest.mark.unit +def test_snake_aliases_map_to_camel_api_names(): + extra = { + "scheduler_cron": {"expression": "0 0 * * *"}, + "response_schema": {"type": "object"}, + "search_for": [{"field": "x"}], + "client_mutation_id": "cli-1", + } + assert normalize_automation_input_keys(extra) == { + "schedulerCron": {"expression": "0 0 * * *"}, + "responseSchema": {"type": "object"}, + "searchFor": [{"field": "x"}], + "clientMutationId": "cli-1", + } + + +@pytest.mark.unit +def test_api_names_pass_through_unchanged(): + extra = { + "action_params": {"card_id": "%{id}"}, + "event_params": {"to_phase_id": "7"}, + "schedulerCron": {"expression": "0 0 * * *"}, + "searchFor": [{"field": "x"}], + "active": False, + "name": "Rule", + "condition": {"expressions": []}, + } + assert normalize_automation_input_keys(extra) == extra + + +@pytest.mark.unit +def test_api_name_wins_when_both_spellings_present(): + extra = { + "action_params": {"to_phase_id": "keep"}, + "actionParams": {"to_phase_id": "drop"}, + } + assert normalize_automation_input_keys(extra) == { + "action_params": {"to_phase_id": "keep"}, + } + + +@pytest.mark.unit +def test_unknown_keys_pass_through_verbatim(): + extra = {"somethingElse": 1, "another_key": 2} + assert normalize_automation_input_keys(extra) == extra + + +@pytest.mark.unit +def test_nested_dicts_are_not_rewritten(): + extra = { + "actionParams": { + "taskParams": {"title": "T"}, + "fieldsAttributes": [{"fieldId": "1"}], + }, + } + assert normalize_automation_input_keys(extra) == { + "action_params": { + "taskParams": {"title": "T"}, + "fieldsAttributes": [{"fieldId": "1"}], + }, + } + + +@pytest.mark.unit +def test_input_dict_is_not_mutated(): + extra = {"actionParams": {"a": 1}} + normalize_automation_input_keys(extra) + assert extra == {"actionParams": {"a": 1}} From a5cb6f89b54c34b62c6029e576b0fda0db668905 Mon Sep 17 00:00:00 2001 From: danielmoraisg Date: Fri, 3 Jul 2026 08:49:54 -0300 Subject: [PATCH 2/3] docs(automation): teach one canonical extra_input spelling, stop advertising aliases The normalizer accepting both spellings is a silent safety net; documenting it made the LLM stop and choose. Lead the MCP tool docstrings with 'mirror get_automation output' and present top-level extra_input keys as snake_case, dropping the 'camelCase aliases accepted' language. Keep a short 'camelCase also accepted' note in the human-facing CLI help. No behavior change; the normalizer still accepts both spellings. --- .../cli/src/pipefy_cli/commands/automation.py | 10 ++++------ .../cli/tests/fixtures/cli_help_golden.txt | 19 +++++++++---------- .../src/pipefy_mcp/tools/automation_tools.py | 18 +++++++++--------- packages/sdk/src/pipefy_sdk/client.py | 11 +++++------ 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/packages/cli/src/pipefy_cli/commands/automation.py b/packages/cli/src/pipefy_cli/commands/automation.py index 60cbda39..59ed4869 100644 --- a/packages/cli/src/pipefy_cli/commands/automation.py +++ b/packages/cli/src/pipefy_cli/commands/automation.py @@ -105,9 +105,8 @@ def automation_create( None, "--extra", help=( - "Optional JSON object: extra CreateAutomationInput fields, using the API " - "field names (e.g. action_params, event_params). camelCase aliases such " - "as actionParams are accepted and rewritten." + "Optional JSON object: extra CreateAutomationInput fields. Top-level keys " + "are snake_case (e.g. action_params, event_params); camelCase is also accepted." ), ), json_out: bool = typer.Option( @@ -142,9 +141,8 @@ def automation_update( ..., "--extra", help=( - "JSON object: fields to patch, using the UpdateAutomationInput API field " - "names (e.g. action_params, event_params). camelCase aliases such as " - "actionParams are accepted and rewritten." + "JSON object: UpdateAutomationInput fields to patch. Top-level keys are " + "snake_case (e.g. action_params, event_params); camelCase is also accepted." ), ), json_out: bool = typer.Option( diff --git a/packages/cli/tests/fixtures/cli_help_golden.txt b/packages/cli/tests/fixtures/cli_help_golden.txt index 1c8303b1..8862ddc5 100644 --- a/packages/cli/tests/fixtures/cli_help_golden.txt +++ b/packages/cli/tests/fixtures/cli_help_golden.txt @@ -597,13 +597,12 @@ Usage: pipefy automation create [OPTIONS] │ --extra TEXT Optional JSON object: │ │ extra │ │ CreateAutomationInput │ -│ fields, using the API │ -│ field names (e.g. │ +│ fields. Top-level keys │ +│ are snake_case (e.g. │ │ action_params, │ -│ event_params). │ -│ camelCase aliases such │ -│ as actionParams are │ -│ accepted and rewritten. │ +│ event_params); │ +│ camelCase is also │ +│ accepted. │ │ --json -j Print machine-readable │ │ JSON to stdout. │ │ --help Show this message and │ @@ -822,10 +821,10 @@ Usage: pipefy automation update [OPTIONS] AUTOMATION_ID │ * automation_id TEXT Automation rule id. [required] │ ╰──────────────────────────────────────────────────────────────────────────────╯ ╭─ Options ────────────────────────────────────────────────────────────────────╮ -│ * --extra TEXT JSON object: fields to patch, using the │ -│ UpdateAutomationInput API field names (e.g. │ -│ action_params, event_params). camelCase aliases │ -│ such as actionParams are accepted and rewritten. │ +│ * --extra TEXT JSON object: UpdateAutomationInput fields to │ +│ patch. Top-level keys are snake_case (e.g. │ +│ action_params, event_params); camelCase is also │ +│ accepted. │ │ [required] │ │ --json -j Print machine-readable JSON to stdout. │ │ --help Show this message and exit. │ diff --git a/packages/mcp/src/pipefy_mcp/tools/automation_tools.py b/packages/mcp/src/pipefy_mcp/tools/automation_tools.py index 5da1e5da..34da4ece 100644 --- a/packages/mcp/src/pipefy_mcp/tools/automation_tools.py +++ b/packages/mcp/src/pipefy_mcp/tools/automation_tools.py @@ -365,11 +365,11 @@ async def create_automation( """Create a traditional automation rule on a pipe (event + action). Use ``get_automation_events`` and ``get_automation_actions`` on ``pipe_id`` first to obtain - valid ``trigger_id`` and ``action_id``. Optional ``extra_input`` merges API fields for - ``CreateAutomationInput``, using the API field names (``action_params``, ``event_params``, - ``condition``, ``schedulerCron``, ...); top-level camelCase aliases like ``actionParams`` - are accepted and rewritten. Use ``update_automation`` with ``active: false`` to disable a - rule after creation. + valid ``trigger_id`` and ``action_id``. Optional ``extra_input`` merges extra + ``CreateAutomationInput`` fields; its top-level keys are snake_case (``action_params``, + ``event_params``, ``condition``, ...). The reliable way to shape it is to mirror what + ``get_automation`` returns for an existing rule. Use ``update_automation`` with + ``active: false`` to disable a rule after creation. For ``card_moved`` rules with action ``move_single_card``, when ``extra_input`` includes ``event_params.to_phase_id`` (or ``toPhaseId``) and ``action_params.to_phase_id`` (or @@ -417,7 +417,7 @@ async def create_automation( action_id: Action type ID from ``get_automation_actions``. active: When True (default), the rule is created **enabled**. Set False to start disabled. If ``extra_input`` includes ``active``, that value wins. action_repo_id: Pipe ID where the action executes (destination pipe). Defaults to ``pipe_id``. Required for cross-pipe actions. - extra_input: Optional extra fields for the mutation input (API field names; top-level camelCase aliases accepted). + extra_input: Optional extra fields for the mutation input; top-level keys are snake_case (mirror ``get_automation`` output). debug: When True, append GraphQL codes and correlation_id to errors. """ pid, pid_err = validate_tool_id(pipe_id, "pipe_id") @@ -578,9 +578,9 @@ async def update_automation( ) -> dict[str, Any]: """Update an existing traditional automation (partial ``UpdateAutomationInput``). - Optional ``extra_input`` holds fields to change, using the ``UpdateAutomationInput`` API - field names (``action_params``, ``event_params``, ...); top-level camelCase aliases like - ``actionParams`` are accepted and rewritten. Call ``get_automation`` + Optional ``extra_input`` holds fields to change; its top-level keys are snake_case + (``action_params``, ``event_params``, ...), matching what ``get_automation`` returns. + Call ``get_automation`` first when patching ``action_params`` — especially ``field_map`` for ``update_card_field`` rules (same shape as ``create_automation``: numeric ``fieldId``, ``inputMode``, ``value``, ``card_id``, ``fields_map_order``). diff --git a/packages/sdk/src/pipefy_sdk/client.py b/packages/sdk/src/pipefy_sdk/client.py index 6106bf80..bc04d890 100644 --- a/packages/sdk/src/pipefy_sdk/client.py +++ b/packages/sdk/src/pipefy_sdk/client.py @@ -655,10 +655,9 @@ async def create_automation( action_repo_id: Pipe ID where the action executes. Defaults to ``pipe_id``. For cross-pipe actions (``create_connected_card``, ``move_card_to_pipe``), pass the **destination** pipe ID. - extra_input: Extra ``CreateAutomationInput`` keys, using the API field names - (``action_params``, ``event_params``, ``schedulerCron``, ...). Top-level - camelCase/snake_case aliases are rewritten to the API names before sending; - ``active`` here overrides the ``active`` argument. + extra_input: Extra ``CreateAutomationInput`` keys. Top-level keys are snake_case + (``action_params``, ``event_params``, ...) and are normalized to the exact API + field names before sending. ``active`` here overrides the ``active`` argument. Raises: AutomationPreflightError: When the move-card transition or ``field_map`` @@ -712,8 +711,8 @@ async def update_automation( ) -> UpdateAutomationMutationResult: """Update a traditional automation (optional ``extra_input`` uses UpdateAutomationInput field names). - Top-level camelCase/snake_case aliases in ``extra_input`` are rewritten to the API - field names before sending, as in :meth:`create_automation`. + Top-level ``extra_input`` keys are snake_case and are normalized to the exact API field + names before sending, as in :meth:`create_automation`. Does not run ``field_map`` or move-transition preflight (those run on ``create_automation`` only). """ From 5d55bfd1041dff228e520bad6f066fa15e96c068 Mon Sep 17 00:00:00 2001 From: danielmoraisg Date: Fri, 3 Jul 2026 11:53:23 -0300 Subject: [PATCH 3/3] docs(automation): align automations reference with snake_case extra_input guidance The reference doc opened with 'extra_input (camelCase API keys)', contradicting the tool docstrings and the doc's own snake_case examples. Same class of confusion as #275: agents reading the doc instead of the tool schema would send the wrong shape. Also drop a meaningless 'or camelCase active' aside (active has no case variant). Addresses review feedback F1 on #352. --- docs/mcp/tools/automations-and-ai.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/mcp/tools/automations-and-ai.md b/docs/mcp/tools/automations-and-ai.md index de19c85a..2b6c0625 100644 --- a/docs/mcp/tools/automations-and-ai.md +++ b/docs/mcp/tools/automations-and-ai.md @@ -8,7 +8,7 @@ Traditional automations (if/then rules) and AI-powered automations and agents. * Ten tools manage Pipefy traditional automations: if/then rules bound to a pipe via the standard GraphQL API. -**Tip:** For **send-a-task** rules (`send_a_task` action), use `create_send_task_automation` (pipe, trigger, task title, recipients) instead of hand-building `action_params.taskParams` on `create_automation`. For other actions, call `get_automation_events` (global event catalog) and `get_automation_actions` with the target pipe (`repoId`) before `create_automation` to pick valid `trigger_id` / `action_id` values. Writes accept optional `extra_input` (camelCase API keys) and `debug=true` on errors. +**Tip:** For **send-a-task** rules (`send_a_task` action), use `create_send_task_automation` (pipe, trigger, task title, recipients) instead of hand-building `action_params.taskParams` on `create_automation`. For other actions, call `get_automation_events` (global event catalog) and `get_automation_actions` with the target pipe (`repoId`) before `create_automation` to pick valid `trigger_id` / `action_id` values. Writes accept optional `extra_input` (top-level keys are snake_case, e.g. `action_params`, `event_params`; mirror `get_automation` output) and `debug=true` on errors. | Tool | Read-only | Role | |------|-----------|------| @@ -107,7 +107,7 @@ For `card_moved` + `move_single_card`, when `extra_input` includes source and de 1. **Discover** — `get_automation_events(pipe_id)`, `get_automation_actions(pipe_id)`, `get_automation_event_attributes()` for official `field_map` tokens; field ids via `get_start_form_fields` / `get_phase_fields`. 2. **Create disabled** — `create_automation` with `active: false` and the `extra_input` payload above. 3. **Verify** — `get_automation(automation_id)` and confirm `action_params.field_map` round-trip. -4. **Enable** — `update_automation` with `extra_input: { "active": true }` (or camelCase `active` per API). +4. **Enable** — `update_automation` with `extra_input: { "active": true }`. ---