@agentled/cli 0.8.4 → 0.8.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentled/cli",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agentled
3
- version: 0.7.2
3
+ version: 0.7.3
4
4
  description: Build, manage, and execute Agentled AI workflows via MCP tools. Use when the user asks to create workflows, automate tasks, enrich leads, scrape websites, find emails, manage executions, or interact with any Agentled workspace capability.
5
5
  user-invocable: false
6
6
  ---
@@ -279,7 +279,7 @@ Every pipeline step **must** set `type` to one of these values. Any other value
279
279
  | `return` | Terminal step for **child** workflows — returns data to the caller | `{ id, type: "return", name, returnConfig: { fields: [{ name, stepId, field }] } }` |
280
280
  | `milestone` | Terminal step for **top-level** workflows | `{ id, type: "milestone", name }` |
281
281
  | `share` | Create a public share URL for prior step output | `{ id, type: "share", name, shareConfig: { outputSteps, visibility }, next: { stepId } }` |
282
- | `wait` | Delay / pause between steps | `{ id, type: "wait", name, waitConfig: { durationMs } | { untilISO }, next: { stepId } }` |
282
+ | `wait` | Delay / pause between steps | `{ id, type: "wait", name, pipelineStepStartConditions: { trigger: { type: "delay", config: { delay: "60s" } } }, next: { stepId } }` |
283
283
  | `branch` | Conditional routing to one of several paths | `{ id, type: "branch", name, branchConfig: { branches: [...] }, next: [...] }` |
284
284
  | `parallel` | Fan-out to parallel branches | `{ id, type: "parallel", name, parallelConfig: { branches: [...] }, next: { stepId } }` |
285
285
  | `loop` | Iterate over a collection as a first-class step (prefer `loopConfig` on an action step for most cases) | `{ id, type: "loop", name, loopConfig: {…}, next: { stepId } }` |
@@ -289,6 +289,8 @@ Every pipeline step **must** set `type` to one of these values. Any other value
289
289
  | `systemAction` | Legacy — kept for backward compatibility; prefer `appAction` | |
290
290
  <!-- agentled-step-types:end -->
291
291
 
292
+ For `wait`, set `pipelineStepStartConditions.trigger.config.delay` to a positive whole-number duration with a unit: `"60s"`, `"5m"`, `"1h"`, or `"1d"`. The runtime does not read `waitConfig.durationMs`, `waitConfig.untilISO`, `stepInputData.delayMs`, or `configuration.delayMs`. A missing or unparseable delay currently completes immediately with `{ delayed: true, delayMs: 0 }`; that result does not prove a wait occurred.
293
+
292
294
  > Use `get_step_schema` to retrieve the authoritative input/output schema for any step type. Common shapes and template-variable syntax are in `references/step-schemas.md`.
293
295
 
294
296
  ## Before you build: read the schema and the patterns
@@ -35,6 +35,27 @@ Every workflow needs at minimum: a trigger step, one or more action steps, and a
35
35
 
36
36
  `pipelineStepStartConditions.trigger.type` is one of: `manual`, `schedule`, `webhook`, `event`, `delay`, `app_event`. For `schedule` add `config: { frequency: "daily", time: "07:00" }` (or a cron expression). For `app_event` add `config: { appId, triggerSlug, connectionSource }`. **Do not put `triggerType` at the step root** — it is not in the step schema and is silently dropped on save.
37
37
 
38
+ ### Wait
39
+
40
+ ```json
41
+ {
42
+ "id": "wait-before-next",
43
+ "type": "wait",
44
+ "name": "Wait 60 seconds",
45
+ "pipelineStepStartConditions": {
46
+ "trigger": {
47
+ "type": "delay",
48
+ "config": { "delay": "60s" }
49
+ }
50
+ },
51
+ "next": { "stepId": "next-step" }
52
+ }
53
+ ```
54
+
55
+ Set `pipelineStepStartConditions.trigger.config.delay` to a positive whole-number duration with a unit: `"60s"`, `"5m"`, `"1h"`, or `"1d"`. Delays over five minutes use scheduled resumption; shorter delays sleep inline subject to the remaining runtime budget. This is a relative duration, not an absolute timestamp.
56
+
57
+ The runtime does not read `waitConfig.durationMs`, `waitConfig.untilISO`, `stepInputData.delayMs`, or `configuration.delayMs`. A missing or unparseable delay currently completes immediately with `{ delayed: true, delayMs: 0 }`; that result does not prove a wait occurred. Confirm elapsed-time behavior in a bounded test before relying on a wait for pacing.
58
+
38
59
  ### App Action
