autotouch-cli 0.2.93__tar.gz → 0.2.97__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 (58) hide show
  1. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/PKG-INFO +67 -2
  2. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/README.md +66 -1
  3. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/cli.py +24 -0
  4. autotouch_cli-0.2.97/autotouch_cli/commands/integrations.py +226 -0
  5. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/data/CLI_REFERENCE.md +185 -13
  6. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/data/cli-manifest.json +1859 -791
  7. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/parser.py +42 -2
  8. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/templates.py +439 -32
  9. autotouch_cli-0.2.97/autotouch_cli/workflows/__init__.py +5 -0
  10. autotouch_cli-0.2.97/autotouch_cli/workflows/registry.py +192 -0
  11. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli.egg-info/PKG-INFO +67 -2
  12. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli.egg-info/SOURCES.txt +3 -0
  13. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/pyproject.toml +2 -2
  14. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/MANIFEST.in +0 -0
  15. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/__init__.py +0 -0
  16. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/cli_contracts.py +0 -0
  17. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/__init__.py +0 -0
  18. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/agents.py +0 -0
  19. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/auth.py +0 -0
  20. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/cells.py +0 -0
  21. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/columns.py +0 -0
  22. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/jobs.py +0 -0
  23. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/leads.py +0 -0
  24. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/linkedin.py +0 -0
  25. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/list_build.py +0 -0
  26. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/prompts.py +0 -0
  27. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/rows.py +0 -0
  28. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/search.py +0 -0
  29. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/sequences.py +0 -0
  30. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/tables.py +0 -0
  31. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/tasks.py +0 -0
  32. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/webhooks.py +0 -0
  33. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/commands/workspace_secrets.py +0 -0
  34. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/__init__.py +0 -0
  35. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/auth.py +0 -0
  36. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/config.py +0 -0
  37. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/csv_import.py +0 -0
  38. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/http.py +0 -0
  39. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/io.py +0 -0
  40. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/output.py +0 -0
  41. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/polling.py +0 -0
  42. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/run.py +0 -0
  43. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/core/validation.py +0 -0
  44. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/exceptions.py +0 -0
  45. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/mongo_status.py +0 -0
  46. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/parser_groups.py +0 -0
  47. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli/sequence_support.py +0 -0
  48. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli.egg-info/dependency_links.txt +0 -0
  49. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli.egg-info/entry_points.txt +0 -0
  50. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli.egg-info/requires.txt +0 -0
  51. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_cli.egg-info/top_level.txt +0 -0
  52. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_shared/__init__.py +0 -0
  53. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_shared/linkedin_contract.py +0 -0
  54. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_shared/linkedin_filters.py +0 -0
  55. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_shared/list_build_contract.py +0 -0
  56. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_shared/provider_registry.py +0 -0
  57. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/autotouch_shared/search_contract.py +0 -0
  58. {autotouch_cli-0.2.93 → autotouch_cli-0.2.97}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.93
3
+ Version: 0.2.97
4
4
  Summary: Autotouch Smart Table CLI
5
5
  Project-URL: Homepage, https://app.autotouch.ai
6
6
  Project-URL: Documentation, https://github.com/nicolonic/autotouch_main/tree/main/docs/research-table/reference
@@ -154,6 +154,16 @@ autotouch rows get --table-id "$TABLE_ID" --row-id "$ROW_ID" --output json
154
154
  - Query leads: `autotouch leads query`
155
155
  - Find a lead by email or phone: `autotouch leads query --search '<email-or-phone>' --limit 10`
156
156
 
157
+ ## Sequence Automation Choices
158
+
159
+ When a user asks to create a campaign sequence, distinguish three separate decisions:
160
+
161
+ - Manual AI-draft review: `autotouch sequences recipe --type manual_review` (or `create`) sets `executionMode=MANUAL` and `aiDraft=true`; AI drafts content and a human approves/completes each task.
162
+ - Template-based automated send: `autotouch sequences recipe --type automated_template` (or `bulk_automated`) sets `executionMode=AUTOMATED` and `emailSendMode=AUTOMATED` with fixed templates; use this when the user explicitly asks to automate sending without review.
163
+ - LinkedIn-assisted outreach: `autotouch sequences recipe --type linkedin_outreach` uses manual AI-draft LinkedIn connection/message/email fallback tasks after the automated profile visit; use it only when LinkedIn touches are part of the campaign.
164
+
165
+ If the user says "automate the sequence" without asking for AI-written sends, choose the template-based automated path. Offer manual AI-draft review as the higher-personalization path, but call out that it creates upfront manual tasks while the system learns.
166
+
157
167
  ## Neural Search vs Durable List Build
