autotouch-cli 0.2.17__tar.gz → 0.2.19__tar.gz

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 (63) hide show
  1. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/PKG-INFO +107 -1
  2. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/autotouch_cli.egg-info/PKG-INFO +107 -1
  3. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/docs/research-table/reference/autotouch-cli-pypi.md +106 -0
  4. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/pyproject.toml +1 -1
  5. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/smart_table_cli.py +46 -0
  6. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/autotouch_cli.egg-info/SOURCES.txt +0 -0
  7. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/autotouch_cli.egg-info/dependency_links.txt +0 -0
  8. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/autotouch_cli.egg-info/entry_points.txt +0 -0
  9. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/autotouch_cli.egg-info/requires.txt +0 -0
  10. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/autotouch_cli.egg-info/top_level.txt +0 -0
  11. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/__init__.py +0 -0
  12. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/add_column_unique_index.py +0 -0
  13. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/attach_csv_import_leads_to_research_table.py +0 -0
  14. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/bundle_sequences_backend.py +0 -0
  15. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/check_agent_traces.py +0 -0
  16. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/check_column_mode.py +0 -0
  17. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/exit_terminal_leads_from_sequences.py +0 -0
  18. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/fetch_lead.py +0 -0
  19. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/fix_lead_titles_from_csv.py +0 -0
  20. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250106_add_column_position.py +0 -0
  21. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250108_fix_legacy_column_fields.py +0 -0
  22. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250109_add_user_fields_to_tables.py +0 -0
  23. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250117_add_call_logs_webhook_indexes.py +0 -0
  24. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250117_rename_call_logs_collection.py +0 -0
  25. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250119_create_leads_unique_email_index.py +0 -0
  26. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250123_add_filter_indexes.py +0 -0
  27. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250123_add_llm_responses_collection.py +0 -0
  28. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250128_migrate_user_ids_to_objectid.py +0 -0
  29. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250208_backfill_task_research_values.py +0 -0
  30. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250604_add_origin_indexes.py +0 -0
  31. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250608_cleanup_agent_metadata.py +0 -0
  32. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250608_rename_agent_metadata_to_metadata.py +0 -0
  33. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250922_add_activity_indexes.py +0 -0
  34. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250926_migrate_single_to_arrays.py +0 -0
  35. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250928_add_missing_timestamp_fields.py +0 -0
  36. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250929_add_task_join_indexes.py +0 -0
  37. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250929_add_task_join_indexes_safe.py +0 -0
  38. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20250929_create_shared_phone_cache.py +0 -0
  39. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20251007_add_rows_position_id_index.py +0 -0
  40. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20251109_add_ttl_for_llm_and_preview_traces.py +0 -0
  41. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20260113_normalize_table_filter_operators.py +0 -0
  42. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20260113_set_user_permissions_user_admin.py +0 -0
  43. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20260204_sync_lead_owner_from_tasks.py +0 -0
  44. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/20260303_add_webhook_subscription_collections.py +0 -0
  45. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/migrate_org_user_credits.py +0 -0
  46. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/set_default_lead_status.py +0 -0
  47. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/migrations/update_lead_owner_from_tasks.py +0 -0
  48. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/reassign_sequence_owner.py +0 -0
  49. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/run_sidecar_orchestrator_demo.py +0 -0
  50. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/test_crm_company_policy.py +0 -0
  51. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/test_sequences_instantly_e2e.py +0 -0
  52. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/test_sequences_personal_e2e.py +0 -0
  53. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/test_task_error_logger.py +0 -0
  54. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/scripts/verify_azurite_voicemail.py +0 -0
  55. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/setup.cfg +0 -0
  56. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_contactout_custom.py +0 -0
  57. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_contactout_integration.py +0 -0
  58. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_contactout_multi_titles.py +0 -0
  59. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_contactout_pipeline.py +0 -0
  60. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_contactout_simple.py +0 -0
  61. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_contactout_v2_bulk.py +0 -0
  62. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_lead_required_fields.py +0 -0
  63. {autotouch_cli-0.2.17 → autotouch_cli-0.2.19}/tests/test_phone_provider_pipeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.17
3
+ Version: 0.2.19
4
4
  Summary: Autotouch Smart Table CLI
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -140,6 +140,8 @@ Recipe-first flow (recommended):
140
140
 
