autotouch-cli 0.2.26__tar.gz → 0.2.28__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 (68) hide show
  1. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/PKG-INFO +183 -22
  2. autotouch_cli-0.2.28/autotouch_cli/__init__.py +1 -0
  3. autotouch_cli-0.2.26/scripts/smart_table_cli.py → autotouch_cli-0.2.28/autotouch_cli/cli.py +1347 -48
  4. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/autotouch_cli.egg-info/PKG-INFO +183 -22
  5. autotouch_cli-0.2.28/autotouch_cli.egg-info/SOURCES.txt +18 -0
  6. autotouch_cli-0.2.28/autotouch_cli.egg-info/entry_points.txt +3 -0
  7. autotouch_cli-0.2.28/autotouch_cli.egg-info/top_level.txt +1 -0
  8. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/docs/research-table/reference/autotouch-cli.md +182 -21
  9. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/pyproject.toml +4 -4
  10. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/tests/test_contactout_pipeline.py +4 -9
  11. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/tests/test_lead_required_fields.py +7 -5
  12. autotouch_cli-0.2.26/autotouch_cli.egg-info/SOURCES.txt +0 -62
  13. autotouch_cli-0.2.26/autotouch_cli.egg-info/entry_points.txt +0 -3
  14. autotouch_cli-0.2.26/autotouch_cli.egg-info/top_level.txt +0 -1
  15. autotouch_cli-0.2.26/scripts/__init__.py +0 -1
  16. autotouch_cli-0.2.26/scripts/add_column_unique_index.py +0 -112
  17. autotouch_cli-0.2.26/scripts/attach_csv_import_leads_to_research_table.py +0 -130
  18. autotouch_cli-0.2.26/scripts/bundle_sequences_backend.py +0 -250
  19. autotouch_cli-0.2.26/scripts/check_agent_traces.py +0 -125
  20. autotouch_cli-0.2.26/scripts/check_column_mode.py +0 -87
  21. autotouch_cli-0.2.26/scripts/exit_terminal_leads_from_sequences.py +0 -302
  22. autotouch_cli-0.2.26/scripts/fetch_lead.py +0 -12
  23. autotouch_cli-0.2.26/scripts/fix_lead_titles_from_csv.py +0 -217
  24. autotouch_cli-0.2.26/scripts/migrations/20250106_add_column_position.py +0 -66
  25. autotouch_cli-0.2.26/scripts/migrations/20250108_fix_legacy_column_fields.py +0 -91
  26. autotouch_cli-0.2.26/scripts/migrations/20250109_add_user_fields_to_tables.py +0 -84
  27. autotouch_cli-0.2.26/scripts/migrations/20250117_add_call_logs_webhook_indexes.py +0 -84
  28. autotouch_cli-0.2.26/scripts/migrations/20250117_rename_call_logs_collection.py +0 -91
  29. autotouch_cli-0.2.26/scripts/migrations/20250119_create_leads_unique_email_index.py +0 -263
  30. autotouch_cli-0.2.26/scripts/migrations/20250123_add_filter_indexes.py +0 -134
  31. autotouch_cli-0.2.26/scripts/migrations/20250123_add_llm_responses_collection.py +0 -108
  32. autotouch_cli-0.2.26/scripts/migrations/20250128_migrate_user_ids_to_objectid.py +0 -166
  33. autotouch_cli-0.2.26/scripts/migrations/20250208_backfill_task_research_values.py +0 -150
  34. autotouch_cli-0.2.26/scripts/migrations/20250604_add_origin_indexes.py +0 -52
  35. autotouch_cli-0.2.26/scripts/migrations/20250608_cleanup_agent_metadata.py +0 -85
  36. autotouch_cli-0.2.26/scripts/migrations/20250608_rename_agent_metadata_to_metadata.py +0 -103
  37. autotouch_cli-0.2.26/scripts/migrations/20250922_add_activity_indexes.py +0 -215
  38. autotouch_cli-0.2.26/scripts/migrations/20250926_migrate_single_to_arrays.py +0 -465
  39. autotouch_cli-0.2.26/scripts/migrations/20250928_add_missing_timestamp_fields.py +0 -133
  40. autotouch_cli-0.2.26/scripts/migrations/20250929_add_task_join_indexes.py +0 -245
  41. autotouch_cli-0.2.26/scripts/migrations/20250929_add_task_join_indexes_safe.py +0 -107
  42. autotouch_cli-0.2.26/scripts/migrations/20250929_create_shared_phone_cache.py +0 -213
  43. autotouch_cli-0.2.26/scripts/migrations/20251007_add_rows_position_id_index.py +0 -46
  44. autotouch_cli-0.2.26/scripts/migrations/20251109_add_ttl_for_llm_and_preview_traces.py +0 -99
  45. autotouch_cli-0.2.26/scripts/migrations/20260113_normalize_table_filter_operators.py +0 -113
  46. autotouch_cli-0.2.26/scripts/migrations/20260113_set_user_permissions_user_admin.py +0 -100
  47. autotouch_cli-0.2.26/scripts/migrations/20260204_sync_lead_owner_from_tasks.py +0 -269
  48. autotouch_cli-0.2.26/scripts/migrations/20260303_add_webhook_subscription_collections.py +0 -124
  49. autotouch_cli-0.2.26/scripts/migrations/20260305_force_formatter_autorun_on_source_update.py +0 -98
  50. autotouch_cli-0.2.26/scripts/migrations/migrate_org_user_credits.py +0 -117
  51. autotouch_cli-0.2.26/scripts/migrations/set_default_lead_status.py +0 -49
  52. autotouch_cli-0.2.26/scripts/migrations/update_lead_owner_from_tasks.py +0 -152
  53. autotouch_cli-0.2.26/scripts/reassign_sequence_owner.py +0 -136
  54. autotouch_cli-0.2.26/scripts/run_sidecar_orchestrator_demo.py +0 -106
  55. autotouch_cli-0.2.26/scripts/test_crm_company_policy.py +0 -277
  56. autotouch_cli-0.2.26/scripts/test_sequences_instantly_e2e.py +0 -249
  57. autotouch_cli-0.2.26/scripts/test_sequences_personal_e2e.py +0 -215
  58. autotouch_cli-0.2.26/scripts/test_task_error_logger.py +0 -44
  59. autotouch_cli-0.2.26/scripts/verify_azurite_voicemail.py +0 -64
  60. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/autotouch_cli.egg-info/dependency_links.txt +0 -0
  61. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/autotouch_cli.egg-info/requires.txt +0 -0
  62. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/setup.cfg +0 -0
  63. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/tests/test_contactout_custom.py +0 -0
  64. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/tests/test_contactout_integration.py +0 -0
  65. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/tests/test_contactout_multi_titles.py +0 -0
  66. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/tests/test_contactout_simple.py +0 -0
  67. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/tests/test_contactout_v2_bulk.py +0 -0
  68. {autotouch_cli-0.2.26 → autotouch_cli-0.2.28}/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.26