158
168
 
159
169
  Autotouch has two different company/people discovery paths.
@@ -166,23 +176,78 @@ Use `autotouch search people` for provider-hidden people search when the target
166
176
 
167
177
  Use `autotouch list-build companies` and `autotouch list-build leads` for structured, repeatable LinkedIn/Sales Navigator list construction. This is the only CLI path for building LinkedIn-sourced company and lead lists. Treat list builds as the sourcing step for the Smart Table research workspace: build company/account records first by default, add the records to a research table, then enrich, score, segment, find related leads, attach signals/notes, and continue downstream workflows from that table. Use lead builds directly when the request is explicitly person/contact focused. This path uses Autotouch-managed provider access, so users do not need to connect their own LinkedIn account. Use filters like geography IDs, company size, industry IDs, title/persona, and current company IDs; call `autotouch list-build inputs` for supported values. Durable list builds run as background jobs with status/results endpoints and cost 1 credit per successful non-empty result page.
168
178
 
179
+ LinkedIn is an optional campaign channel, not the default for every outbound workflow. Use it when the user explicitly wants LinkedIn-sourced lists, profile visits, connection requests, or LinkedIn follow-up tasks. Prefer email/call/custom sequences or research-table workflows when LinkedIn would unnecessarily constrain output because of provider limits, cooldowns, missing profile URLs, or campaign fit.
180
+
169
181
  For structured company builds, start with industry IDs plus geo/company-size filters. User-supplied `keywords` are optional when structured filters are present; use them only to refine, disambiguate, or recover hard-to-classify targets instead of carrying the whole target definition.
170
182
 
171
183
  For account-first prospecting from LinkedIn/Sales Navigator, build companies/accounts first, inspect the returned company IDs, then pass those IDs to `autotouch list-build leads --current-company-id ...`. Do not use Exa company search as a default pre-step for every LinkedIn list build; use it when the user's target is genuinely semantic, niche, competitor-based, or not meant to be LinkedIn-sourced.
172
184
 
173
185
  Use `autotouch agents ...` for recurring signal-based discovery. Scheduled agents support `--target ACCOUNTS` for company/account output and `--target LEADS` for people output. Every agent writes a source/signal table for the evidence it used; lead agents then write `candidate_research.candidates[]` on source rows and list-sync those candidates into the lead/candidate output table. See the agent playbook for the full source-table and candidate-sync contract.
174
186
 
187
+ ## Workflow Plans
188
+
189
+ Use workflow plans for user goals, and recipes for individual payloads. The clean mental model is:
190
+
191
+ ```text
192
+ discover -> plan -> scaffold -> run primitives -> inspect
193
+ ```
194
+
195
+ - `autotouch integrations list` discovers connected sources and destinations.
196
+ - `autotouch workflows plan --type <TYPE>` explains the recommended path for a goal.
197
+ - `autotouch workflows scaffold --type <TYPE> --out-dir <DIR>` writes payload files and a command runbook.
198
+ - `autotouch columns recipe` and `autotouch sequences recipe` remain leaf-level templates.
199
+
200
+ Goal-level workflow types include `bulk-outreach`, `company-table-to-people`, `table-to-outreach`, `research-to-sequence`, `account-research`, `signal-outreach`, and `list-build-to-table`. These keep CRM, outreach providers, Autotouch Leads, and Autotouch Sequences as sources/destinations inside one organized workflow layer instead of creating one-off top-level commands.
201
+
202
+ ## Sources And Destinations
203
+
204
+ Use `autotouch integrations list` before wiring data movement. It returns connected sources and destinations with the directional verbs agents should use:
205
+
206
+ - `from_crm`: pull HubSpot or Attio records into a research table. Start with `autotouch integrations recipe --type from_crm --provider hubspot`.
207
+ - `to_crm`: push research-table rows to an external CRM such as HubSpot or Attio. Start with `autotouch columns recipe --type to_crm`.
208
+ - `to_outreach`: push research-table rows to an existing Instantly or Smartlead campaign. Start with `autotouch columns recipe --type to_outreach`.
209
+ - `to_leads`: sync research-table rows into Autotouch Leads before sequencing. Start with `autotouch columns recipe --type to_leads`.
210
+ - `to_sequence`: enroll Autotouch Leads into an Autotouch Sequence and assign generated tasks. Start with `autotouch columns recipe --type to_sequence`.
211
+
212
+ Use the direction in the user's wording. "Pull from HubSpot" means `from_crm`. "Push to HubSpot" means `to_crm`. "Add these leads to this Autotouch sequence" means `to_leads` first when lead IDs do not exist, then `to_sequence`.
213
+
214
+ CRM round trip:
215
+
216
+ ```bash
217
+ # 1. Confirm the org has the right source/destination connections.
218
+ autotouch integrations list --output json
219
+ autotouch integrations status --provider hubspot
220
+
221
+ # 2. Pull CRM records into a research table. This prints the API path/body to use;
222
+ # it does not execute the import by itself.
223
+ autotouch integrations recipe --type from_crm --provider hubspot --output json
224
+
225
+ # 3. Add enrichment columns to the research table.
226
+ autotouch columns recipe --type llm_enrichment --out-file enrich.json
227
+ autotouch columns recipe --type email_finder --out-file email-finder.json
228
+
229
+ # 4. Push enriched rows back to the CRM, then run the created column.
230
+ autotouch columns recipe --type to_crm --out-file push-to-crm.json
231
+ autotouch columns create --table-id <TABLE_ID> --data-file push-to-crm.json
232
+ autotouch columns run --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope filtered --wait
233
+ ```
234
+
175
235
  ## More
