@pipefy/pipefy-process-coder 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/.agents/skills/ppc-pipefy-flow-authoring/SKILL.md +262 -262
  2. package/.agents/skills/ppc-pipefy-flow-authoring/examples/01-main-2-danfe-consulta.json +247 -247
  3. package/.agents/skills/ppc-pipefy-flow-authoring/examples/01-main-2-webhook-retorno-consulta.json +589 -589
  4. package/.agents/skills/ppc-pipefy-flow-authoring/examples/01-main-4-recebimento-barramento.json +1391 -1391
  5. package/.agents/skills/ppc-pipefy-flow-authoring/examples/02-subflow-2-danfe-retorno.json +623 -623
  6. package/.agents/skills/ppc-pipefy-flow-authoring/examples/02-subflow-4-criacao-operacao.json +636 -636
  7. package/.agents/skills/ppc-pipefy-flow-authoring/examples/03-subflow-4-criacao-titulo.json +3642 -3642
  8. package/.agents/skills/ppc-pipefy-flow-authoring/examples/04-subflow-4-criacao-cedente.json +863 -863
  9. package/.agents/skills/ppc-pipefy-flow-authoring/examples/04-subflow-4-criacao-sacado.json +799 -799
  10. package/.agents/skills/ppc-pipefy-flow-authoring/examples/README.md +42 -42
  11. package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-01-subflow-1-titulo-acompanhamento-cobranca.json +581 -581
  12. package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-01-subflow-1-titulo-nfe-monitoramento.json +503 -503
  13. package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-01-subflow-1-titulo-retorno-bancario.json +562 -562
  14. package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-02-subflow-2-retorno-consulta-cedente.json +557 -557
  15. package/.agents/skills/ppc-pipefy-flow-authoring/examples/hml-02-subflow-2-retorno-consulta-sacado.json +609 -609
  16. package/.agents/skills/ppc-pipefy-pipe-authoring/SKILL.md +146 -146
  17. package/.agents/skills/ppc-pipefy-process-design/SKILL.md +127 -127
  18. package/.agents/skills/ppc-pipefy-workspace/SKILL.md +91 -91
  19. package/AGENTS.md +465 -456
  20. package/README.md +825 -807
  21. package/bin/pipe.js +25 -4
  22. package/dist/apply/adopt.js +128 -0
  23. package/dist/apply/agentops.js +42 -0
  24. package/dist/apply/compile.js +722 -0
  25. package/dist/apply/execute.js +277 -0
  26. package/dist/apply/flowops.js +293 -0
  27. package/dist/apply/idmap.js +233 -0
  28. package/dist/apply/mutations.js +704 -0
  29. package/dist/apply/registry.js +348 -0
  30. package/dist/apply/types.js +18 -0
  31. package/dist/cli/args.js +79 -0
  32. package/dist/cli.js +187 -0
  33. package/dist/codec/flow.js +164 -0
  34. package/dist/codec/pack.js +88 -0
  35. package/dist/codec/roundtrip.js +86 -0
  36. package/dist/codec/unpack.js +181 -0
  37. package/dist/commands/agents.js +145 -0
  38. package/dist/commands/apply.js +982 -0
  39. package/dist/commands/context.js +79 -0
  40. package/dist/commands/create.js +63 -0
  41. package/dist/commands/diff.js +294 -0
  42. package/dist/commands/flows.js +348 -0
  43. package/dist/commands/misc.js +528 -0
  44. package/dist/commands/plan.js +301 -0
  45. package/dist/commands/pull.js +511 -0
  46. package/dist/commands/runs.js +74 -0
  47. package/dist/commands/skills.js +131 -0
  48. package/dist/commands/verify.js +205 -0
  49. package/dist/config.js +125 -0
  50. package/dist/diff/agents.js +80 -0
  51. package/dist/diff/diff.js +983 -0
  52. package/dist/diff/flow.js +258 -0
  53. package/{src/diff/html.ts → dist/diff/html.js} +274 -322
  54. package/dist/diff/render.js +90 -0
  55. package/dist/model/payload.js +84 -0
  56. package/dist/model/tree.js +7 -0
  57. package/dist/model/volatile.js +54 -0
  58. package/dist/pipefy/agents.js +122 -0
  59. package/dist/pipefy/automations.js +155 -0
  60. package/dist/pipefy/capability.js +84 -0
  61. package/dist/pipefy/client.js +204 -0
  62. package/dist/pipefy/discovery.js +148 -0
  63. package/dist/pipefy/internal.js +315 -0
  64. package/dist/pipefy/ipaas.js +269 -0
  65. package/dist/pipefy/reconstruct.js +674 -0
  66. package/dist/pipefy/reference.js +172 -0
  67. package/dist/pipefy/snapshot.js +185 -0
  68. package/dist/pipefy/toolkit.js +158 -0
  69. package/dist/report/integrations.js +165 -0
  70. package/dist/report/run.js +355 -0
  71. package/dist/util/fsx.js +50 -0
  72. package/dist/util/git.js +25 -0
  73. package/dist/util/json.js +56 -0
  74. package/dist/util/log.js +69 -0
  75. package/dist/util/pool.js +42 -0
  76. package/dist/util/slug.js +23 -0
  77. package/dist/util/tui.js +287 -0
  78. package/dist/validate/index.js +86 -0
  79. package/dist/validate/integrity.js +370 -0
  80. package/dist/validate/reference.js +120 -0
  81. package/dist/validate/schema.js +278 -0
  82. package/dist/workspace/agents.js +245 -0
  83. package/{src/workspace/docs.ts → dist/workspace/docs.js} +367 -407
  84. package/dist/workspace/flows.js +149 -0
  85. package/dist/workspace/layout.js +146 -0
  86. package/dist/workspace/lock.js +83 -0
  87. package/dist/workspace/read.js +168 -0
  88. package/dist/workspace/reference.js +24 -0
  89. package/dist/workspace/stamp.js +234 -0
  90. package/dist/workspace/write.js +194 -0
  91. package/package.json +37 -35
  92. package/src/apply/adopt.ts +0 -150
  93. package/src/apply/agentops.ts +0 -71
  94. package/src/apply/compile.ts +0 -875
  95. package/src/apply/execute.ts +0 -336
  96. package/src/apply/flowops.ts +0 -399
  97. package/src/apply/idmap.ts +0 -241
  98. package/src/apply/mutations.ts +0 -955
  99. package/src/apply/registry.ts +0 -430
  100. package/src/apply/types.ts +0 -134
  101. package/src/cli/args.ts +0 -88
  102. package/src/cli.ts +0 -211
  103. package/src/codec/flow.ts +0 -199
  104. package/src/codec/pack.ts +0 -103
  105. package/src/codec/roundtrip.ts +0 -94
  106. package/src/codec/unpack.ts +0 -198
  107. package/src/commands/agents.ts +0 -184
  108. package/src/commands/apply.ts +0 -1144
  109. package/src/commands/context.ts +0 -119
  110. package/src/commands/create.ts +0 -79
  111. package/src/commands/diff.ts +0 -314
  112. package/src/commands/flows.ts +0 -414
  113. package/src/commands/misc.ts +0 -644
  114. package/src/commands/plan.ts +0 -331
  115. package/src/commands/pull.ts +0 -567
  116. package/src/commands/runs.ts +0 -83
  117. package/src/commands/skills.ts +0 -137
  118. package/src/commands/verify.ts +0 -253
  119. package/src/config.ts +0 -168
  120. package/src/diff/agents.ts +0 -122
  121. package/src/diff/diff.ts +0 -1130
  122. package/src/diff/flow.ts +0 -318
  123. package/src/diff/render.ts +0 -101
  124. package/src/model/payload.ts +0 -154
  125. package/src/model/tree.ts +0 -99
  126. package/src/model/volatile.ts +0 -55
  127. package/src/pipefy/agents.ts +0 -165
  128. package/src/pipefy/automations.ts +0 -219
  129. package/src/pipefy/capability.ts +0 -119
  130. package/src/pipefy/client.ts +0 -267
  131. package/src/pipefy/discovery.ts +0 -209
  132. package/src/pipefy/internal.ts +0 -380
  133. package/src/pipefy/ipaas.ts +0 -365
  134. package/src/pipefy/reconstruct.ts +0 -775
  135. package/src/pipefy/reference.ts +0 -251
  136. package/src/pipefy/snapshot.ts +0 -245
  137. package/src/pipefy/toolkit.ts +0 -200
  138. package/src/report/integrations.ts +0 -231
  139. package/src/report/run.ts +0 -475
  140. package/src/util/fsx.ts +0 -45
  141. package/src/util/git.ts +0 -32
  142. package/src/util/json.ts +0 -55
  143. package/src/util/log.ts +0 -76
  144. package/src/util/pool.ts +0 -48
  145. package/src/util/slug.ts +0 -26
  146. package/src/util/tui.ts +0 -335
  147. package/src/validate/index.ts +0 -123
  148. package/src/validate/integrity.ts +0 -387
  149. package/src/validate/reference.ts +0 -136
  150. package/src/validate/schema.ts +0 -328
  151. package/src/workspace/agents.ts +0 -290
  152. package/src/workspace/flows.ts +0 -191
  153. package/src/workspace/layout.ts +0 -165
  154. package/src/workspace/lock.ts +0 -148
  155. package/src/workspace/read.ts +0 -165
  156. package/src/workspace/reference.ts +0 -24
  157. package/src/workspace/stamp.ts +0 -301
  158. package/src/workspace/write.ts +0 -225
  159. /package/{src → dist}/pipefy/toolkit_bearer.py +0 -0