3
+ Version: 0.2.28
4
4
  Summary: Autotouch Smart Table CLI
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -21,7 +21,7 @@ Use this order when you are orienting in the CLI:
21
21
  2. Use the API endpoint -> CLI command map when translating an existing API workflow.
22
22
  3. Use `autotouch columns recipe` before creating provider-backed workflow columns.
23
23
  4. Use `autotouch jobs get` as the source of truth for async run state.
24
- 5. Use raw HTTP for sequences/tasks workflows; those endpoints share the same developer-key model but do not yet have dedicated CLI commands.
24
+ 5. Use `autotouch sequences ...` for sequence definitions, status changes, and direct enrollments; tasks still use raw HTTP.
25
25
 
26
26
  ### Quick decision guide
27
27
 
@@ -36,14 +36,20 @@ Use this order when you are orienting in the CLI:
36
36
  | run one exact row or an explicit list of row IDs | `scope=row` for one ID, `scope=subset` for many IDs |
37
37
  | verify whether a job is really done | `autotouch jobs get --job-id <JOB_ID>` |
38
38
  | create projections from JSON output | `autotouch columns projections` |
39
- | work with sequences/tasks | raw HTTP plus `docs/platform/external-workflows-api.md` |
39
+ | create/manage sequence definitions directly | `autotouch sequences recipe`, then `autotouch sequences create/update/activate` |
40
+ | enroll leads directly into a sequence | `autotouch sequences enroll --sequence-id <SEQUENCE_ID> ...` |
41
+ | enroll table rows into an existing sequence | `autotouch columns recipe --type add_to_sequence`, then `autotouch columns create` + `autotouch columns run` |
42
+ | create or update a CRM lead | `autotouch leads recipe --type create`, then `autotouch leads create` / `autotouch leads update` |
43
+ | add email or phone contact info to a lead | `autotouch leads recipe --type contact_upsert`, then `autotouch leads upsert-contact-channels --lead-id <LEAD_ID> ...` |
44
+ | bulk update lead status or owner | `autotouch leads update-status` / `autotouch leads reassign-owner` |
45
+ | manage tasks directly | raw HTTP plus `docs/platform/external-workflows-api.md` |
40
46
  | query/filter CRM leads and attached research | `autotouch leads query` then `autotouch leads research` |