176
236
 
177
237
  For automation or agent-driven setup, use:
178
238
  - `autotouch cli-manifest --output json` for the local machine-readable command contract
179
239
  - `autotouch cli-reference` for the shipped parser-generated reference
180
240
  - `autotouch capabilities --output json` for provider/workflow contracts
181
- - `autotouch --version` should be `0.2.92` or newer for structured company list builds without user-supplied keywords, stored list-build input lookup, research-workspace list-build guidance, the cleaned single LinkedIn-sourced list-build path, Exa Company Search up to 100 results, scheduled agent `--target ACCOUNTS|LEADS`, paced HTTP Request column contracts, V2 sequence flowGraph recipes, real agent soft-delete with associated-table handling, and research-table sequence handoff assignee config
241
+ - `autotouch --version` should be `0.2.97` or newer for structured company list builds without user-supplied keywords, stored list-build input lookup, research-workspace list-build guidance, the cleaned single LinkedIn-sourced list-build path, Exa Company Search up to 100 results, scheduled agent `--target ACCOUNTS|LEADS`, paced HTTP Request column contracts, branch-aware LinkedIn sequence recipes, real agent soft-delete with associated-table handling, research-table sequence handoff assignee config, backend-owned directional source/destination helpers, and goal-level workflow plans
182
242
  - `autotouch capabilities --output json --select list_builds` for documented list-build inputs such as geography IDs, company size buckets, profile language, and company IDs
243
+ - `autotouch integrations list` and `autotouch integrations status --provider <provider>` before choosing source/destination workflows
244
+ - `autotouch workflows plan --type bulk-outreach` and `autotouch workflows scaffold --type bulk-outreach --out-dir workflow` for goal-level workflow planning
245
+ - `autotouch integrations recipe --type from_crm --provider hubspot` for CRM-to-research-table imports
246
+ - `autotouch columns recipe --type to_crm|to_outreach|to_leads|to_sequence` for research-table destination workflows
183
247
  - `autotouch list-build inputs` and `autotouch list-build pricing` before creating durable list-build jobs
184
248
  - `autotouch list-build companies` and `autotouch list-build leads` for durable LinkedIn-sourced company and lead list builds with Smart Table-owned background workers, visible progress, and no user-owned LinkedIn connection requirement
185
249
  - `autotouch linkedin status` and `autotouch linkedin limits` for connected-account diagnostics
250
+ - `autotouch sequences recipe --type linkedin_outreach` only when the campaign should include LinkedIn touches; the emitted branch waits for connection acceptance before LinkedIn chat and uses email fallback after the wait window
186
251
  - `autotouch rows list` / `autotouch rows get` / `autotouch cells get` for read-back and audit