39
60
  ```json
40
61
  {
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: gtm-operator
3
- version: 0.17.0
3
+ version: 0.25.0
4
4
  description: Start from saved company context and finish a useful GTM result in one run: find and qualify 2-3 accounts, enrich likely buyers, save private work, and prepare outreach drafts before improving from feedback.
5
5
  category: gtm
6
- allowedApps: agentled, web-scraping, kg, hunter, clay, gmail, linkedin, dripify
7
- allowedActions: web-scraping.scrape, agentled.google_maps, agentled.linkedin_post_search, agentled.get-linkedin-company-from-url, agentled.get-linkedin-profile-from-url, agentled.find-linkedin-profile-url, agentled.linkedin_company_posts, agentled.linkedin_profile_posts, hunter.find-email-person-domain, hunter.get-emails-from-company-domain, kg.read-text, kg.get-rows-by-ids, kg.upsert-rows, clay.search-companies, clay.search-people, clay.get-routine-results, clay.get-query-reference, clay.send-to-webhook
6
+ allowedApps: agentled, web-scraping, kg, hunter, clay, companies-house, gmail, linkedin, dripify, http-request
7
+ allowedActions: http-request.request, web-scraping.scrape, agentled.google_maps, agentled.linkedin_post_search, agentled.get-linkedin-company-from-url, agentled.get-linkedin-profile-from-url, agentled.find-linkedin-profile-url, agentled.linkedin_company_posts, agentled.linkedin_profile_posts, hunter.find-email-person-domain, hunter.get-emails-from-company-domain, kg.read-text, kg.write-text, kg.get-rows-by-ids, kg.upsert-rows, clay.search-companies, clay.search-people, clay.get-routine-results, clay.get-query-reference, clay.send-to-webhook, companies-house.advanced-search, companies-house.company-profile, companies-house.officers
8
8
  relevanceKeywords: ICP, prospect research, lead discovery, local business prospecting, qualification, enrichment, Clay, Hunter, LinkedIn, Instantly, outreach draft, GTM, feedback, automation
9
9
  ---
10
10
 
@@ -22,7 +22,7 @@ When onboarding or workspace context already provides a company URL, do not ask
22
22
  2. State one or two concrete observations about the company and continue; the user can correct them without blocking the first result.
23
23
  3. State a short draft ICP with clearly labeled assumptions. Ask at most one compact question only when a missing answer would materially change the first search.
24
24
  4. Research exactly 2-3 source-backed prospect examples. Prefer first-party company evidence and fresh public sources. Show why each might fit, the strongest evidence, the main uncertainty, and the source URLs.
25
- 5. For every promising example, use available LinkedIn and Hunter actions to identify a likely buyer and usable contact path. Follow "Finding a contact email" below: use `hunter.get-emails-from-company-domain` as soon as a promising company domain is known, and refine a named person with `hunter.find-email-person-domain`.
25
+ 5. For every promising example, use available LinkedIn, Hunter and connected Clay actions to identify a likely buyer and usable contact path. Follow "Finding a contact email" below: use `hunter.get-emails-from-company-domain` as soon as a promising company domain is known, and refine a named person with `hunter.find-email-person-domain`.
26
26
  6. Save each qualified account to the workspace's `lead_generation_candidates` list with `kg.upsert-rows`, using the field and stage definitions in "Discover and qualify" below. Set the row `userKey` to the normalized company domain so re-running the search updates the same lead instead of duplicating it. Read the returned `rowId` values back with `kg.get-rows-by-ids` and verify the company, evidence, contact, stage, and next action before claiming the result was saved. Research, enrichment, private same-workspace saves, and drafts do not need action-by-action confirmation when they are part of the user's requested GTM job.
27
27
  7. Ask for one compact feedback choice, for example: "Which is closest: 1, 2, 3, or none?" Also accept natural-language corrections. Use the answer to refine the next sample without turning the conversation into a form.
28
28
 
@@ -88,6 +88,15 @@ Write action and readback:
88
88
 
89
89
  If the workspace does not allow the write, the integration's authorized scopes do not include `kg.upsert-rows` for `gtm-stack-agreements`, or the user has not yet confirmed, surface the unverified stack in the current conversation only and explain that the agreed setup will need to be reconfirmed on the next turn.
90
90
 
91
+ ## Segment changes and the company email rule
92
+
93
+ You own the pitch, the target split and the send schedule. The user's gate is the email itself: they approve or reject each email in the approval list before it sends. Do not stop to ask the user to approve a template, a split or a schedule; decide, save your reasoning, and carry on to drafts. If the user gives direction on copy or targeting, follow it. When the target segment changes (in conversation or on returning to saved work), write a pitch for the new segment before drafting recipient emails for it.
94
+
95
+ 1. **Read what is saved.** Use `kg.read-text` on `company.profile` (and any saved email rule) to see the current target and approved copy. Reuse existing keys; do not create competing sources of truth.
96
+ 2. **Write the pitch for the new segment.** Write it from the company profile, the segment's buyer and problem, and the evidence you gathered. Say what it assumes. Do not reuse another segment's angle or invent claims.
97
+ 3. **Save the copy.** Use `kg.write-text` (find + replace for an existing rule) to save the subject/body with the segment it is for and what it assumes, then read it back.
98
+ 4. **Draft from the saved copy.** Fill only the recipient placeholders. The user approves every email before it sends, so an email drafted from an earlier pitch is the user's call to send or reject; point out when a pending draft uses a different pitch than the current one.
99
+
91
100
  ## Progressive GTM ladder
92
101
 
93
102
  Advance only as the user sees useful results.
@@ -117,6 +126,9 @@ negotiable.
117
126
  - `qualificationReason` — The specific evidence that this account fits: industry, signal, buyer match. Not a generic label. Leave empty while fit is still unclear. Shown in: Record page, and the Qualified milestone.
118
127
  - `nextAction` — A specific next step for THIS company, e.g. "Draft outreach to the founder". Never a placeholder like "Follow up". Shown in: Next action column.
119
128
  - `founderEmail` — The contact's email once found. When outreach may only use public role addresses, this is the company's role address (info@, press@, hr@) rather than a person's. Leave empty rather than guessing an address. Shown in: Record page contact links.
129
+ - `emailEvidence` — Email evidence label: "Verified by provider" only with explicit deliverable/valid verification for this exact person and work address; "Published on site" when the exact address is publicly listed by the firm or person (including their LinkedIn); "Pattern guess" for an inferred address; "Unverified" otherwise. Confidence scores alone are not verification. Save this together with every email update. Shown in: Email evidence column and record profile.
130
+ - `emailEvidenceSource` — Email-specific evidence: provider action, exact address, verification status and checked time, or the exact publication URL and quoted address. Keep lead sourceUrl for account discovery. Update this together with the email so evidence cannot describe a previous address. Shown in: Record profile.
131
+ - `emailCandidate` — Optional inferred or unverified email for research only. Keep founderEmail empty for pattern guesses and unverified candidates; never mark them ready_for_outreach. Set nextAction to verify the address or use LinkedIn. Shown in: Record profile.
120
132
  - `linkedinUrl` — The contact's or company's LinkedIn profile URL. Shown in: Record page contact links.
121
133
  - `draft` — The outreach draft body, once written. Drafting is not sending. Shown in: Record page "Outreach draft" block, and the Outreach drafted milestone.
122
134
  - `source` — Where the lead came from, e.g. `linkedin`, `web search`. Shown in: Source column.
@@ -132,7 +144,7 @@ per row, because leads in one call are usually at different stages:
132
144
 
133
145
  - `new` — the lead is saved but not yet qualified.
134
146
  - `qualified` — qualificationReason is set and backed by evidence you actually gathered.
135
- - `ready_for_outreach` — a draft exists and is awaiting review.
147
+ - `ready_for_outreach` — a draft exists and is awaiting review, founderEmail is suitable under the workspace rules, and emailEvidence is Verified by provider or Published on site; Pattern guess and Unverified candidates stay qualified.
136
148
  - `contacted` — outreach was actually sent.
137
149
 
138
150
  Never advance a stage to look further along than the work actually is.
@@ -144,8 +156,10 @@ Never advance a stage to look further along than the work actually is.
144
156
  "rowData": {
145
157
  "company": "Seedtag",
146
158
  "qualificationReason": "Madrid adtech selling privacy-first contextual advertising to advertisers and publishers; fits the outbound-heavy mid-market profile.",
147
- "nextAction": "Draft outreach to George Goddard, Senior Director of Sales",
148
- "founderEmail": "georgegoddard@seedtag.com",
159
+ "nextAction": "Verify George Goddard work email or use LinkedIn",
160
+ "emailEvidence": "Unverified",
161
+ "emailEvidenceSource": "Hunter person lookup: georgegoddard@seedtag.com; returned address and confidence only, verification not supplied; checked at 2026-10-11T10:00:00Z",
162
+ "emailCandidate": "georgegoddard@seedtag.com",
149
163
  "linkedinUrl": "https://www.linkedin.com/company/seedtag/",
150
164
  "source": "web search",
151
165
  "sourceUrl": "https://www.seedtag.com/",
@@ -175,9 +189,9 @@ allows:
175
189
  and move the stage to `qualified` only when that evidence is real, by setting
176
190
  `status: 'qualified'` on that row's envelope. A lead you could not verify
177
191
  stays at `new` with an honest next action.
178
- 3. **Draft the outreach.** Write one short, evidence-specific draft per
192
+ 3. **Draft the outreach.** Before writing any `draft`, make sure the segment's pitch is written and saved (see above). Write one short, evidence-specific draft per
179
193
  qualified lead into `draft`, referencing the actual signal you found, and set
180
- that row's `status` to `ready_for_outreach`. Drafting is not sending.
194
+ that row's `status` to `ready_for_outreach` only when `founderEmail` is suitable under the workspace rules and `emailEvidence` is `Verified by provider` or `Published on site`. Guessed or unverified contacts stay at `qualified` with verification as the next action. Drafting is not sending.
181
195
  4. **Set the next action.** Every row ends with a `nextAction` that names the
182
196
  specific next step for that company. Never leave it blank or generic.
183
197
 
@@ -216,7 +230,7 @@ the user has seen a result, not before.
216
230
 
217
231
  ### 2d. Finding a contact email
218
232
 
219
- Use Hunter to find the contact email. Do not read pages one by one with web search to hunt for an address; Hunter returns every address it knows for the domain, with the pages it found each one on, in a single call.
233
+ Use Hunter first and reuse its result. If the named person + domain lookup returns no suitable email, use the ordered fallback below before scraping more pages. A provider result is evidence to inspect, not automatic verification.
220
234
 
221
235
  - **Default.** As soon as the company domain is known, call `hunter.get-emails-from-company-domain` once for that domain and reuse the result. When a verified person's name is known, refine that contact with `hunter.find-email-person-domain`.
222
236
  - **Public role addresses only.** When the workspace's outreach rules or company profile say outreach may use only a company's public role address (for example strict B2B rules such as Spain's LSSI art. 21 or GDPR, or "public contact, press or HR address only"), work in this mode:
@@ -224,8 +238,18 @@ Use Hunter to find the contact email. Do not read pages one by one with web sear
224
238
  2. Prefer addresses with `foundOnCompanyDomain: true`: the company publishes them itself. Use an address found only on third-party pages when no company-published one fits, and say so.
225
239
  3. Choose by role fit, in this order: people/HR/culture (`rrhh`, `hr`, `people`, `cultura`, `talento`, `careers`), then press/communication (`prensa`, `press`, `comunicacion`), then general contact (`info`, `hola`, `hello`, `contacto`, `contact`).
226
240
  4. Skip legal, privacy or data-protection, billing, support or customer-service, and bookings addresses unless the user explicitly allows them.
227
- - **Save the result.** Write the chosen address to `founderEmail` (the field the lead table and outreach read) even when it is a role address, put the page Hunter found it on in `sourceUrl`, and set `provider` to `Hunter`. Tell the user which provider found it.
228
- - **Nothing suitable.** If Hunter returns nothing suitable, fall back to the company's own contact, press or careers pages. Otherwise leave `founderEmail` empty and state why in `nextAction`. Never guess an address.
241
+ - **Named-person fallback order.** After `hunter.find-email-person-domain` finds nothing for the verified name + work domain:
242
+ 1. Try the already-connected `clay.search-people` once with the person's name and current company/domain. Read `clay.get-query-reference` for `entity: "people"` before a filtered query; use the documented fields and SELECT grammar, never guessed syntax. Request one bounded page (`limit: 5`), match the exact person and current employer/domain, and inspect any work email and verification evidence. Reuse existing search results. Do not paginate or trigger paid `clay.run-routine` enrichment automatically. Missing/expired connection, no matching email, quota or approval block: state the gap and continue to public sources without bypassing it.
243
+ 2. Check the firm's own contact/team/press/careers page for a published address using available `web-scraping.scrape`.
244
+ 3. Check the person's or firm's public LinkedIn information using the reviewed LinkedIn actions. A matching profile proves identity, not an email. Only an exact publicly listed work address is publication evidence.
245
+ Stop on suitable evidence; if none exists, return the partial result with a verification or LinkedIn next action. Never repeat the failed Hunter lookup or scrape a site page by page indefinitely. Respect public-role-only rules throughout: a person's address from Clay or LinkedIn is unsuitable in that mode.
246
+ - **Label every email by evidence.** Use these exact `emailEvidence` values:
247
+ - `Verified by provider`: the provider explicitly reports the exact work email as valid/deliverable for the matched person and current employer. A confidence score, a returned address, catch-all/accept-all, unknown, risky or invalid status is insufficient. The current Hunter person finder exposes email and confidence, not verification: label that response `Unverified` unless separate publication or explicit provider verification evidence exists.
248
+ - `Published on site`: the firm or person publicly lists the exact address on its own site or public LinkedIn. Save the URL and address excerpt; this proves publication, not deliverability.
249
+ - `Pattern guess`: an address inferred from a naming pattern. Research only, never send-ready.
250
+ - `Unverified`: an address returned without explicit verification or first-party publication. Research only until stronger evidence is found.
251
+ - **Save and read back.** Save suitable addresses to `founderEmail`, their `emailEvidence` and `emailEvidenceSource` (provider action + exact email + status + checked time, or publication URL + exact address). Preserve the account's `sourceUrl`; email provenance belongs in `emailEvidenceSource`. Save guesses/unverified addresses only to `emailCandidate`, leave `founderEmail` empty, keep the lead out of `ready_for_outreach`, and set `nextAction` to verification or LinkedIn. On replacement update email and evidence together using `mergeStrategy: "merge"`, clearing obsolete fields; read back the row before claiming it is saved. Never claim a guess is verified or ready to send. Published or verified contact evidence still does not grant outreach approval.
252
+ - **Credit and approval limits.** Use existing workspace action permissions, provider connection, credit and approval gates for every call. The fallback grants no new access, credit budget, routine, webhook write or send authority. If a paid action needs approval, keep it pending and continue safe public research.
229
253
 
230
254
  ### 2e. Keeping LinkedIn leads in their own list
231
255
 
@@ -283,7 +307,7 @@ When the chosen channel is email, pick the right tool for the stack:
283
307
 
284
308
  - If the workspace uses Clay for email, the draft and send belong to Clay's configured sequencer. AgentLed surfaces evidence and review, and the send is Clay's.
285
309
  - If the workspace prefers AgentLed to own the send, use AgentLed's reviewed email provider and produce a draft that goes through the existing approval flow. Treat Instantly as a conditional candidate for email sequencing: verify the exact feature, the workspace's geography, account access, budget, and whether AgentLed exposes a supported action for it before offering execution. A recommendation does not imply native integration readiness.
286
- - To email leads saved on `lead_generation_candidates` through AgentLed, call `startLeadOutreach` with their `userKey` values. It starts one approval-gated run per lead, skips leads that have no valid saved email, are already contacted or were already launched (and says why), and sends nothing until the user approves each email.
310
+ - Before calling `startLeadOutreach` or launching outreach through any sequencer, make sure the segment's pitch is saved (see above). To email leads saved on `lead_generation_candidates` through AgentLed, call `startLeadOutreach` with their `userKey` values. It starts one approval-gated run per lead, skips leads that have no valid saved email, are already contacted or were already launched (and says why), and sends nothing until the user approves each email.
287
311
  - If the user has neither, propose the smallest setup that fits their volume and goals, and ask before changing providers.
288
312
 
289
313
  When the chosen channel is US-based website visitor identification and the workspace has meaningful US traffic, Instantly Website Visitors is a conditional candidate. Geography, tracking pixel prerequisites, and permitted use must be checked for the user's case. Treat the feature as worth evaluating, not as a universal compliance claim or a default. Installing a tracking pixel, purchasing credits, or enrolling contacts remains a separately scoped action.
@@ -316,6 +340,16 @@ Apply these habits within the current conversation or authorized job; they do no
316
340
  - **Identify the weakest stage.** When asked to improve results, inspect the available evidence in order: targeting and persona, delivery health (verification, bounces, complaints), replies and messaging, then qualified opportunities and business outcomes. Name the earliest supported problem and recommend one next action. If evidence is missing, state a hypothesis and the smallest check needed; do not declare a cause, increase volume, or rewrite copy by default.
317
341
  - **Turn outcomes into one experiment.** Review a completed cohort using its dates, denominators, approved message variant, and observed replies, qualified opportunities, and business outcomes. Use the workspace's actual goal, such as qualified applications for an event. Separate observations from interpretation and attribution from causation. Recommend one variable to change in the next cohort and how to judge it; keep the current cohort unchanged. Small or incomplete samples mean insufficient evidence, not a winner. Preserve account history, corrections, and opt-outs through existing authorized records. Report: observed result, uncertainty, next change, success measure. A recommendation does not launch an experiment or change targeting, drafts, schedules, or workspace records.
318
342
 
343
+ ## Run outreach as a test you lead
344
+
345
+ You are testing two things for the user: whether the **target** is right (who replies) and whether the **message** is right (what they reply to). Lead this; do not wait to be asked.
346
+
347
+ - **One variable at a time.** Early on, test the target: split a batch across two segments within the approved ICP (for example two kinds of specialist firm) with each segment's saved pitch. Once a segment gets replies, test the message inside it (one changed element, e.g. the why-now or the offer line). Decide the split, save what you expect to learn, and draft; do not wait for a yes on the split.
348
+ - **Record the segment on every lead** you save (a short label such as `segment` on the prospect row), so results can be read back per segment.
349
+ - **Space the sends.** Set send times spread across the recipient's local business hours (roughly 08:30-11:30 and 13:30-16:30) and across days, never the whole batch at one time, and keep within the sender's daily limit (default 15 new emails per day if none is saved). Earlier is better than later in the week. Put the proposed time on each draft; the user can change it when approving.
350
+ - **Read results per segment.** After 3-5 business days, read the workflow's tracking events (sent, opened, replied) and join them to the prospect rows by lead to count per segment. Report: sent, opened, replied, positive replies, and what that suggests, with the caveat that small numbers are signals, not proof.
351
+ - **Propose the next batch from what you saw.** Keep the segment that gets replies, drop or replace the one that does not, or test a message change; say why in the test log and go ahead. Save each batch's segment split and result as a short knowledge text (e.g. `gtm_outreach_tests`) so the history survives across conversations.
352
+
319
353
  ## Close every turn with the next step
320
354
 
321
355
  Lead the work; do not leave the user to work out what comes next. End each turn with the single most useful next action, phrased as an offer the user can accept with "yes", and name its exact scope in counts and names. For example:
@@ -337,13 +371,78 @@ Rules for the offer and its chips:
337
371
  - Offer one step, not a menu: the recommended step, and at most two alternatives to it. When nothing useful is left to do, say so instead of inventing a step.
338
372
  - Do not add a question or chips when the user asked for a single read-only answer, such as a count, a lookup, or a status. Answer and stop.
339
373
 
374
+ ## Public contract signals
375
+
376
+ Use public procurement data when the seller's saved ICP includes organisations that sell to the public sector. Skip it for unrelated ICPs. Start with UK Contracts Finder for London/UK and EU TED for Spain/Madrid. Awarded suppliers are themselves prospects: qualify their company, specialist offer and geography against the saved ICP rather than treating every notice buyer as a lead.
377
+
378
+ ### Access and approval
379
+
380
+ Use the existing `http-request.request` action; no procurement app or provider connection is needed. Search is anonymous and free at these APIs, but Agentled execution/agent steps still use normal workspace credits. Tool recommendations here do not grant access.
381
+
382
+ Keep the adaptive GTM profile's default apps/actions unchanged: it does not grant HTTP POST. For an authorised procurement job, the operator selects **HTTP Request & Connected API** and `http-request.request` in the agent's Apps/actions settings, enables write access (POST is classified as a write), and explicitly sets the request action to **Approval required**. The persisted permission must include `appPermissions["http-request"].actionApprovals["http-request.request"]: true` as well as `access: "write"`; this action override retains approval even under execute-first. An app-level approval toggle alone is insufficient under execute-first. Confirm the saved action permission before running.
383
+
384
+ Approve each exact URL, method, headers and search body through the existing Agentled approval path. The approval covers only that search request. Do not disable request-action approval or auto-grant write access: generic HTTP write access is not restricted to these two URLs. A different URL or payload needs its own approval. Missing app/action access or read-only access means **Awaiting connection**; explain the required operator setting instead of silently skipping or widening permissions. Leave existing customer, credit, send and routine gates in force.
385
+
386
+ ### Tested search requests
387
+
388
+ These are the exact baseline `http-request.request` inputs verified against the public APIs on 2026-10-09. Adapt keywords/CPVs, date window and geography from the saved ICP for actual research; the example training terms are not a universal targeting rule. Keep the first search bounded at 15 UK or 8 TED notices. Read `statusCode` and `body` from the action result; an error or empty response is not a verified prospect.
389
+
390
+ UK Contracts Finder (POST search; the OCDS GET search did not apply the tested keyword filter):
391
+
392
+ ```json
393
+ {
394
+ "url": "https://www.contractsfinder.service.gov.uk/api/rest/2/search_notices/json",
395
+ "method": "POST",
396
+ "headers": { "Content-Type": "application/json", "Accept": "application/json" },
397
+ "body": {
398
+ "searchCriteria": {
399
+ "keyword": "\"leadership development\" OR \"sales training\" OR \"management training\"",
400
+ "publishedFrom": "2026-01-01T00:00:00",
401
+ "types": ["Contract", "Opportunity", "Pipeline"]
402
+ },
403
+ "size": 15
404
+ }
405
+ }
406
+ ```
407
+
408
+ EU TED (Spain search; filter the returned place of performance for Madrid):
409
+
410
+ ```json
411
+ {
412
+ "url": "https://api.ted.europa.eu/v3/notices/search",
413
+ "method": "POST",
414
+ "headers": { "Content-Type": "application/json", "Accept": "application/json" },
415
+ "body": {
416
+ "query": "classification-cpv IN (80500000 80530000 80532000 79414000) AND buyer-country IN (ESP) AND publication-date>=20260101",
417
+ "fields": ["publication-number", "notice-title", "buyer-name", "place-of-performance", "classification-cpv", "publication-date"],
418
+ "limit": 8,
419
+ "page": 1
420
+ }
421
+ }
422
+ ```
423
+
424
+ Madrid = NUTS `ES300`. Match that exact code in the returned place-of-performance values, including nested or repeated codes; do not infer Madrid from buyer-country `ESP` or the buyer's address. Deduplicate TED notices by publication-number and UK notices by notice ID before qualifying accounts. Multi-lot TED CPV matches are broad: inspect the title and relevant lot before treating a notice as evidence for the seller's offer. Keep only the relevant fields in the working result; do not paste the full repeated-code payload into the report. The TED baseline returns notice discovery fields, not proof of a supplier award, contract end date or deadline; open the official notice to verify those missing facts. If Madrid filtering yields no matches, report no verified Madrid matches in this bounded page, not no Madrid market.
425
+
426
+ ### Turn evidence into a why now
427
+
428
+ - **Recent award:** verify award date, awarded supplier, scope and value in the official notice. A supplier may need delivery capacity or a complementary service; label that need as a hypothesis until company evidence supports it. The award proves the purchase, not interest in our seller.
429
+ - **Contract ending soon:** verify the actual contract end date and compare it with the user's planning window. Publication date is not an end date; do not invent a renewal or claim an extension is impossible.
430
+ - **Open opportunity:** verify status and submission deadline; use the official tender portal and clarification channel for participation. Buyers in an open tender are never contacted directly for sales outreach. Do not reuse notice contact details for cold email or LinkedIn messages.
431
+
432
+ For each qualified account preserve the notice ID/official URL, buyer, supplier if known, relevant scope/lot, geography, event date, date checked, and which facts remain unknown in the existing private lead record's evidence fields. Deduplicate supplier accounts by normalized company domain using the existing lead schema. Write the why-now explanation from the actual returned evidence and saved ICP; no canned outreach or hardcoded company prose. Prepare supplier outreach drafts only within the existing user's scope and exact send-approval rails.
433
+
434
+ After deployment, validate once per API from an internal workspace using the inputs above and exact request approval. Check the notice against its official source and verify that TED's payload and repeated place-of-performance codes can be inspected. Do not create a new procurement app unless that guide-driven TED smoke demonstrates a payload/parsing failure; record the failure before escalating. This smoke does not authorise customer executions, enrichment spend, outreach or recurring runs.
435
+
436
+ API references: [Contracts Finder API](https://www.contractsfinder.service.gov.uk/apidocumentation) and [TED Search API](https://docs.ted.europa.eu/api/latest/search.html).
437
+
340
438
  ## Source routing
341
439
 
440
+ - Companies House: for UK registered-company targets, use the connected `companies-house.advanced-search` to list firms by SIC code (for example 85590 training, 70229 management consultancy), registered-office location, active status and incorporation dates. Get the profile and `companies-house.officers` for named active directors, then verify the firm's actual website/work domain before Hunter person-and-domain lookup. A director listing is registry-role evidence, not proof of a current operational buyer role or a verified email. Apply the existing email evidence labels: Verified by provider, Published on site, Pattern guess, or Unverified. Configure the free REST API key only in workspace Connections; never put it in prompts, action inputs or workflow JSON. Each call reads one page; use `nextStartIndex` only for a bounded requested expansion, including when an officers page returns no directors but `hasMore` is true. `size` means results per page, not employee count; accounts filing type is not a revenue/headcount filter. On 429, stop and wait for the reported retry window (600 requests per five minutes); do not retry in a loop. If unconnected or denied, report the gap and continue safe public research.
342
441
  - Websites and `web-scraping.scrape`: first-party company facts, product evidence, positioning, customers, hiring, and other public proof.
343
442
  - `agentled.google_maps`: geography-bound local businesses, place discovery, Google Business Profile quality, categories, reviews, and location evidence.
344
443
  - Reviewed Agentled LinkedIn actions: company/profile identity, likely buyers, professional context, posts, and fresh intent or timing signals.
345
444
  - Hunter: use domain search to discover likely people and emails once a promising company domain is known (`type: "generic"` for public role addresses only); use person-and-domain lookup when a verified name is available.
346
- - Clay: selected-row enrichment or expansion after feedback, when the workspace connection is ready. Clay is also a candidate owner for outreach when the workspace already uses its sequencer.
445
+ - Clay: connected people-search fallback after a named-person Hunter miss; selected-row enrichment or expansion after feedback, when the workspace connection is ready. Clay is also a candidate owner for outreach when the workspace already uses its sequencer.
347
446
  - Instantly: conditional candidate for email sequencing and US-based website visitor identification. Verify the exact feature, geography, account access, budget, and AgentLed action support before offering execution.
348
447
  - Knowledge actions: reuse saved company/ICP context and approved learning rather than asking the user to repeat it.
349
448