41
47
 
42
48
  ### Operating model
43
49
 
44
50
  - This file is the full CLI reference and the package readme published to PyPI.
45
51
  - The installed package gives you CLI entrypoints and package metadata; do not assume there is a separate installed docs directory.
46
- - Research-table APIs and read-only leads queries are the primary CLI surface today; workflow APIs (sequences/tasks) are still HTTP-first.
52
+ - Research-table APIs, sequence commands, and lead create/query/update operations are the primary CLI surface today; direct task management is still HTTP-first.
47
53
  - For async operations, backend bulk-job state is authoritative; local terminal output is only a convenience layer.
48
54
  - For staged or cost-sensitive runs, estimate first and prefer filtered scopes plus `firstN` or `run-next`.
49
55
 
@@ -129,6 +135,23 @@ Notes:
129
135
  | `POST /api/tables/{table_id}/columns/{column_id}/stop` | `autotouch columns stop --table-id <TABLE_ID> --column-id <COLUMN_ID>` |
130
136
  | `GET /api/bulk-jobs` | `autotouch jobs list --table-id <TABLE_ID> --column-id <COLUMN_ID> --limit 10` |
131
137
  | `GET /api/bulk-jobs/{job_id}` | `autotouch jobs get --job-id <JOB_ID>` |
138
+ | `GET /api/sequences` | `autotouch sequences list --limit 50` |
139
+ | `GET /api/sequences/{sequence_id}` | `autotouch sequences get --sequence-id <SEQUENCE_ID>` |
140
+ | `GET /api/sequences/{sequence_id}/stats` | `autotouch sequences stats --sequence-id <SEQUENCE_ID>` |
141
+ | `GET /api/sequences/delivery-status` | `autotouch sequences delivery-status` |
142
+ | `POST /api/sequences` | `autotouch sequences create --data-file sequence.json` |
143
+ | `PUT /api/sequences/{sequence_id}` | `autotouch sequences update --sequence-id <SEQUENCE_ID> --data-file sequence.json` |
144
+ | `DELETE /api/sequences/{sequence_id}` | `autotouch sequences delete --sequence-id <SEQUENCE_ID> --yes` |
145
+ | `POST /api/sequences/{sequence_id}/clone` | `autotouch sequences clone --sequence-id <SEQUENCE_ID>` |
146
+ | `PATCH /api/sequences/{sequence_id}/status` | `autotouch sequences status --sequence-id <SEQUENCE_ID> --status ACTIVE` |
147
+ | `POST /api/sequences/{sequence_id}/enroll` | `autotouch sequences enroll --sequence-id <SEQUENCE_ID> --lead-id <LEAD_ID>` |
148
+ | `POST /api/sequences/{sequence_id}/enrollments/pause` | `autotouch sequences pause-enrollment --sequence-id <SEQUENCE_ID> --lead-id <LEAD_ID>` |
149
+ | `GET /api/leads/{lead_id}` | `autotouch leads get --lead-id <LEAD_ID>` |
150
+ | `POST /api/leads` | `autotouch leads create --data-file lead.json` |
151
+ | `PUT /api/leads/{lead_id}` | `autotouch leads update --lead-id <LEAD_ID> --data-file patch.json` |
152
+ | `POST /api/leads/{lead_id}/contact-channels` | `autotouch leads upsert-contact-channels --lead-id <LEAD_ID> --data-file contacts.json` |
153
+ | `POST /api/leads/bulk_update_status` | `autotouch leads update-status --lead-id <LEAD_ID> --status contacting` |
154
+ | `POST /api/leads/bulk_reassign_owner` | `autotouch leads reassign-owner --lead-id <LEAD_ID> --user-id <USER_ID>` |
132
155
  | `POST /api/leads/query` | `autotouch leads query --filter-file lead-filter.json --limit 50` |