187
252
  - `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
188
253
  - `pip install 'autotouch-cli[mongo]'` if you need the Mongo-backed `status` / `watch` commands
@@ -129,6 +129,16 @@ autotouch rows get --table-id "$TABLE_ID" --row-id "$ROW_ID" --output json
129
129
  - Query leads: `autotouch leads query`
130
130
  - Find a lead by email or phone: `autotouch leads query --search '<email-or-phone>' --limit 10`
131
131
 
132
+ ## Sequence Automation Choices
133
+
134
+ When a user asks to create a campaign sequence, distinguish three separate decisions:
135
+
136
+ - Manual AI-draft review: `autotouch sequences recipe --type manual_review` (or `create`) sets `executionMode=MANUAL` and `aiDraft=true`; AI drafts content and a human approves/completes each task.
137
+ - Template-based automated send: `autotouch sequences recipe --type automated_template` (or `bulk_automated`) sets `executionMode=AUTOMATED` and `emailSendMode=AUTOMATED` with fixed templates; use this when the user explicitly asks to automate sending without review.
138
+ - LinkedIn-assisted outreach: `autotouch sequences recipe --type linkedin_outreach` uses manual AI-draft LinkedIn connection/message/email fallback tasks after the automated profile visit; use it only when LinkedIn touches are part of the campaign.
139
+
140
+ If the user says "automate the sequence" without asking for AI-written sends, choose the template-based automated path. Offer manual AI-draft review as the higher-personalization path, but call out that it creates upfront manual tasks while the system learns.
141
+
132
142
  ## Neural Search vs Durable List Build
133
143
 
134
144
  Autotouch has two different company/people discovery paths.
@@ -141,23 +151,78 @@ Use `autotouch search people` for provider-hidden people search when the target
141
151
 
142
152
  Use `autotouch list-build companies` and `autotouch list-build leads` for structured, repeatable LinkedIn/Sales Navigator list construction. This is the only CLI path for building LinkedIn-sourced company and lead lists. Treat list builds as the sourcing step for the Smart Table research workspace: build company/account records first by default, add the records to a research table, then enrich, score, segment, find related leads, attach signals/notes, and continue downstream workflows from that table. Use lead builds directly when the request is explicitly person/contact focused. This path uses Autotouch-managed provider access, so users do not need to connect their own LinkedIn account. Use filters like geography IDs, company size, industry IDs, title/persona, and current company IDs; call `autotouch list-build inputs` for supported values. Durable list builds run as background jobs with status/results endpoints and cost 1 credit per successful non-empty result page.
143
153
 
154
+ LinkedIn is an optional campaign channel, not the default for every outbound workflow. Use it when the user explicitly wants LinkedIn-sourced lists, profile visits, connection requests, or LinkedIn follow-up tasks. Prefer email/call/custom sequences or research-table workflows when LinkedIn would unnecessarily constrain output because of provider limits, cooldowns, missing profile URLs, or campaign fit.
155
+
144
156
  For structured company builds, start with industry IDs plus geo/company-size filters. User-supplied `keywords` are optional when structured filters are present; use them only to refine, disambiguate, or recover hard-to-classify targets instead of carrying the whole target definition.
145
157
 
146
158
  For account-first prospecting from LinkedIn/Sales Navigator, build companies/accounts first, inspect the returned company IDs, then pass those IDs to `autotouch list-build leads --current-company-id ...`. Do not use Exa company search as a default pre-step for every LinkedIn list build; use it when the user's target is genuinely semantic, niche, competitor-based, or not meant to be LinkedIn-sourced.
147
159
 
148
160
  Use `autotouch agents ...` for recurring signal-based discovery. Scheduled agents support `--target ACCOUNTS` for company/account output and `--target LEADS` for people output. Every agent writes a source/signal table for the evidence it used; lead agents then write `candidate_research.candidates[]` on source rows and list-sync those candidates into the lead/candidate output table. See the agent playbook for the full source-table and candidate-sync contract.
149
161
 
162
+ ## Workflow Plans
163
+
164
+ Use workflow plans for user goals, and recipes for individual payloads. The clean mental model is:
165
+
166
+ ```text
167
+ discover -> plan -> scaffold -> run primitives -> inspect
168
+ ```
169
+
170
+ - `autotouch integrations list` discovers connected sources and destinations.
171
+ - `autotouch workflows plan --type <TYPE>` explains the recommended path for a goal.
172
+ - `autotouch workflows scaffold --type <TYPE> --out-dir <DIR>` writes payload files and a command runbook.
173
+ - `autotouch columns recipe` and `autotouch sequences recipe` remain leaf-level templates.
174
+
175
+ Goal-level workflow types include `bulk-outreach`, `company-table-to-people`, `table-to-outreach`, `research-to-sequence`, `account-research`, `signal-outreach`, and `list-build-to-table`. These keep CRM, outreach providers, Autotouch Leads, and Autotouch Sequences as sources/destinations inside one organized workflow layer instead of creating one-off top-level commands.
176
+
177
+ ## Sources And Destinations
178
+
179
+ Use `autotouch integrations list` before wiring data movement. It returns connected sources and destinations with the directional verbs agents should use:
180
+
181
+ - `from_crm`: pull HubSpot or Attio records into a research table. Start with `autotouch integrations recipe --type from_crm --provider hubspot`.
182
+ - `to_crm`: push research-table rows to an external CRM such as HubSpot or Attio. Start with `autotouch columns recipe --type to_crm`.
183
+ - `to_outreach`: push research-table rows to an existing Instantly or Smartlead campaign. Start with `autotouch columns recipe --type to_outreach`.
184
+ - `to_leads`: sync research-table rows into Autotouch Leads before sequencing. Start with `autotouch columns recipe --type to_leads`.
185
+ - `to_sequence`: enroll Autotouch Leads into an Autotouch Sequence and assign generated tasks. Start with `autotouch columns recipe --type to_sequence`.
186
+
187
+ Use the direction in the user's wording. "Pull from HubSpot" means `from_crm`. "Push to HubSpot" means `to_crm`. "Add these leads to this Autotouch sequence" means `to_leads` first when lead IDs do not exist, then `to_sequence`.
188
+
189
+ CRM round trip:
190
+
191
+ ```bash
192
+ # 1. Confirm the org has the right source/destination connections.
193
+ autotouch integrations list --output json
194
+ autotouch integrations status --provider hubspot
195
+
196
+ # 2. Pull CRM records into a research table. This prints the API path/body to use;
197
+ # it does not execute the import by itself.
198
+ autotouch integrations recipe --type from_crm --provider hubspot --output json
199
+
200
+ # 3. Add enrichment columns to the research table.
201
+ autotouch columns recipe --type llm_enrichment --out-file enrich.json
202
+ autotouch columns recipe --type email_finder --out-file email-finder.json
203
+
204
+ # 4. Push enriched rows back to the CRM, then run the created column.
205
+ autotouch columns recipe --type to_crm --out-file push-to-crm.json
206
+ autotouch columns create --table-id <TABLE_ID> --data-file push-to-crm.json
207
+ autotouch columns run --table-id <TABLE_ID> --column-id <COLUMN_ID> --scope filtered --wait
208
+ ```
209
+
150
210
  ## More
151
211
 
152
212
  For automation or agent-driven setup, use:
153
213
  - `autotouch cli-manifest --output json` for the local machine-readable command contract
154
214
  - `autotouch cli-reference` for the shipped parser-generated reference
155
215
  - `autotouch capabilities --output json` for provider/workflow contracts
156
- - `autotouch --version` should be `0.2.92` or newer for structured company list builds without user-supplied keywords, stored list-build input lookup, research-workspace list-build guidance, the cleaned single LinkedIn-sourced list-build path, Exa Company Search up to 100 results, scheduled agent `--target ACCOUNTS|LEADS`, paced HTTP Request column contracts, V2 sequence flowGraph recipes, real agent soft-delete with associated-table handling, and research-table sequence handoff assignee config
216
+ - `autotouch --version` should be `0.2.97` or newer for structured company list builds without user-supplied keywords, stored list-build input lookup, research-workspace list-build guidance, the cleaned single LinkedIn-sourced list-build path, Exa Company Search up to 100 results, scheduled agent `--target ACCOUNTS|LEADS`, paced HTTP Request column contracts, branch-aware LinkedIn sequence recipes, real agent soft-delete with associated-table handling, research-table sequence handoff assignee config, backend-owned directional source/destination helpers, and goal-level workflow plans
157
217
  - `autotouch capabilities --output json --select list_builds` for documented list-build inputs such as geography IDs, company size buckets, profile language, and company IDs
218
+ - `autotouch integrations list` and `autotouch integrations status --provider <provider>` before choosing source/destination workflows
219
+ - `autotouch workflows plan --type bulk-outreach` and `autotouch workflows scaffold --type bulk-outreach --out-dir workflow` for goal-level workflow planning
220
+ - `autotouch integrations recipe --type from_crm --provider hubspot` for CRM-to-research-table imports
221
+ - `autotouch columns recipe --type to_crm|to_outreach|to_leads|to_sequence` for research-table destination workflows
158
222
  - `autotouch list-build inputs` and `autotouch list-build pricing` before creating durable list-build jobs
159
223
  - `autotouch list-build companies` and `autotouch list-build leads` for durable LinkedIn-sourced company and lead list builds with Smart Table-owned background workers, visible progress, and no user-owned LinkedIn connection requirement
160
224
  - `autotouch linkedin status` and `autotouch linkedin limits` for connected-account diagnostics
225
+ - `autotouch sequences recipe --type linkedin_outreach` only when the campaign should include LinkedIn touches; the emitted branch waits for connection acceptance before LinkedIn chat and uses email fallback after the wait window
161
226
  - `autotouch rows list` / `autotouch rows get` / `autotouch cells get` for read-back and audit
162
227
  - `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