141
141
  ```bash
142
142
  autotouch columns recipe --type add_to_crm --output human
143
+ autotouch columns recipe --type sync_to_table --output human
144
+ autotouch columns recipe --type add_to_sequence --output human
143
145
  ```
144
146
 
145
147
  Then create from the generated payload:
@@ -155,6 +157,44 @@ Notes:
155
157
  - `add_to_crm` is optional and non-billable.
156
158
  - Email/phone enrichment does not require creating/running `add_to_crm`.
157
159
  - For `add_to_crm`, required mapping keys are `linkedinUrl` and `companyDomain`.
160
+ - `sync_to_table` supports both:
161
+ - single destination: `destinationTableId` + `columnMappings`
162
+ - router mode: `routes[]` (first matching route wins)
163
+ - `add_to_sequence` requires:
164
+ - `sequenceId`
165
+ - `sourceLeadColumn` pointing to a lead-id producing column (`add_to_crm` or `lead_finder` output)
166
+ - auto-attaches research context defaults during enrollment (`source_table_id`, plus optional table name); favorite fields resolve from current starred columns when explicit `fieldIds` are not provided
167
+
168
+ If you create custom `llm_enrichment` schemas:
169
+ - Use strict field-map schema shape (no root `type/properties` wrapper).
170
+ - Arrays must be explicit `{"type":"array","items":...}`.
171
+ - Avoid legacy/list schema values like `["string"]` or `[{...}]`.
172
+ - Prefer snake_case schema keys in payloads: `response_schema`, `user_schema`, `use_auto_schema`.
173
+
174
+ ## Parse enrichment outputs safely (important for agents)
175
+
176
+ Use a layered rule:
177
+
178
+ 1. Always inspect raw outputs first (sample at least 3 rows).
179
+ 2. Parse by column `dataType`:
180
+ - `json`: use key precedence below.
181
+ - scalar types (`text`, `number`, `date`, `boolean`, `email`, `url`): parse direct value (no JSON key paths).
182
+ 3. Only then publish found/missing counts.
183
+
184
+ Do not rely on a single key for JSON outputs.
185
+
186
+ - Phone extraction precedence: `mobile_number` -> `phone_numbers[0].number` -> `primary_phone`
187
+ - Email extraction precedence: `response` -> `email` -> `work_email`
188
+
189
+ If path A is missing, continue to B/C before declaring `not_found`.
190
+
191
+ JSON split note:
192
+ - Optional by default.
193
+ - Use only when downstream filters/mappings need stable flat keys.
194
+
195
+ Reference:
196
+ - `docs/research-table/guides/context-first-sequence-playbook.md`
197
+ - `docs/research-table/reference/runbooks/context-first-sequence.json`
158
198
 
159
199
  ## Recommended ICP buyer discovery pattern
160
200
 
@@ -187,6 +227,72 @@ Important:
187
227
  - These workflow routes support `actorUserId` query parameter.
188
228
  - External sequence validation rules (manual vs automated vs AI draft constraints) are documented in the workflow reference above.
189
229
 
230
+ ### Sequence step types and rules (quick reference)
231
+
232
+ Supported step kinds:
233
+ - `EMAIL`
234
+ - `CALL`
235
+ - `LINKEDIN`
236
+ - `LINKEDIN_CONNECT`
237
+ - `LINKEDIN_MESSAGE`
238
+ - `CUSTOM`
239
+
240
+ Email send modes:
241
+ - `AUTOMATED`
242
+ - `MANUAL`
243
+
244
+ External API validation rules:
245
+ - First email step cannot be reply (`first_email_reply_not_allowed`).
246
+ - Bulk mode cannot include manual email steps (`bulk_manual_email_not_allowed`).
247
+ - `aiDraft` is only allowed on manual-capable steps:
248
+ - `CALL`, `CUSTOM`, `LINKEDIN`, `LINKEDIN_CONNECT`, `LINKEDIN_MESSAGE`
249
+ - `EMAIL` only when `emailSendMode=MANUAL`
250
+ - `defaultAppendSignature` (sequence-level, optional) sets default signature behavior for email steps.
251
+ - `steps[].appendSignature` (step-level, optional) overrides signature behavior per email step.
252
+
253
+ Runtime behavior:
254
+ - `EMAIL + AUTOMATED` is sent by scheduler/provider flow.
255
+ - Manual/non-automated steps are created as Tasks for rep execution.
256
+
257
+ Minimal mixed-step example:
258
+
259
+ ```json
260
+ {
261
+ "name": "Outbound v1",
262
+ "sourceTableId": "tbl_123",
263
+ "defaultAppendSignature": true,
264
+ "steps": [
265
+ {
266
+ "id": "s1",
267
+ "kind": "EMAIL",
268
+ "emailSendMode": "AUTOMATED",
269
+ "emailIsReply": false,
270
+ "appendSignature": true,
271
+ "subjectTemplate": "Quick intro",
272
+ "bodyTemplate": "Hi {{first_name}}, ..."
273
+ },
274
+ {
275
+ "id": "s2",
276
+ "kind": "CALL",
277
+ "waitDays": 2,
278
+ "aiDraft": true
279
+ },
280
+ {
281
+ "id": "s3",
282
+ "kind": "EMAIL",
283
+ "waitDays": 4,
284
+ "emailSendMode": "MANUAL",
285
+ "emailIsReply": false,
286
+ "appendSignature": false,
287
+ "aiDraft": true
288
+ }
289
+ ]
290
+ }
291
+ ```
292
+
293
+ Canonical contract:
294
+ - `docs/platform/external-workflows-api.md`
295
+
190
296
  ## Outbound webhook subscriptions