133
156
  | `POST /api/leads/query/count` | `autotouch leads count --filter-file lead-filter.json` |
134
157
  | `POST /api/leads/query/stats` | `autotouch leads stats --filter-file lead-filter.json` |
@@ -138,6 +161,15 @@ Notes:
138
161
  | `GET /api/tables/{table_id}/webhook` | `autotouch webhooks get --table-id <TABLE_ID>` |
139
162
  | `POST /api/tables/{table_id}/webhook` | `autotouch webhooks rotate --table-id <TABLE_ID>` |
140
163
  | `POST /api/webhooks/tables/{table_id}/ingest` | `autotouch webhooks ingest --table-id <TABLE_ID> --records-file records.json --webhook-token <WEBHOOK_TOKEN>` |
164
+ | `GET /api/webhook-subscriptions` | `autotouch webhooks subscriptions list --limit 100` |
165
+ | `POST /api/webhook-subscriptions` | `autotouch webhooks subscriptions create --data-file subscription.json` |
166
+ | `GET /api/webhook-subscriptions/{subscription_id}` | `autotouch webhooks subscriptions get --subscription-id <SUBSCRIPTION_ID>` |
167
+ | `PATCH /api/webhook-subscriptions/{subscription_id}` | `autotouch webhooks subscriptions update --subscription-id <SUBSCRIPTION_ID> --data-file patch.json` |
168
+ | `DELETE /api/webhook-subscriptions/{subscription_id}` | `autotouch webhooks subscriptions delete --subscription-id <SUBSCRIPTION_ID>` |
169
+ | `POST /api/webhook-subscriptions/{subscription_id}/pause` | `autotouch webhooks subscriptions pause --subscription-id <SUBSCRIPTION_ID>` |
170
+ | `POST /api/webhook-subscriptions/{subscription_id}/resume` | `autotouch webhooks subscriptions resume --subscription-id <SUBSCRIPTION_ID>` |
171
+ | `POST /api/webhook-subscriptions/{subscription_id}/rotate-secret` | `autotouch webhooks subscriptions rotate-secret --subscription-id <SUBSCRIPTION_ID>` |
172
+ | `POST /api/webhook-subscriptions/{subscription_id}/test` | `autotouch webhooks subscriptions test --subscription-id <SUBSCRIPTION_ID>` |
141
173
  | `POST /api/auth/agent-bootstrap` | HTTP-only bootstrap (no direct CLI wrapper yet) |
142
174
 
143
175
  ## Delete column
@@ -153,19 +185,81 @@ CLI:
153
185
  autotouch columns delete --table-id <TABLE_ID> --column-id <COLUMN_ID> --yes