@@ -1,146 +1,146 @@
1
- ---
2
- name: ppc-pipefy-pipe-authoring
3
- description: Use when writing or editing the JSON of a Pipefy pipe's structure in a pipefy-process-coder workspace — phases, fields, automations, field conditions, labels, webhooks, pipe relations, preferences, public form. Covers the file layout, referencing entities that do not exist yet, and the specific edits that fail silently because a mutation accepts them and ignores them.
4
- ---
5
-
6
- # Authoring pipe structure JSON
7
-
8
- Read `ppc-pipefy-workspace` first for the loop and the identity rules. This is the
9
- detail: what goes in which file, and which edits look fine and are not.
10
-
11
- ## Where things live
12
-
13
- ```
14
- pipes/<id>--<name>/
15
- pipe.json the repo row: name, noun, public, title_field_id
16
- phases/NN--name.json the phase, its fields[], jump_target_ids[], team_member_ids[]
17
- automations/<name>.json the automation, its condition, field_maps, response_schemas
18
- field-conditions/<name>.json the condition and its actions
19
- labels.json webhooks.json public-form.json preferences.json relations.json
20
- _readonly/ _non-snapshot/ _meta.json
21
- ```
22
-
23
- **Fields live inside their phase file.** That is where they make sense and where
24
- you will edit them most. Ordering comes from the `index` value inside the file,
25
- never from the filename — renumbering works without renaming.
26
-
27
- The start form is a real phase at `index: 0`. Deleting or reindexing it is
28
- catastrophic; the validator refuses.
29
-
30
- ## Creating something new
31
-
32
- ```json
33
- { "id": null, "_new": true, "uuid": "<fresh v4>", "label": "Severity", "type_id": "select", … }
34
- ```
35
-
36
- A new field nested in an existing phase file needs no `phase_id` — it inherits its
37
- owner's. A field in a *new* phase leaves it null; the compiler substitutes the
38
- phase's real id after the phase is created.
39
-
40
- **Referencing something you are creating in the same edit:** leave
41
- `%{_new:<its uuid>}` and the applier substitutes the real id once it exists. This
42
- works in automation `field_maps`, condition `field_address`, `jump_target_ids`,
43
- and field-condition action targets.
44
-
45
- ## What cannot be changed at all
46
-
47
- | Edit | Why |
48
- | --- | --- |
49
- | a field's `type_id` | `updatePhaseField` has no `type_id`. Delete+create destroys every existing value. |
50
- | a field's `phase_id` | same — no input, and moving it would destroy the data |
51
- | a phase's `index` | `createPhase` takes an index, `updatePhase` does not |
52
- | a pipe's `description` | `UpdatePipeInput` has no `description` field at all |
53
- | `start_form_title` | no input on any preference mutation |
54
- | anything under `_readonly/` | no public write path exists |
55
-
56
- If a request needs one of these, say so and stop. `pipe plan` refuses them per
57
- column, with the reason.
58
-
59
- ## The silent failures — every one of these cost a live incident
60
-
61
- These are edits the API *accepts* and does not apply, or applies wrongly. They are
62
- guarded now, but understanding them stops you writing them.
63
-
64
- **A mutation can succeed and change nothing.** Arguments are filtered against the
65
- live schema, so an argument the mutation has no input for is dropped and the call
66
- returns success. `description`, `anyone_can_create_card` and `create_card_label`
67
- all did this on `updatePipe`. That is why the registry names settable columns per
68
- entity rather than trusting the mutation.
69
-
70
- **Some arguments want a uuid where the payload stores an id.**
71
- `updatePipe.title_field_id` takes the field's **uuid** or slug, never the numeric
72
- id the payload holds. `archiveField` takes `{ uuid }`. Both are translated for you.
73
-
74
- **`phaseSettings` reports failure for changes it has already made.** Observed on
75
- three separate runs, with the row present in the read-back and timestamped to the
76
- failing call. Its errors are inconclusive — re-read before assuming nothing
77
- happened.
78
-
79
- **`hidden_top_buttons` and `hidden_start_form_attributes` are closed sets:**
80
- `Assignees, Attachments, Checklist, Comments, DueDate, Labels`. Anything else is
81
- rejected mid-apply. Checked offline now.
82
-
83
- **Every event and action accepts a fixed parameter list, and nothing enforces it.**
84
- Read `REFERENCE.md` in the workspace before writing an automation. It is generated
85
- by `pipe pull` from the API and lists each event's `event_params`, each action's
86
- `action_params`, and which pairings are refused.
87
-
88
- The reason it needs reading: the schema publishes these lists, then types
89
- `event_id`, `action_id` and `type_id` as `ID` and `String`, so GraphQL validates
90
- none of them. A wrong value returns `is invalid` or `All fields must be filled
91
- properly.` — naming nothing — partway through an apply. And the mistakes are
92
- near-misses, not nonsense:
93
-
94
- - `card_moved` takes only `to_phase_id`. `in_phase_id` is real, on
95
- `card_inbox_received_email`.
96
- - `card_id` is accepted on `update_card_field` and refused on `move_single_card`.
97
-
98
- `pipe validate` catches all of it offline and names the parameter, so run it before
99
- `plan`. Treat it as the backstop, not the reference.
100
-
101
- **Automation params mix naming conventions.** `AutomationActionParamsInput` has
102
- `card_id`, `to_phase_id` and `field_map` in snake_case, but `taskParams`,
103
- `aiParams` and `httpMethod` in camelCase. Getting one wrong deleted a live
104
- automation once, because the update strategy is delete-then-recreate.
105
-
106
- **Pipe relation flags are spelled differently in the mutation and the payload.**
107
- `createPipeRelation` says `canCreateNewItems`; the payload row says
108
- `can_create_connected_cards`. Set both, or read the one that is there.
109
-
110
- **A phase's jump set is set-replacing.** `jump_target_ids` is written whole. Never
111
- append blindly to a set you have not fully read.
112
-
113
- ## Cross-surface obligations
114
-
115
- **Deleting a field obliges you to fix every reference to it.** Automations and
116
- conditions hold bare numeric ids inside opaque JSON — `"field_address": "<fieldId>"`,
117
- `"trigger_field_ids": ["<fieldId>"]`, `"%{<fieldId>}"`. `pipe validate` fails on a
118
- dangling reference by design. `MAPPING.md` translates every id.
119
-
120
- **If the pipe has iPaaS flows, a field may be referenced there too**, by slug,
121
- and the tool cannot yet see it. Check `flows/` if it exists before deleting a
122
- field. See `ppc-pipefy-flow-authoring`.
123
-
124
- ## A worked shape: creating a phase with fields and a jump
125
-
126
- The numbers below are made up — use the real ids from `MAPPING.md`.
127
-
128
- ```json
129
- // phases/09--customer-validation.json
130
- {
131
- "id": null, "_new": true, "uuid": "<fresh v4>",
132
- "name": "Customer Validation", "index": 9, "done": false,
133
- "repo_id": 100200300,
134
- "fields": [
135
- { "id": null, "_new": true, "uuid": "<fresh v4>", "label": "Customer acceptance",
136
- "type_id": "select", "options": ["Accepted", "Needs rework", "Declined"],
137
- "index": 0, "required": false, "repo_id": 100200300 }
138
- ],
139
- "jump_target_ids": [400500600],
140
- "team_member_ids": []
141
- }
142
- ```
143
-
144
- Set `index` on new phases explicitly and leave existing ones alone — their index
145
- cannot be edited. Creating a phase auto-links jumps, so state the jump set you
146
- want or the platform's default stands.
1
+ ---
2
+ name: ppc-pipefy-pipe-authoring
3
+ description: Use when writing or editing the JSON of a Pipefy pipe's structure in a pipefy-process-coder workspace — phases, fields, automations, field conditions, labels, webhooks, pipe relations, preferences, public form. Covers the file layout, referencing entities that do not exist yet, and the specific edits that fail silently because a mutation accepts them and ignores them.
4
+ ---
5
+
6
+ # Authoring pipe structure JSON
7
+
8
+ Read `ppc-pipefy-workspace` first for the loop and the identity rules. This is the
9
+ detail: what goes in which file, and which edits look fine and are not.
10
+
11
+ ## Where things live
12
+
13
+ ```
14
+ pipes/<id>--<name>/
15
+ pipe.json the repo row: name, noun, public, title_field_id
16
+ phases/NN--name.json the phase, its fields[], jump_target_ids[], team_member_ids[]
17
+ automations/<name>.json the automation, its condition, field_maps, response_schemas
18
+ field-conditions/<name>.json the condition and its actions
19
+ labels.json webhooks.json public-form.json preferences.json relations.json
20
+ _readonly/ _non-snapshot/ _meta.json
21
+ ```
22
+
23
+ **Fields live inside their phase file.** That is where they make sense and where
24
+ you will edit them most. Ordering comes from the `index` value inside the file,
25
+ never from the filename — renumbering works without renaming.
26
+
27
+ The start form is a real phase at `index: 0`. Deleting or reindexing it is
28
+ catastrophic; the validator refuses.
29
+
30
+ ## Creating something new
31
+
32
+ ```json
33
+ { "id": null, "_new": true, "uuid": "<fresh v4>", "label": "Severity", "type_id": "select", … }
34
+ ```
35
+
36
+ A new field nested in an existing phase file needs no `phase_id` — it inherits its
37
+ owner's. A field in a *new* phase leaves it null; the compiler substitutes the
38
+ phase's real id after the phase is created.
39
+
40
+ **Referencing something you are creating in the same edit:** leave
41
+ `%{_new:<its uuid>}` and the applier substitutes the real id once it exists. This
42
+ works in automation `field_maps`, condition `field_address`, `jump_target_ids`,
43
+ and field-condition action targets.
44
+
45
+ ## What cannot be changed at all
46
+
47
+ | Edit | Why |
48
+ | --- | --- |
49
+ | a field's `type_id` | `updatePhaseField` has no `type_id`. Delete+create destroys every existing value. |
50
+ | a field's `phase_id` | same — no input, and moving it would destroy the data |
51
+ | a phase's `index` | `createPhase` takes an index, `updatePhase` does not |
52
+ | a pipe's `description` | `UpdatePipeInput` has no `description` field at all |
53
+ | `start_form_title` | no input on any preference mutation |
54
+ | anything under `_readonly/` | no public write path exists |
55
+
56
+ If a request needs one of these, say so and stop. `pipe plan` refuses them per
57
+ column, with the reason.
58
+
59
+ ## The silent failures — every one of these cost a live incident
60
+
61
+ These are edits the API *accepts* and does not apply, or applies wrongly. They are
62
+ guarded now, but understanding them stops you writing them.
63
+
64
+ **A mutation can succeed and change nothing.** Arguments are filtered against the
65
+ live schema, so an argument the mutation has no input for is dropped and the call
66
+ returns success. `description`, `anyone_can_create_card` and `create_card_label`
67
+ all did this on `updatePipe`. That is why the registry names settable columns per
68
+ entity rather than trusting the mutation.
69
+
70
+ **Some arguments want a uuid where the payload stores an id.**
71
+ `updatePipe.title_field_id` takes the field's **uuid** or slug, never the numeric
72
+ id the payload holds. `archiveField` takes `{ uuid }`. Both are translated for you.
73
+
74
+ **`phaseSettings` reports failure for changes it has already made.** Observed on
75
+ three separate runs, with the row present in the read-back and timestamped to the
76
+ failing call. Its errors are inconclusive — re-read before assuming nothing
77
+ happened.
78
+
79
+ **`hidden_top_buttons` and `hidden_start_form_attributes` are closed sets:**
80
+ `Assignees, Attachments, Checklist, Comments, DueDate, Labels`. Anything else is
81
+ rejected mid-apply. Checked offline now.
82
+
83
+ **Every event and action accepts a fixed parameter list, and nothing enforces it.**
84
+ Read `REFERENCE.md` in the workspace before writing an automation. It is generated
85
+ by `pipe pull` from the API and lists each event's `event_params`, each action's
86
+ `action_params`, and which pairings are refused.
87
+
88
+ The reason it needs reading: the schema publishes these lists, then types
89
+ `event_id`, `action_id` and `type_id` as `ID` and `String`, so GraphQL validates
90
+ none of them. A wrong value returns `is invalid` or `All fields must be filled
91
+ properly.` — naming nothing — partway through an apply. And the mistakes are
92
+ near-misses, not nonsense:
93
+
94
+ - `card_moved` takes only `to_phase_id`. `in_phase_id` is real, on
95
+ `card_inbox_received_email`.
96
+ - `card_id` is accepted on `update_card_field` and refused on `move_single_card`.
97
+
98
+ `pipe validate` catches all of it offline and names the parameter, so run it before
99
+ `plan`. Treat it as the backstop, not the reference.
100
+
101
+ **Automation params mix naming conventions.** `AutomationActionParamsInput` has
102
+ `card_id`, `to_phase_id` and `field_map` in snake_case, but `taskParams`,
103
+ `aiParams` and `httpMethod` in camelCase. Getting one wrong deleted a live
104
+ automation once, because the update strategy is delete-then-recreate.
105
+
106
+ **Pipe relation flags are spelled differently in the mutation and the payload.**
107
+ `createPipeRelation` says `canCreateNewItems`; the payload row says
108
+ `can_create_connected_cards`. Set both, or read the one that is there.
109
+
110
+ **A phase's jump set is set-replacing.** `jump_target_ids` is written whole. Never
111
+ append blindly to a set you have not fully read.
112
+
113
+ ## Cross-surface obligations
114
+
115
+ **Deleting a field obliges you to fix every reference to it.** Automations and
116
+ conditions hold bare numeric ids inside opaque JSON — `"field_address": "<fieldId>"`,
117
+ `"trigger_field_ids": ["<fieldId>"]`, `"%{<fieldId>}"`. `pipe validate` fails on a
118
+ dangling reference by design. `MAPPING.md` translates every id.
119
+
120
+ **If the pipe has iPaaS flows, a field may be referenced there too**, by slug,
121
+ and the tool cannot yet see it. Check `flows/` if it exists before deleting a
122
+ field. See `ppc-pipefy-flow-authoring`.
123
+
124
+ ## A worked shape: creating a phase with fields and a jump
125
+
126
+ The numbers below are made up — use the real ids from `MAPPING.md`.
127
+
128
+ ```json
129
+ // phases/09--customer-validation.json
130
+ {
131
+ "id": null, "_new": true, "uuid": "<fresh v4>",
132
+ "name": "Customer Validation", "index": 9, "done": false,
133
+ "repo_id": 100200300,
134
+ "fields": [
135
+ { "id": null, "_new": true, "uuid": "<fresh v4>", "label": "Customer acceptance",
136
+ "type_id": "select", "options": ["Accepted", "Needs rework", "Declined"],
137
+ "index": 0, "required": false, "repo_id": 100200300 }
138
+ ],
139
+ "jump_target_ids": [400500600],
140
+ "team_member_ids": []
141
+ }
142
+ ```
143
+
144
+ Set `index` on new phases explicitly and leave existing ones alone — their index
145
+ cannot be edited. Creating a phase auto-links jumps, so state the jump set you
146
+ want or the platform's default stands.
@@ -1,127 +1,127 @@
1
- ---
2
- name: ppc-pipefy-process-design
3
- description: Use when deciding HOW to build a requirement in Pipefy — which mechanism a need calls for (phase, field condition, automation, iPaaS flow, pipe relation, phase jump, connector field), and how to shape a process so it survives contact with real users. Read before authoring, when the question is "what should this look like" rather than "what JSON does this need".
4
- ---
5
-
6
- # Designing a process in Pipefy
7
-
8
- Most bad Pipefy builds are not bad JSON. They are the right JSON for the wrong
9
- mechanism — an automation doing what a field condition should, a `CODE` node doing
10
- what a piece action does, a flow built where a phase would have been enough.
11
-
12
- Pick the mechanism first.
13
-
14
- ## Choosing the mechanism
15
-
16
- Work down this list and stop at the first one that fits. Each rung costs more to
17
- build, more to explain, and more to debug than the one above it.
18
-
19
- | Need | Mechanism | Why it is the cheapest fit |
20
- | --- | --- | --- |
21
- | Show or hide a field depending on another field | **field condition** | Instant, no run history, no failure mode. Never build this as an automation. |
22
- | Constrain where a card can move | **phase jump set** | Structural. The board enforces it; no rule can be out of date. |
23
- | Stamp a timestamp, copy a value, set a label, move a card, send a task or email — **within one pipe** | **automation** | Native, visible in the pipe, no external dependency, no separate credential |
24
- | Compute something from fields in the same card | **automation with a formula, or an AI action** | Still inside the pipe |
25
- | Link cards between two pipes so people can navigate between them | **pipe relation + connector field** | Structural and bidirectional. An automation that "creates a card" does not link anything. |
26
- | Hold a reusable list people pick from — departments, products, suppliers, services | **a database**, not a pipe | A database has columns and records but no workflow. Reach it with a `connector` field. Reaching for a pipe here gives you phases nobody moves cards through. |
27
- | Store rows that a process reads but nobody works on | **a database** | If a row has no owner and no next step, it is reference data. Cards are for work that moves. |
28
- | Create a card in another pipe when something happens | **automation with `create_card` and `action_repo_id`** | Cross-pipe *writes* are within the automation engine's reach |
29
- | **Read** a pipe other than the one that triggered | **iPaaS flow** | The automation engine cannot. This is the real dividing line. |
30
- | Touch anything outside Pipefy — Slack, HTTP, Sheets, an ERP | **iPaaS flow** | Only iPaaS has pieces |
31
- | Aggregate across many cards, or run on a schedule | **iPaaS flow** | No automation trigger does either |
32
- | Anything else, plus arbitrary logic | **iPaaS flow with a `CODE` node** | Last rung. See the ladder below. |
33
-
34
- ### The dividing line worth memorising
35
-
36
- **An automation can write to another pipe. It cannot read one.** That single fact
37
- decides most automation-versus-flow questions. "When X completes, open a card in
38
- Y" is an automation. "When X completes, check whether the card in Y exists" is a
39
- flow.
40
-
41
- ### Inside a flow, the same discipline applies
42
-
43
- 1. A **piece action** that already does it — check the catalogue first.
44
- 2. An **inline formula expression** in a free-text input.
45
- 3. A **`CODE` node**, only when no piece fits and the logic exceeds a formula.
46
-
47
- A `CODE` node is where the destination of a write can be computed at runtime,
48
- which means no static check can see it. That is the most expensive kind of bug in
49
- this domain — prefer a piece.
50
-
51
- ## Shaping the process itself
52
-
53
- **Name the phases after states, not actions.** "Qualification & Prioritization",
54
- not "Qualify". A card *is in* a state; it does not *do* a phase.
55
-
56
- **Every phase needs an exit.** A phase whose `jump_target_ids` is empty is a dead
57
- end — cards arrive and cannot leave. Author the jump set explicitly; creating a
58
- phase auto-links jumps, and the platform's default is rarely the process you meant.
59
-
60
- **Make required fields answerable at the moment they are asked.** An intake form
61
- that requires a value only known after triage is a form nobody can submit. Real
62
- example: a Customer Success intake required "Account tier" and "Customer impact",
63
- which meant an automated handoff from another pipe could never satisfy it — the
64
- form was blocked until both became triage-time fields.
65
-
66
- **Distinguish intake from work.** The start form is what the requester knows; the
67
- first phase is what the team adds. Do not put "Triage owner" on the start form.
68
-
69
- **Let the last phase mean something.** Set `done: true` on the phase that ends the
70
- process. Webhooks and `cardDone` triggers depend on it, and a pipe whose final
71
- phase is not marked done cannot fire either.
72
-
73
- **Give closure a reason.** A "Rejected / Closed" phase with a `select` for the
74
- reason turns a dead card into data. Without it, nobody can answer "why do we
75
- decline things".
76
-
77
- ## Designing the integration, not just the flow
78
-
79
- **Silence on success, noise on failure.** A flow that messages someone every time
80
- things go right gets muted, and then the one that matters is invisible too. If both
81
- outcomes are worth saying, say different things — and make the failure louder.
82
-
83
- **Assume the other side can be missing.** A cross-pipe read returns an empty list
84
- when the thing you expected was never created. That empty list is usually the most
85
- interesting outcome — handle it in a `ROUTER` branch rather than letting the flow
86
- run on with nothing.
87
-
88
- **Let a search fail without stopping the flow.** Set `continueOnFailure` on the
89
- step that can legitimately find nothing, so the branch that reports "not found"
90
- is reachable.
91
-
92
- **Never assume a connection exists in another workspace.** Connections are
93
- pipe-scoped. A flow that works in one pipe will not import into another that has
94
- no connection for the same piece.
95
-
96
- ## Reviewing a process someone else built
97
-
98
- Ask these in order. Each has caught a real problem.
99
-
100
- 1. **Does every phase have an exit?** Check every `jump_target_ids`.
101
- 2. **Can the start form actually be submitted** by the people and systems that
102
- need to submit it?
103
- 3. **Is any required field only knowable later?**
104
- 4. **Does the final phase have `done: true`?**
105
- 5. **Does anything reference a field that no longer exists?** `pipe validate`
106
- answers this; a dangling reference is an error by design.
107
- 6. **If the pipe has flows, does any of them read a field the pipe is about to
108
- lose?** The tool cannot check this yet — look at `flows/` yourself.
109
- 7. **Is any automation doing a field condition's job?** Those are the first
110
- things to delete.
111
- 8. **Are there duplicate automations?** Two identical rules on one trigger is
112
- almost always the residue of a failed apply, not a decision.
113
-
114
- ## Two failure modes specific to this tool
115
-
116
- **A partial apply leaves created entities looking new.** If an apply half-fails,
117
- the files may still say `"id": null, "_new": true` for things that now exist.
118
- Re-planning would create them twice. `pipe apply` repairs this automatically, and
119
- `pipe verify --adopt` does it on demand — but if you see a diff proposing to create
120
- something you know exists, that is the cause.
121
-
122
- **A clean `pipe diff` covers flows too** — but only where they were readable.
123
- Check `pipes/<id>--<name>/flows/_meta.json`: `coverage: "complete"` means the
124
- flows were compared and match. **`coverage: "unknown"` means iPaaS could not be
125
- reached for that pipe, so its flows were not compared at all** — and a pipe can
126
- diff clean while its actual behaviour changed entirely, because the change was in
127
- a flow nobody looked at. That is the one case where a clean diff is not proof.
1
+ ---
2
+ name: ppc-pipefy-process-design
3
+ description: Use when deciding HOW to build a requirement in Pipefy — which mechanism a need calls for (phase, field condition, automation, iPaaS flow, pipe relation, phase jump, connector field), and how to shape a process so it survives contact with real users. Read before authoring, when the question is "what should this look like" rather than "what JSON does this need".
4
+ ---
5
+
6
+ # Designing a process in Pipefy
7
+
8
+ Most bad Pipefy builds are not bad JSON. They are the right JSON for the wrong
9
+ mechanism — an automation doing what a field condition should, a `CODE` node doing
10
+ what a piece action does, a flow built where a phase would have been enough.
11
+
12
+ Pick the mechanism first.
13
+
14
+ ## Choosing the mechanism
15
+
16
+ Work down this list and stop at the first one that fits. Each rung costs more to
17
+ build, more to explain, and more to debug than the one above it.
18
+
19
+ | Need | Mechanism | Why it is the cheapest fit |
20
+ | --- | --- | --- |
21
+ | Show or hide a field depending on another field | **field condition** | Instant, no run history, no failure mode. Never build this as an automation. |
22
+ | Constrain where a card can move | **phase jump set** | Structural. The board enforces it; no rule can be out of date. |
23
+ | Stamp a timestamp, copy a value, set a label, move a card, send a task or email — **within one pipe** | **automation** | Native, visible in the pipe, no external dependency, no separate credential |
24
+ | Compute something from fields in the same card | **automation with a formula, or an AI action** | Still inside the pipe |
25
+ | Link cards between two pipes so people can navigate between them | **pipe relation + connector field** | Structural and bidirectional. An automation that "creates a card" does not link anything. |
26
+ | Hold a reusable list people pick from — departments, products, suppliers, services | **a database**, not a pipe | A database has columns and records but no workflow. Reach it with a `connector` field. Reaching for a pipe here gives you phases nobody moves cards through. |
27
+ | Store rows that a process reads but nobody works on | **a database** | If a row has no owner and no next step, it is reference data. Cards are for work that moves. |
28
+ | Create a card in another pipe when something happens | **automation with `create_card` and `action_repo_id`** | Cross-pipe *writes* are within the automation engine's reach |
29
+ | **Read** a pipe other than the one that triggered | **iPaaS flow** | The automation engine cannot. This is the real dividing line. |
30
+ | Touch anything outside Pipefy — Slack, HTTP, Sheets, an ERP | **iPaaS flow** | Only iPaaS has pieces |
31
+ | Aggregate across many cards, or run on a schedule | **iPaaS flow** | No automation trigger does either |
32
+ | Anything else, plus arbitrary logic | **iPaaS flow with a `CODE` node** | Last rung. See the ladder below. |
33
+
34
+ ### The dividing line worth memorising
35
+
36
+ **An automation can write to another pipe. It cannot read one.** That single fact
37
+ decides most automation-versus-flow questions. "When X completes, open a card in
38
+ Y" is an automation. "When X completes, check whether the card in Y exists" is a
39
+ flow.
40
+
41
+ ### Inside a flow, the same discipline applies
42
+
43
+ 1. A **piece action** that already does it — check the catalogue first.
44
+ 2. An **inline formula expression** in a free-text input.
45
+ 3. A **`CODE` node**, only when no piece fits and the logic exceeds a formula.
46
+
47
+ A `CODE` node is where the destination of a write can be computed at runtime,
48
+ which means no static check can see it. That is the most expensive kind of bug in
49
+ this domain — prefer a piece.
50
+
51
+ ## Shaping the process itself
52
+
53
+ **Name the phases after states, not actions.** "Qualification & Prioritization",
54
+ not "Qualify". A card *is in* a state; it does not *do* a phase.
55
+
56
+ **Every phase needs an exit.** A phase whose `jump_target_ids` is empty is a dead
57
+ end — cards arrive and cannot leave. Author the jump set explicitly; creating a
58
+ phase auto-links jumps, and the platform's default is rarely the process you meant.
59
+
60
+ **Make required fields answerable at the moment they are asked.** An intake form
61
+ that requires a value only known after triage is a form nobody can submit. Real
62
+ example: a Customer Success intake required "Account tier" and "Customer impact",
63
+ which meant an automated handoff from another pipe could never satisfy it — the
64
+ form was blocked until both became triage-time fields.
65
+
66
+ **Distinguish intake from work.** The start form is what the requester knows; the
67
+ first phase is what the team adds. Do not put "Triage owner" on the start form.
68
+
69
+ **Let the last phase mean something.** Set `done: true` on the phase that ends the
70
+ process. Webhooks and `cardDone` triggers depend on it, and a pipe whose final
71
+ phase is not marked done cannot fire either.
72
+
73
+ **Give closure a reason.** A "Rejected / Closed" phase with a `select` for the
74
+ reason turns a dead card into data. Without it, nobody can answer "why do we
75
+ decline things".
76
+
77
+ ## Designing the integration, not just the flow
78
+
79
+ **Silence on success, noise on failure.** A flow that messages someone every time
80
+ things go right gets muted, and then the one that matters is invisible too. If both
81
+ outcomes are worth saying, say different things — and make the failure louder.
82
+
83
+ **Assume the other side can be missing.** A cross-pipe read returns an empty list
84
+ when the thing you expected was never created. That empty list is usually the most
85
+ interesting outcome — handle it in a `ROUTER` branch rather than letting the flow
86
+ run on with nothing.
87
+
88
+ **Let a search fail without stopping the flow.** Set `continueOnFailure` on the
89
+ step that can legitimately find nothing, so the branch that reports "not found"
90
+ is reachable.
91
+
92
+ **Never assume a connection exists in another workspace.** Connections are
93
+ pipe-scoped. A flow that works in one pipe will not import into another that has
94
+ no connection for the same piece.
95
+
96
+ ## Reviewing a process someone else built
97
+
98
+ Ask these in order. Each has caught a real problem.
99
+
100
+ 1. **Does every phase have an exit?** Check every `jump_target_ids`.
101
+ 2. **Can the start form actually be submitted** by the people and systems that
102
+ need to submit it?
103
+ 3. **Is any required field only knowable later?**
104
+ 4. **Does the final phase have `done: true`?**
105
+ 5. **Does anything reference a field that no longer exists?** `pipe validate`
106
+ answers this; a dangling reference is an error by design.
107
+ 6. **If the pipe has flows, does any of them read a field the pipe is about to
108
+ lose?** The tool cannot check this yet — look at `flows/` yourself.
109
+ 7. **Is any automation doing a field condition's job?** Those are the first
110
+ things to delete.
111
+ 8. **Are there duplicate automations?** Two identical rules on one trigger is
112
+ almost always the residue of a failed apply, not a decision.
113
+
114
+ ## Two failure modes specific to this tool
115
+
116
+ **A partial apply leaves created entities looking new.** If an apply half-fails,
117
+ the files may still say `"id": null, "_new": true` for things that now exist.
118
+ Re-planning would create them twice. `pipe apply` repairs this automatically, and
119
+ `pipe verify --adopt` does it on demand — but if you see a diff proposing to create
120
+ something you know exists, that is the cause.
121
+
122
+ **A clean `pipe diff` covers flows too** — but only where they were readable.
123
+ Check `pipes/<id>--<name>/flows/_meta.json`: `coverage: "complete"` means the
124
+ flows were compared and match. **`coverage: "unknown"` means iPaaS could not be
125
+ reached for that pipe, so its flows were not compared at all** — and a pipe can
126
+ diff clean while its actual behaviour changed entirely, because the change was in
127
+ a flow nobody looked at. That is the one case where a clean diff is not proof.