autotouch-cli 0.2.94__tar.gz → 0.2.98__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.
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/PKG-INFO +67 -2
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/README.md +66 -1
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/cli.py +24 -0
- autotouch_cli-0.2.98/autotouch_cli/commands/integrations.py +226 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/data/CLI_REFERENCE.md +185 -13
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/data/cli-manifest.json +1859 -791
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/parser.py +42 -2
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/templates.py +436 -29
- autotouch_cli-0.2.98/autotouch_cli/workflows/__init__.py +5 -0
- autotouch_cli-0.2.98/autotouch_cli/workflows/registry.py +192 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli.egg-info/PKG-INFO +67 -2
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli.egg-info/SOURCES.txt +3 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/pyproject.toml +2 -2
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/MANIFEST.in +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/__init__.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/cli_contracts.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/__init__.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/agents.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/auth.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/cells.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/columns.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/jobs.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/leads.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/linkedin.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/list_build.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/prompts.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/rows.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/search.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/sequences.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/tables.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/tasks.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/webhooks.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/commands/workspace_secrets.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/__init__.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/auth.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/config.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/csv_import.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/http.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/io.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/output.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/polling.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/run.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/core/validation.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/exceptions.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/mongo_status.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/parser_groups.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli/sequence_support.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli.egg-info/dependency_links.txt +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli.egg-info/entry_points.txt +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli.egg-info/requires.txt +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_cli.egg-info/top_level.txt +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_shared/__init__.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_shared/linkedin_contract.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_shared/linkedin_filters.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_shared/list_build_contract.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_shared/provider_registry.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/autotouch_shared/search_contract.py +0 -0
- {autotouch_cli-0.2.94 → autotouch_cli-0.2.98}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autotouch-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.98
|
|
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.
|
|
241
|
+
- `autotouch --version` should be `0.2.98` 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.
|
|
216
|
+
- `autotouch --version` should be `0.2.98` 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"])
|