154
186
  ```
155
187
 
156
- ## Workflow API coverage (sequences/tasks)
188
+ ## Sequence commands
157
189
 
158
- Sequences/tasks APIs are supported by the backend developer-key model but do not yet have dedicated `autotouch` CLI commands.
190
+ The CLI now exposes the public Sequences endpoints under `autotouch sequences`.
191
+ Tasks still use raw HTTP plus `docs/platform/external-workflows-api.md`.
159
192
 
160
- Use raw HTTP for these endpoints today, with the same `stk_...` key:
161
- - `POST /api/sequences`
162
- - `PUT /api/sequences/{sequence_id}`
163
- - `PATCH /api/sequences/{sequence_id}/status`
164
- - `POST /api/sequences/{sequence_id}/enroll`
165
- - `POST /api/task-queue/create`
166
- - `PUT /api/task-queue/{task_id}`
167
- - `POST /api/task-queue/{task_id}/draft`
168
- - `POST /api/task-queue/{task_id}/email/schedule`
193
+ Common commands:
194
+ - `autotouch sequences recipe --type create --out-file sequence.json`
195
+ - `autotouch sequences recipe --type bulk_automated --out-file sequence.json`
196
+ - `autotouch sequences create --data-file sequence.json`
197
+ - `autotouch sequences update --sequence-id <SEQUENCE_ID> --data-file sequence.json`
198
+ - `autotouch sequences activate --sequence-id <SEQUENCE_ID>`
199
+ - `autotouch sequences pause --sequence-id <SEQUENCE_ID>`
200
+ - `autotouch sequences archive --sequence-id <SEQUENCE_ID>`
201
+ - `autotouch sequences enroll --sequence-id <SEQUENCE_ID> --lead-id <LEAD_ID> --wait`
202
+ - `autotouch sequences pause-enrollment --sequence-id <SEQUENCE_ID> --lead-id <LEAD_ID>`
203
+ - `autotouch sequences delivery-status`
204
+ - `autotouch sequences list --include-stats`
205
+
206
+ Important contract notes:
207
+ - Create/update via developer key still requires `sourceTableId`.
208
+ - Mutating sequence commands accept `--actor-user-id` for explicit actor resolution.
209
+ - Recommended default: personal delivery plus `EMAIL` steps with `emailSendMode=MANUAL` and `aiDraft=true`.
210
+ - Use `bulk_automated` only when the provider should send email automatically at scale. `aiDraft` does not apply to bulk automated email steps.
211
+ - Personal delivery uses the connected inbox for the enrolled owner (`assignedToUserId`, else the enrolling actor); there is no per-sequence personal sender picker yet.
212
+ - If that user has multiple connected personal inboxes for the same provider, the most recently updated one is used. Gmail is tried before Microsoft. Sender stays pinned after the first personal email in that enrollment.
213
+ - Bulk delivery uses `emailDelivery.bulkProvider`; Instantly can also narrow sending accounts via `emailDelivery.providerConfig.instantly.selectedAccounts`.
214
+ - `activate`, `pause`, and `archive` are convenience wrappers around `autotouch sequences status`.
215
+ - `autotouch sequences enroll --wait` polls `/api/bulk-jobs/{job_id}` and preserves the API response `task_id` as the bulk job id.
216
+ - Research-table `add_to_sequence` is still available through `autotouch columns create/update/run` and still targets an existing sequence.
217
+ - Real enrollment requires the target sequence to be `ACTIVE` unless direct enroll uses `reviewOnly=true`.
218
+ - Tasks remain HTTP-only.
219
+
220
+ AI draft outputs:
221
+ - Manual new email: subject + body
222
+ - Manual reply email: reply body
223
+ - LinkedIn connect: connection note
224
+ - LinkedIn message: message copy
225
+ - Call: call script
226
+
227
+ Example:
228
+
229
+ ```bash
230
+ autotouch sequences recipe --type create --out-file sequence.json
231
+ autotouch sequences create --data-file sequence.json
232
+ autotouch sequences activate --sequence-id <SEQUENCE_ID>
233
+ ```
234
+
235
+ Cookbooks:
236
+
237
+ 1. Recommended personal AI-assisted outreach
238
+
239
+ ```bash
240
+ autotouch sequences recipe --type create --out-file sequence.json
241
+ autotouch sequences create --data-file sequence.json
242
+ autotouch sequences activate --sequence-id <SEQUENCE_ID>
243
+ autotouch sequences enroll --sequence-id <SEQUENCE_ID> --lead-ids-file lead_ids.json --wait
244
+ ```
245
+
246
+ Notes:
247
+ - `recipe --type create` is the recommended default.
248
+ - It starts with personal delivery, a manual AI-drafted email, then AI-drafted call and LinkedIn follow-up steps.
249
+ - Favorite/starred research fields are the default grounding context when explicit `fieldIds` are not provided.
250
+
251
+ 2. Bulk automated email sequence
252
+
253
+ ```bash
254
+ autotouch sequences recipe --type bulk_automated --out-file sequence.json
255
+ autotouch sequences create --data-file sequence.json
256
+ autotouch sequences activate --sequence-id <SEQUENCE_ID>
257
+ autotouch sequences enroll --sequence-id <SEQUENCE_ID> --lead-ids-file lead_ids.json --wait
258
+ ```
259
+
260
+ Notes:
261
+ - Use this when Instantly or Smartlead should send email automatically.
262
+ - Bulk automated email steps do not support `aiDraft`; author the templates directly in `subjectTemplate` and `bodyTemplate`.
169
263
 
170
264
  Reference contract (actor model + manual/automated/AI-draft nuances):
171
265
  - `docs/platform/external-workflows-api.md`
@@ -177,16 +271,25 @@ Signature controls for sequence payloads:
177
271
 
178
272
  ## Leads API coverage
179
273
 
180
- The CLI now exposes the public read-only leads endpoints under `autotouch leads`.
274
+ The CLI now exposes the public leads read + write endpoints under `autotouch leads`.
181
275
 
182
276
  Use this pattern:
183
277
 
184
- 1. `autotouch leads query` to page through leads, apply descriptor filters, and inspect `related_tables` / `research_summary`.
185
- 2. `autotouch leads research` when you need actual research field values for specific lead IDs from one source table.
186
- 3. `autotouch leads count` / `autotouch leads stats` when you need sizing before a downstream workflow.
278
+ 1. `autotouch leads create` when you need to create one lead from canonical JSON input.
279
+ 2. `autotouch leads recipe` when you want a ready-to-edit payload for create, update, or contact upsert.
280
+ 3. `autotouch leads update` for scalar or partial lead updates.
281
+ 4. `autotouch leads upsert-contact-channels` when you need to add or merge emails/phones without replacing the full arrays.
282
+ 5. `autotouch leads update-status` / `autotouch leads reassign-owner` for operational bulk changes by explicit IDs or descriptor selection.
283
+ 6. `autotouch leads query` to page through leads, apply descriptor filters, and inspect `related_tables` / `research_summary`.
284
+ 7. `autotouch leads research` when you need actual research field values for specific lead IDs from one source table.
187
285
 
188
286
  Important contract notes:
189
287
  - External callers should use `POST /api/leads/query` rather than the older `GET /api/leads` list route.
288
+ - `autotouch leads get` is the direct single-lead lookup path.
289
+ - Use `autotouch leads update` for scalar lead fields only.
290
+ - `autotouch leads update` rejects email/phone fields and points callers to `autotouch leads upsert-contact-channels`.
291
+ - Contact upsert merges into canonical `email_addresses` and `phone_numbers` instead of replacing those arrays.
292
+ - `update-status` and `reassign-owner` accept either explicit lead IDs or descriptor selection input (`--filter-json`, `--search`, `--scope`, etc.).
190
293
  - `autotouch leads query` accepts the same descriptor payload shape as the backend:
191
294
  - `filter`
192
295
  - `search`
@@ -200,6 +303,52 @@ Important contract notes:
200
303
 
201
304
  Examples:
202
305
 
306
+ ```bash
307
+ autotouch leads recipe --type create --out-file lead.json
308
+ autotouch leads create --data-file lead.json
309
+ autotouch leads get --lead-id <LEAD_ID>
310
+ ```
311
+
312
+ ```bash
313
+ autotouch leads recipe --type update --out-file lead-patch.json
314
+ autotouch leads update \
315
+ --lead-id <LEAD_ID> \
316
+ --data-file lead-patch.json
317
+ ```
318
+
319
+ ```bash
320
+ autotouch leads recipe --type contact_upsert --out-file contacts.json
321
+ autotouch leads upsert-contact-channels \
322
+ --lead-id <LEAD_ID> \
323
+ --data-file contacts.json
324
+ ```
325
+
326
+ `contacts.json` example:
327
+
328
+ ```json
329
+ {
330
+ "emails": [
331
+ { "address": "john@acme.com", "type": "work", "primary": true }
332
+ ],
333
+ "phones": [
334
+ { "number": "+14155551234", "type": "mobile", "primary": true }
335
+ ]
336
+ }
337
+ ```
338
+
339
+ ```bash
340
+ autotouch leads update-status \
341
+ --filter-json '{"root":{"kind":"rule","field":"lead_status","operator":"eq","value":"new"}}' \
342
+ --status contacting
343
+ ```
344
+
345
+ ```bash
346
+ autotouch leads reassign-owner \
347
+ --lead-id <LEAD_ID_1> \
348
+ --lead-id <LEAD_ID_2> \
349
+ --user-id <USER_ID>
350
+ ```
351
+
203
352
  ```bash