163
228
  - `pip install 'autotouch-cli[mongo]'` if you need the Mongo-backed `status` / `watch` commands
@@ -75,6 +75,14 @@ from autotouch_cli.commands.jobs import (
75
75
  cmd_jobs_list as cmd_jobs_list_impl,
76
76
  cmd_jobs_watch as cmd_jobs_watch_impl,
77
77
  )
78
+ from autotouch_cli.commands.integrations import (
79
+ IntegrationCommandRuntime as IntegrationCommandHandlerRuntime,
80
+ cmd_integrations_from_crm_status as cmd_integrations_from_crm_status_impl,
81
+ cmd_integrations_list as cmd_integrations_list_impl,
82
+ cmd_integrations_recipe as cmd_integrations_recipe_impl,
83
+ cmd_integrations_status as cmd_integrations_status_impl,
84
+ cmd_integrations_to_crm_status as cmd_integrations_to_crm_status_impl,
85
+ )
78
86
  from autotouch_cli.commands.leads import (
79
87
  LeadCommandRuntime as LeadCommandHandlerRuntime,
80
88
  cmd_leads_count as cmd_leads_count_impl,
@@ -1379,6 +1387,15 @@ def _list_build_command_runtime() -> ListBuildCommandHandlerRuntime:
1379
1387
  )