191
297
 
192
298
  Use webhook subscriptions to receive customer-facing event notifications.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.17
3
+ Version: 0.2.19
4
4
  Summary: Autotouch Smart Table CLI
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -140,6 +140,8 @@ Recipe-first flow (recommended):
140
140
 
141
141
  ```bash
142
142
  autotouch columns recipe --type add_to_crm --output human
143
+ autotouch columns recipe --type sync_to_table --output human
144
+ autotouch columns recipe --type add_to_sequence --output human
143
145
  ```
144
146
 
145
147
  Then create from the generated payload:
@@ -155,6 +157,44 @@ Notes:
155
157
  - `add_to_crm` is optional and non-billable.
156
158
  - Email/phone enrichment does not require creating/running `add_to_crm`.
157
159
  - For `add_to_crm`, required mapping keys are `linkedinUrl` and `companyDomain`.
160
+ - `sync_to_table` supports both:
161
+ - single destination: `destinationTableId` + `columnMappings`
162
+ - router mode: `routes[]` (first matching route wins)
163
+ - `add_to_sequence` requires:
164
+ - `sequenceId`
165
+ - `sourceLeadColumn` pointing to a lead-id producing column (`add_to_crm` or `lead_finder` output)
166
+ - auto-attaches research context defaults during enrollment (`source_table_id`, plus optional table name); favorite fields resolve from current starred columns when explicit `fieldIds` are not provided
167
+
168
+ If you create custom `llm_enrichment` schemas:
169
+ - Use strict field-map schema shape (no root `type/properties` wrapper).
170
+ - Arrays must be explicit `{"type":"array","items":...}`.
171
+ - Avoid legacy/list schema values like `["string"]` or `[{...}]`.
172
+ - Prefer snake_case schema keys in payloads: `response_schema`, `user_schema`, `use_auto_schema`.
173
+
174
+ ## Parse enrichment outputs safely (important for agents)
175
+
176
+ Use a layered rule:
177
+
178
+ 1. Always inspect raw outputs first (sample at least 3 rows).
179
+ 2. Parse by column `dataType`:
180
+ - `json`: use key precedence below.
181
+ - scalar types (`text`, `number`, `date`, `boolean`, `email`, `url`): parse direct value (no JSON key paths).
182
+ 3. Only then publish found/missing counts.
183
+
184
+ Do not rely on a single key for JSON outputs.
185
+
186
+ - Phone extraction precedence: `mobile_number` -> `phone_numbers[0].number` -> `primary_phone`
187
+ - Email extraction precedence: `response` -> `email` -> `work_email`
188
+
189
+ If path A is missing, continue to B/C before declaring `not_found`.
190
+
191
+ JSON split note:
192
+ - Optional by default.
193
+ - Use only when downstream filters/mappings need stable flat keys.
194
+
195
+ Reference:
196
+ - `docs/research-table/guides/context-first-sequence-playbook.md`
197
+ - `docs/research-table/reference/runbooks/context-first-sequence.json`
158
198
 
159
199
  ## Recommended ICP buyer discovery pattern
160
200
 
@@ -187,6 +227,72 @@ Important:
187
227
  - These workflow routes support `actorUserId` query parameter.