204
353
  autotouch leads query \
205
354
  --filter-json '{"root":{"kind":"rule","field":"status","operator":"eq","value":"new"}}' \
@@ -246,6 +395,7 @@ Important fields:
246
395
  - `total_rows`: scoped row count for the run
247
396
  - `pending_batches`: derived remaining batches
248
397
  - `terminal_reason`: terminal classifier
398
+ - timing checkpoints: `enqueued_at`, `orchestrator_started_at`, `provider_started_at`, `provider_completed_at`
249
399
 
250
400
  Terminal states:
251
401
  - `completed`
@@ -497,11 +647,13 @@ Notes:
497
647
  }
498
648
  ```
499
649
 
500
- Add-to-Leads note: mapped LinkedIn URL + company domain are required; run is non-billable.
650
+ Add-to-Leads note: `companyDomain` is required; LinkedIn is optional. Each row still needs at least one usable hard identity signal (LinkedIn, email, or phone). Names and location fields are metadata only for this flow. Run is non-billable.
501
651
  If `companyDomain` is missing in the table, derive or enrich that domain column first, then rerun `add_to_crm`.
652
+ Queued lifecycle: the CLI/API accepts the run immediately, then the backend hands off `ops -> data_io` for execution.
502
653
 
503
654
  CRM data model expectations (recommended before `add_to_crm`):
504
- - Lead identity/dedupe expects `linkedin_url` + `company_domain` (clean domain like `example.com`).
655
+ - Lead identity/dedupe expects `company_domain` plus one usable hard identity signal. `linkedin_url` is a strong optional signal, not a requirement.
656
+ - Placeholder or malformed hard identifiers are treated as missing during research-table export. Rows without any surviving LinkedIn/email/phone signal are skipped instead of erroring.
505
657
  - `company_domain` is required; `company_name` is only a display hint and is applied to the linked Company record when provided.
506
658
  - Lead records link to Company via `company_id`; company names live on Company docs, not as canonical lead fields.
507
659
  - Canonical contact fields are arrays (`email_addresses[]`, `phone_numbers[]`); top-level `email`/`mobile_number` may exist on legacy rows but should not be treated as source of truth.
@@ -558,7 +710,7 @@ Notes:
558
710
  ```