1380
1388
 
1381
1389
 
1390
+ def _integration_command_runtime() -> IntegrationCommandHandlerRuntime:
1391
+ return IntegrationCommandHandlerRuntime(
1392
+ resolve_token=_resolve_token,
1393
+ request_api=_request_api,
1394
+ print_json=lambda data, compact=False: _print_json(data, compact=compact),
1395
+ emit_text=_emit_text,
1396
+ )
1397
+
1398
+
1382
1399
  # ---------------------------------------------------------------------------
1383
1400
  # Command registry — replaces ~110 thin shim functions
1384
1401
  # ---------------------------------------------------------------------------
@@ -1507,6 +1524,13 @@ _register("jobs_get", cmd_jobs_get_impl, _job_command_runtime)
1507
1524
  _register("jobs_list", cmd_jobs_list_impl, _job_command_runtime)
1508
1525
  _register("jobs_watch", cmd_jobs_watch_impl, _job_command_runtime)
1509
1526
 
1527
+ # -- Integration commands --
1528
+ _register("integrations_list", cmd_integrations_list_impl, _integration_command_runtime)
1529
+ _register("integrations_status", cmd_integrations_status_impl, _integration_command_runtime)
1530
+ _register("integrations_recipe", cmd_integrations_recipe_impl, _integration_command_runtime)
1531
+ _register("integrations_from_crm_status", cmd_integrations_from_crm_status_impl, _integration_command_runtime)
1532
+ _register("integrations_to_crm_status", cmd_integrations_to_crm_status_impl, _integration_command_runtime)
1533
+
1510
1534
  # -- Lead commands --
1511
1535
  _register("leads_query", cmd_leads_query_impl, _lead_command_runtime)
1512
1536
  _register("leads_get", cmd_leads_get_impl, _lead_command_runtime)