188
228
  - External sequence validation rules (manual vs automated vs AI draft constraints) are documented in the workflow reference above.
189
229
 
230
+ ### Sequence step types and rules (quick reference)
231
+
232
+ Supported step kinds:
233
+ - `EMAIL`
234
+ - `CALL`
235
+ - `LINKEDIN`
236
+ - `LINKEDIN_CONNECT`
237
+ - `LINKEDIN_MESSAGE`
238
+ - `CUSTOM`
239
+
240
+ Email send modes:
241
+ - `AUTOMATED`
242
+ - `MANUAL`
243
+
244
+ External API validation rules:
245
+ - First email step cannot be reply (`first_email_reply_not_allowed`).
246
+ - Bulk mode cannot include manual email steps (`bulk_manual_email_not_allowed`).
247
+ - `aiDraft` is only allowed on manual-capable steps:
248
+ - `CALL`, `CUSTOM`, `LINKEDIN`, `LINKEDIN_CONNECT`, `LINKEDIN_MESSAGE`
249
+ - `EMAIL` only when `emailSendMode=MANUAL`
250
+ - `defaultAppendSignature` (sequence-level, optional) sets default signature behavior for email steps.
251
+ - `steps[].appendSignature` (step-level, optional) overrides signature behavior per email step.
252
+
253
+ Runtime behavior:
254
+ - `EMAIL + AUTOMATED` is sent by scheduler/provider flow.
255
+ - Manual/non-automated steps are created as Tasks for rep execution.
256
+
257
+ Minimal mixed-step example:
258
+
259
+ ```json
260
+ {
261
+ "name": "Outbound v1",
262
+ "sourceTableId": "tbl_123",
263
+ "defaultAppendSignature": true,
264
+ "steps": [
265
+ {
266
+ "id": "s1",
267
+ "kind": "EMAIL",
268
+ "emailSendMode": "AUTOMATED",
269
+ "emailIsReply": false,
270
+ "appendSignature": true,
271
+ "subjectTemplate": "Quick intro",
272
+ "bodyTemplate": "Hi {{first_name}}, ..."
273
+ },
274
+ {
275
+ "id": "s2",
276
+ "kind": "CALL",
277
+ "waitDays": 2,
278
+ "aiDraft": true
279
+ },
280
+ {
281
+ "id": "s3",
282
+ "kind": "EMAIL",
283
+ "waitDays": 4,
284
+ "emailSendMode": "MANUAL",
285
+ "emailIsReply": false,
286
+ "appendSignature": false,
287
+ "aiDraft": true
288
+ }
289
+ ]
290
+ }
291
+ ```
292
+
293
+ Canonical contract:
294
+ - `docs/platform/external-workflows-api.md`
295
+
190
296
  ## Outbound webhook subscriptions
191
297
 
192
298
  Use webhook subscriptions to receive customer-facing event notifications.
@@ -131,6 +131,8 @@ Recipe-first flow (recommended):
131
131
 
132
132
  ```bash
133
133
  autotouch columns recipe --type add_to_crm --output human
134
+ autotouch columns recipe --type sync_to_table --output human
135
+ autotouch columns recipe --type add_to_sequence --output human
134
136
  ```
135
137
 
136
138
  Then create from the generated payload:
@@ -146,6 +148,44 @@ Notes:
146
148
  - `add_to_crm` is optional and non-billable.
147
149
  - Email/phone enrichment does not require creating/running `add_to_crm`.
148
150
  - For `add_to_crm`, required mapping keys are `linkedinUrl` and `companyDomain`.