559
711
 
560
712
  Notes:
561
- - `sourceLeadColumn` must point to a column that stores lead IDs (for example `add_to_crm` or `lead_finder` output).
713
+ - `sourceLeadColumn` must be the source column key that stores lead IDs (for example `add_to_leads` or another lead-id column key from `lead_finder` output), not the provider name `add_to_crm`.
562
714
  - `sequenceId` is the target sequence workflow ID.
563
715
  - The target sequence must already be `ACTIVE` for real enrollment. Table `add_to_sequence` runs and direct `POST /api/sequences/{id}/enroll` share the same activation check.
564
716
  - `add_to_sequence` runs auto-attach `research_context.source_table_id` (and table name when available). Field selection stays implicit so sequence drafts/audience resolve favorites from current starred columns by default.
@@ -573,12 +725,21 @@ autotouch tables create --name "CLI Contacts"
573
725
  autotouch rows import-csv --table-id <TABLE_ID> --file contacts.csv
574
726
  autotouch columns recipe --type add_to_crm --out-file column.json
575
727
  autotouch columns create --table-id <TABLE_ID> --data-file column.json
728
+ autotouch sequences recipe --type create --out-file sequence.json
729
+ autotouch sequences create --data-file sequence.json
730
+ autotouch sequences activate --sequence-id <SEQUENCE_ID>
576
731
  autotouch columns recipe --type add_to_sequence --out-file add-to-sequence.json
577
732
  autotouch columns create --table-id <TABLE_ID> --data-file add-to-sequence.json
578
733
  autotouch columns run-next --table-id <TABLE_ID> --column-id <COLUMN_ID> --count 25 --filters-file filters.json --show-estimate --wait
579
734
  autotouch jobs get --job-id <JOB_ID>
580
735
  ```
581
736
 
737
+ Sequence creation note:
738
+ - The CLI can create/update/activate sequence definitions directly with `autotouch sequences ...`.
739
+ - Research-table `add_to_sequence` columns and direct `autotouch sequences enroll` both target an existing sequence.
740
+ - Real enrollment still requires that sequence to be `ACTIVE` unless direct enroll uses `reviewOnly=true`.
741
+ - Tasks still use raw HTTP.
742
+
582
743
  ## Safe run patterns (`firstN` + `--unprocessed-only`)
583
744
 
584
745
  Use this pattern for progressive rollouts.
@@ -0,0 +1 @@
1
+ """Autotouch CLI package."""