@@ -0,0 +1,226 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from dataclasses import dataclass
5
+ from typing import Any, Callable, Dict, Optional, Sequence
6
+
7
+ from autotouch_cli.exceptions import AutotouchInputError
8
+
9
+
10
+ INTEGRATION_RECIPE_TYPES = ("from_crm",)
11
+
12
+ _CRM_PROVIDERS = {"hubspot", "attio"}
13
+ _OUTREACH_PROVIDERS = {"instantly", "smartlead"}
14
+ _PROVIDER_LABELS = {
15
+ "attio": "Attio",
16
+ "hubspot": "HubSpot",
17
+ "instantly": "Instantly",
18
+ "smartlead": "Smartlead",
19
+ }
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class IntegrationCommandRuntime:
24
+ resolve_token: Callable[[Optional[str], bool], Optional[str]]
25
+ request_api: Callable[..., Any]
26
+ print_json: Callable[[Any, bool], None]
27
+ emit_text: Callable[[str], None]
28
+
29
+
30
+ def cmd_integrations_list(args: argparse.Namespace, *, runtime: IntegrationCommandRuntime) -> None:
31
+ token = runtime.resolve_token(args.token, required=True)
32
+ data = runtime.request_api(
33
+ "GET",
34
+ "/api/integrations/catalog",
35
+ base_url=args.base_url,
36
+ token=token,
37
+ use_x_api_key=args.use_x_api_key,
38
+ timeout=args.timeout,
39
+ verbose=args.verbose,
40
+ )
41
+ runtime.print_json(data if isinstance(data, dict) else {}, args.compact)
42
+
43
+
44
+ def cmd_integrations_status(args: argparse.Namespace, *, runtime: IntegrationCommandRuntime) -> None:
45
+ token = runtime.resolve_token(args.token, required=True)
46
+ provider = str(args.provider or "").strip().lower()
47
+ if provider not in _CRM_PROVIDERS and provider not in _OUTREACH_PROVIDERS:
48
+ raise AutotouchInputError("--provider must be one of: hubspot, attio, instantly, smartlead")
49
+ data = runtime.request_api(
50
+ "GET",
51
+ "/api/integrations/catalog",
52
+ base_url=args.base_url,
53
+ token=token,
54
+ use_x_api_key=args.use_x_api_key,
55
+ timeout=args.timeout,
56
+ verbose=args.verbose,
57
+ )
58
+ integrations = data.get("integrations") if isinstance(data, dict) else []
59
+ match = next(
60
+ (item for item in integrations if isinstance(item, dict) and str(item.get("id") or "").lower() == provider),
61
+ None,
62
+ )
63
+ if not match:
64
+ raise AutotouchInputError(f"provider not present in integration catalog: {provider}")
65
+ runtime.print_json(match, args.compact)
66
+
67
+
68
+ def _from_crm_recipe(provider: str) -> Dict[str, Any]:
69
+ provider = provider.strip().lower()
70
+ if provider not in _CRM_PROVIDERS:
71
+ raise AutotouchInputError("from_crm recipe --provider must be hubspot or attio")
72
+ return {
73
+ "provider": provider,
74
+ "path": f"/api/crm/{provider}/lists/<LIST_ID>/import",
75
+ "method": "POST",
76
+ "body": {
77
+ "table_mode": "create",
78
+ "table_id": "<TABLE_ID_FOR_APPEND>",
79
+ "import_type": "company",
80
+ "selected_fields": ["name", "domain"],
81
+ "table_name": f"{_PROVIDER_LABELS.get(provider, provider)} Import",
82
+ },
83
+ "notes": [
84
+ "Directional recipe: CRM -> research table.",
85
+ "Use list_id='filters' with filters[] for filter-based imports.",
86
+ "Use table_mode='create' for a new research table or 'append' with table_id to add to an existing table.",
87
+ "Check progress with autotouch integrations from-crm-status --task-id <TASK_ID>.",
88
+ ],
89
+ }
90
+
91
+
92
+ def cmd_integrations_recipe(args: argparse.Namespace, *, runtime: IntegrationCommandRuntime) -> None:
93
+ selected_type = str(args.type or "from_crm").strip()
94
+ if selected_type != "from_crm":
95
+ raise AutotouchInputError("unsupported integrations recipe type")
96
+ data = {
97
+ "type": selected_type,
98
+ "payload": _from_crm_recipe(str(args.provider or "hubspot")),
99
+ }
100
+ runtime.print_json(data, args.compact)
101
+
102
+
103
+ def cmd_integrations_from_crm_status(args: argparse.Namespace, *, runtime: IntegrationCommandRuntime) -> None:
104
+ token = runtime.resolve_token(args.token, required=True)
105
+ data = runtime.request_api(
106
+ "GET",
107
+ f"/api/crm/import-status/{args.task_id}",
108
+ base_url=args.base_url,
109
+ token=token,
110
+ use_x_api_key=args.use_x_api_key,
111
+ timeout=args.timeout,
112
+ verbose=args.verbose,
113
+ )
114
+ runtime.print_json(data, args.compact)
115
+
116
+
117
+ def cmd_integrations_to_crm_status(args: argparse.Namespace, *, runtime: IntegrationCommandRuntime) -> None:
118
+ token = runtime.resolve_token(args.token, required=True)
119
+ data = runtime.request_api(
120
+ "GET",
121
+ f"/api/crm/push-status/{args.task_id}",
122
+ base_url=args.base_url,
123
+ token=token,
124
+ use_x_api_key=args.use_x_api_key,
125
+ timeout=args.timeout,
126
+ verbose=args.verbose,
127
+ )
128
+ runtime.print_json(data, args.compact)
129
+
130
+
131
+ def register_integrations_subcommands(
132
+ subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
133
+ *,
134
+ add_api_common_arguments: Callable[[argparse.ArgumentParser], None],
135
+ add_output_formatting_arguments: Callable[[argparse.ArgumentParser], None],
136
+ handlers: Dict[str, Callable[[argparse.Namespace], None]],
137
+ recipe_types: Sequence[str] = INTEGRATION_RECIPE_TYPES,
138
+ ) -> None:
139
+ parser = subparsers.add_parser(
140
+ "integrations",
141
+ help="Discover connected sources/destinations and CRM import/push helpers",
142
+ description=(
143
+ "Use this before choosing a workflow. Directional vocabulary: from_crm pulls HubSpot/Attio into "
144
+ "a research table; to_crm pushes rows to HubSpot/Attio; to_outreach pushes rows to Instantly/Smartlead; "
145
+ "to_leads syncs rows to Autotouch Leads; to_sequence enrolls Leads into Autotouch Sequences."
146
+ ),
147
+ )
148
+ parser._codex_examples = [
149
+ "autotouch integrations list",
150
+ "autotouch integrations status --provider hubspot",
151
+ "autotouch integrations recipe --type from_crm --provider hubspot",
152
+ "autotouch columns recipe --type to_crm --out-file push-to-crm.json",
153
+ "autotouch integrations to-crm-status --task-id <TASK_ID>",
154
+ ]
155
+ integrations_sub = parser.add_subparsers(dest="integrations_cmd", required=True)
156
+
157
+ plist = integrations_sub.add_parser(
158
+ "list",
159
+ help="List available source/destination integrations",
160
+ description=(
161
+ "Read the backend-owned integration catalog. The response includes sources, destinations, and recipes. "
162
+ "Use sources for pull workflows such as from_crm, and destinations for push/sync/enroll workflows such "
163
+ "as to_crm, to_outreach, to_leads, and to_sequence."
164
+ ),
165
+ )
166
+ plist._codex_examples = [
167
+ "autotouch integrations list --output json",
168
+ "autotouch integrations list --select sources",
169
+ "autotouch integrations list --select destinations",
170
+ ]
171
+ add_api_common_arguments(plist)
172
+ plist.set_defaults(func=handlers["list"])
173
+
174
+ pstatus = integrations_sub.add_parser(
175
+ "status",
176
+ help="Show connection status for one integration",
177
+ description=(
178
+ "Read one provider from the integration catalog. The result shows connected/status/supports so agents can "
179
+ "decide whether the provider can be used for from_crm, to_crm, or to_outreach before creating workflow columns."
180
+ ),
181
+ )
182
+ pstatus.add_argument("--provider", required=True, choices=["hubspot", "attio", "instantly", "smartlead"])
183
+ pstatus._codex_examples = [
184
+ "autotouch integrations status --provider hubspot",
185
+ "autotouch integrations status --provider instantly --select connected",
186
+ "autotouch integrations status --provider attio --select supports",
187
+ ]
188
+ add_api_common_arguments(pstatus)
189
+ pstatus.set_defaults(func=handlers["status"])
190
+
191
+ precipe = integrations_sub.add_parser(
192
+ "recipe",
193
+ help="Print integration workflow payload recipes",
194
+ description=(
195
+ "Print payload guidance for integration workflows. This does not execute the workflow; for from_crm, use the "
196
+ "returned path/body with the API to create or append a research table."
197
+ ),
198
+ )
199
+ precipe.add_argument("--type", choices=list(recipe_types), default="from_crm")
200
+ precipe.add_argument("--provider", choices=["hubspot", "attio"], default="hubspot")
201
+ precipe._codex_examples = [
202
+ "autotouch integrations recipe --type from_crm --provider hubspot",
203
+ "autotouch integrations recipe --type from_crm --provider attio --output json --compact",
204
+ ]
205
+ add_output_formatting_arguments(precipe)
206
+ precipe.set_defaults(func=handlers["recipe"])
207
+
208
+ pfromstatus = integrations_sub.add_parser(
209
+ "from-crm-status",
210
+ help="Check a CRM import job",
211
+ description="Check a CRM import task created by POST /api/crm/{provider}/lists/{list_id}/import.",
212
+ )
213
+ pfromstatus.add_argument("--task-id", required=True)
214
+ pfromstatus._codex_examples = ["autotouch integrations from-crm-status --task-id <TASK_ID>"]
215
+ add_api_common_arguments(pfromstatus)
216
+ pfromstatus.set_defaults(func=handlers["from_crm_status"])
217
+
218
+ ptostatus = integrations_sub.add_parser(
219
+ "to-crm-status",
220
+ help="Check a CRM push job",
221
+ description="Check a CRM push task created by running a research-table to_crm column.",
222
+ )
223
+ ptostatus.add_argument("--task-id", required=True)
224
+ ptostatus._codex_examples = ["autotouch integrations to-crm-status --task-id <TASK_ID>"]
225
+ add_api_common_arguments(ptostatus)
226
+ ptostatus.set_defaults(func=handlers["to_crm_status"])