151
+ - `sync_to_table` supports both:
152
+ - single destination: `destinationTableId` + `columnMappings`
153
+ - router mode: `routes[]` (first matching route wins)
154
+ - `add_to_sequence` requires:
155
+ - `sequenceId`
156
+ - `sourceLeadColumn` pointing to a lead-id producing column (`add_to_crm` or `lead_finder` output)
157
+ - auto-attaches research context defaults during enrollment (`source_table_id`, plus optional table name); favorite fields resolve from current starred columns when explicit `fieldIds` are not provided
158
+
159
+ If you create custom `llm_enrichment` schemas:
160
+ - Use strict field-map schema shape (no root `type/properties` wrapper).
161
+ - Arrays must be explicit `{"type":"array","items":...}`.
162
+ - Avoid legacy/list schema values like `["string"]` or `[{...}]`.
163
+ - Prefer snake_case schema keys in payloads: `response_schema`, `user_schema`, `use_auto_schema`.
164
+
165
+ ## Parse enrichment outputs safely (important for agents)
166
+
167
+ Use a layered rule:
168
+
169
+ 1. Always inspect raw outputs first (sample at least 3 rows).
170
+ 2. Parse by column `dataType`:
171
+ - `json`: use key precedence below.
172
+ - scalar types (`text`, `number`, `date`, `boolean`, `email`, `url`): parse direct value (no JSON key paths).
173
+ 3. Only then publish found/missing counts.
174
+
175
+ Do not rely on a single key for JSON outputs.
176
+
177
+ - Phone extraction precedence: `mobile_number` -> `phone_numbers[0].number` -> `primary_phone`
178
+ - Email extraction precedence: `response` -> `email` -> `work_email`
179
+
180
+ If path A is missing, continue to B/C before declaring `not_found`.
181
+
182
+ JSON split note:
183
+ - Optional by default.
184
+ - Use only when downstream filters/mappings need stable flat keys.
185
+
186
+ Reference:
187
+ - `docs/research-table/guides/context-first-sequence-playbook.md`
188
+ - `docs/research-table/reference/runbooks/context-first-sequence.json`
149
189
 
150
190
  ## Recommended ICP buyer discovery pattern
151
191
 
@@ -178,6 +218,72 @@ Important:
178
218
  - These workflow routes support `actorUserId` query parameter.
179
219
  - External sequence validation rules (manual vs automated vs AI draft constraints) are documented in the workflow reference above.
180
220
 
221
+ ### Sequence step types and rules (quick reference)
222
+
223
+ Supported step kinds:
224
+ - `EMAIL`
225
+ - `CALL`
226
+ - `LINKEDIN`
227
+ - `LINKEDIN_CONNECT`
228
+ - `LINKEDIN_MESSAGE`
229
+ - `CUSTOM`
230
+
231
+ Email send modes:
232
+ - `AUTOMATED`
233
+ - `MANUAL`
234
+
235
+ External API validation rules:
236
+ - First email step cannot be reply (`first_email_reply_not_allowed`).
237
+ - Bulk mode cannot include manual email steps (`bulk_manual_email_not_allowed`).
238
+ - `aiDraft` is only allowed on manual-capable steps:
239
+ - `CALL`, `CUSTOM`, `LINKEDIN`, `LINKEDIN_CONNECT`, `LINKEDIN_MESSAGE`
240
+ - `EMAIL` only when `emailSendMode=MANUAL`
241
+ - `defaultAppendSignature` (sequence-level, optional) sets default signature behavior for email steps.
242
+ - `steps[].appendSignature` (step-level, optional) overrides signature behavior per email step.
243
+
244
+ Runtime behavior:
245
+ - `EMAIL + AUTOMATED` is sent by scheduler/provider flow.
246
+ - Manual/non-automated steps are created as Tasks for rep execution.
247
+
248
+ Minimal mixed-step example:
249
+
250
+ ```json
251
+ {
252
+ "name": "Outbound v1",
253
+ "sourceTableId": "tbl_123",
254
+ "defaultAppendSignature": true,
255
+ "steps": [
256
+ {
257
+ "id": "s1",
258
+ "kind": "EMAIL",
259
+ "emailSendMode": "AUTOMATED",
260
+ "emailIsReply": false,
261
+ "appendSignature": true,
262
+ "subjectTemplate": "Quick intro",
263
+ "bodyTemplate": "Hi {{first_name}}, ..."
264
+ },
265
+ {
266
+ "id": "s2",
267
+ "kind": "CALL",
268
+ "waitDays": 2,
269
+ "aiDraft": true
270
+ },
271
+ {
272
+ "id": "s3",
273
+ "kind": "EMAIL",
274
+ "waitDays": 4,
275
+ "emailSendMode": "MANUAL",
276
+ "emailIsReply": false,
277
+ "appendSignature": false,
278
+ "aiDraft": true
279
+ }
280
+ ]
281
+ }
282
+ ```
283
+
284
+ Canonical contract:
285
+ - `docs/platform/external-workflows-api.md`
286
+
181
287
  ## Outbound webhook subscriptions
182
288
 
183
289
  Use webhook subscriptions to receive customer-facing event notifications.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "autotouch-cli"
7
- version = "0.2.17"
7
+ version = "0.2.19"
8
8
  description = "Autotouch Smart Table CLI"
9
9
  readme = "docs/research-table/reference/autotouch-cli-pypi.md"
10
10
  requires-python = ">=3.9"
@@ -77,6 +77,8 @@ COLUMN_RECIPE_TYPES = [
77
77
  "lead_finder",
78
78
  "llm_enrichment",
79
79
  "add_to_crm",
80
+ "sync_to_table",
81
+ "add_to_sequence",
80
82
  ]
81
83
 
82
84
  COLUMN_CREATE_RECIPES: Dict[str, Dict[str, Any]] = {
@@ -181,6 +183,36 @@ COLUMN_CREATE_RECIPES: Dict[str, Dict[str, Any]] = {
181
183
  ],
182
184
  },
183
185
  },
186
+ "sync_to_table": {
187
+ "key": "sync_to_table",
188
+ "label": "Sync to Table",
189
+ "kind": "enrichment",
190
+ "dataType": "json",
191
+ "origin": "manual",
192
+ "autoRun": "onSourceUpdate",
193
+ "config": {
194
+ "provider": "sync_to_table",
195
+ "destinationTableId": "<DESTINATION_TABLE_ID>",
196
+ "columnMappings": [
197
+ {"sourceKey": "company", "destKey": "company"},
198
+ {"sourceKey": "domain", "destKey": "company_domain"},
199
+ {"sourceKey": "work_email", "destKey": "work_email"},
200
+ ],
201
+ },
202
+ },
203
+ "add_to_sequence": {
204
+ "key": "add_to_sequence",
205
+ "label": "Add to Sequence",
206
+ "kind": "enrichment",
207
+ "dataType": "json",
208
+ "origin": "manual",
209
+ "autoRun": "onSourceUpdate",
210
+ "config": {
211
+ "provider": "add_to_sequence",
212
+ "sequenceId": "<SEQUENCE_ID>",
213
+ "sourceLeadColumn": "add_to_leads",
214
+ },
215
+ },
184
216
  }
185
217
 
186
218
  COLUMN_RECIPE_NOTES: Dict[str, List[str]] = {
@@ -201,21 +233,35 @@ COLUMN_RECIPE_NOTES: Dict[str, List[str]] = {
201
233
  "LinkedIn URL + company domain mappings are required for eligibility.",
202
234
  "Add to CRM is optional and non-billable.",
203
235
  ],
236
+ "sync_to_table": [
237
+ "Use destinationTableId + columnMappings for single-destination sync.",
238
+ "Router mode is supported via config.routes[] (first matching route wins).",
239
+ ],
240
+ "add_to_sequence": [
241
+ "sourceLeadColumn should reference a column that stores lead IDs (for example add_to_crm or lead_finder output).",
242
+ "Set sequenceId to the target workflow sequence ID.",
243
+ ],
204
244
  }
205
245
 
206
246
  RUN_SOP_GUIDE: Dict[str, Any] = {
207
247
  "title": "Credit-safe enrichment SOP",
208
248
  "rules": [
249
+ "Use --output json for automation; avoid parsing human-format output.",
209
250
  "Filter first before running billable columns.",
210
251
  "Estimate first with the same payload you plan to run.",
211
252
  "Start with a small firstN pilot before scaling.",
212
253
  "For exact bounded batches, prefer run-next with a small count.",
213
254
  "For add_to_crm, generate payload from columns recipe before create/update.",
214
255
  "Keep unprocessedOnly enabled unless you intentionally reprocess rows.",
256
+ "Treat bulk job state as source of truth: queued/distributing/processing are non-terminal; completed/partial/error/cancelled are terminal.",
257
+ "Always inspect raw outputs before summary counts; parse by column dataType (json vs scalar).",
258
+ "When summarizing enrichment outputs, parse by key precedence (phone: mobile_number -> phone_numbers[0].number -> primary_phone; email: response -> email -> work_email).",
215
259
  ],
216
260
  "clarifications": [
217
261
  "Email/phone enrichment does not require add_to_crm.",
218
262
  "add_to_crm is an optional export action to Leads CRM (non-billable).",
263
+ "For custom LLM schemas, use strict field-map shape (no root type/properties wrapper; arrays must use {type:\"array\",items:...}).",
264
+ "Do not report not_found from a single missing key when fallback keys exist.",
219
265
  ],
220
266
  "default_run_payload": {
221
267
  "scope": "filtered",
File without changes