ethos-cli 0.7.6 → 0.7.7

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/dist/bin/ethos.js CHANGED
@@ -7,6 +7,7 @@ import { registerAgents } from "../commands/agents.js";
7
7
  import { registerAuth } from "../commands/auth.js";
8
8
  import { registerCampaigns } from "../commands/campaigns.js";
9
9
  import { registerFlows } from "../commands/flows.js";
10
+ import { registerFindPeople } from "../commands/find-people.js";
10
11
  import { registerGifting } from "../commands/gifting.js";
11
12
  import { registerHooks } from "../commands/hooks.js";
12
13
  import { registerLists } from "../commands/lists.js";
@@ -24,6 +25,7 @@ export function createEthosProgram() {
24
25
  registerAuth(program);
25
26
  registerAgents(program);
26
27
  registerCampaigns(program);
28
+ registerFindPeople(program);
27
29
  registerFlows(program);
28
30
  registerGifting(program);
29
31
  registerHooks(program);
@@ -1 +1 @@
1
- {"version":3,"file":"ethos.js","sourceRoot":"","sources":["../../src/bin/ethos.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAwB,CAAC;AAExF,MAAM,UAAU,kBAAkB;IAChC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,gBAAgB,CACd,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CAAC,8CAA8C,CAAC;SAC3D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CACxB,CAAC;IAEF,YAAY,CAAC,OAAO,CAAC,CAAC;IACtB,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3B,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,eAAe,CAAC,OAAO,CAAC,CAAC;IACzB,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAiB,OAAO,CAAC,IAAI;IACtD,MAAM,kBAAkB,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,kBAAkB,EAAE,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,UAAU,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"ethos.js","sourceRoot":"","sources":["../../src/bin/ethos.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,oBAAoB,CAAwB,CAAC;AAExF,MAAM,UAAU,kBAAkB;IAChC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,gBAAgB,CACd,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CAAC,8CAA8C,CAAC;SAC3D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CACxB,CAAC;IAEF,YAAY,CAAC,OAAO,CAAC,CAAC;IACtB,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3B,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC5B,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,eAAe,CAAC,OAAO,CAAC,CAAC;IACzB,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,aAAa,CAAC,OAAO,CAAC,CAAC;IACvB,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,cAAc,CAAC,OAAO,CAAC,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,OAAiB,OAAO,CAAC,IAAI;IACtD,MAAM,kBAAkB,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,kBAAkB,EAAE,EAAE,CAAC;IACzB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,UAAU,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerFindPeople(program: Command): void;
@@ -0,0 +1,200 @@
1
+ import { inferAppUrl } from "../lib/agent-clients.js";
2
+ import { EthosApiError } from "../lib/client.js";
3
+ import { compactObject, jsonRequest, parsePositiveInteger, pathId, withClient } from "../lib/command-helpers.js";
4
+ import { openInBrowser } from "../lib/open-browser.js";
5
+ import { printResult } from "../lib/output.js";
6
+ const terminalStatuses = new Set([
7
+ "needs_refinement",
8
+ "succeeded",
9
+ "failed",
10
+ "canceled",
11
+ ]);
12
+ const STATUS_REQUEST_TIMEOUT_MS = 15_000;
13
+ export function registerFindPeople(program) {
14
+ const findPeople = program
15
+ .command("find-people")
16
+ .description("Find prospects from a natural-language company and person ICP search");
17
+ const startCommand = findPeople
18
+ .command("start")
19
+ .description("Parse a prospect search and start linked table creation in the background")
20
+ .requiredOption("--query <text>", "natural-language query with both company ICP and person criteria")
21
+ .option("--name <name>", "base name for the generated company and people tables")
22
+ .option("--max-profiles <count>", "maximum profiles allowed before refinement is required", "10000")
23
+ .option("--wait", "wait until the background search reaches a terminal state")
24
+ .option("--timeout <seconds>", "seconds to wait when --wait is set", "1800")
25
+ .option("--poll-interval <seconds>", "seconds between status checks when --wait is set", "3")
26
+ .option("--app-url <url>", "Ethos web app URL for table links")
27
+ .option("--open", "open the people table when the job succeeds");
28
+ startCommand.action(async () => {
29
+ await withClient(startCommand, async (client, config) => {
30
+ const options = startCommand.opts();
31
+ const maxProfiles = parsePositiveInteger(options.maxProfiles, "--max-profiles", 10_000);
32
+ let search;
33
+ try {
34
+ search = await client.request("/v1/prospect-searches", jsonRequest("POST", compactObject({
35
+ query: options.query,
36
+ name: options.name,
37
+ max_profiles: maxProfiles,
38
+ })));
39
+ }
40
+ catch (error) {
41
+ if (emitRichProspectSearchError(config.json, error))
42
+ return;
43
+ throw error;
44
+ }
45
+ if (options.wait) {
46
+ search = await waitForProspectSearch(client, search.id, options);
47
+ }
48
+ const data = prospectSearchCliResponse(search, config.apiUrl, options.appUrl);
49
+ printResult(config, {
50
+ label: prospectSearchLabel(data),
51
+ data,
52
+ });
53
+ if (options.open && data.status === "succeeded" && data.people_table_url) {
54
+ openInBrowser(data.people_table_url);
55
+ }
56
+ });
57
+ });
58
+ const getCommand = findPeople.command("get <search-id>").description("Fetch a prospect search job");
59
+ getCommand.option("--app-url <url>", "Ethos web app URL for table links");
60
+ getCommand.action(async (searchId) => {
61
+ await withClient(getCommand, async (client, config) => {
62
+ const options = getCommand.opts();
63
+ const search = await client.request(`/v1/prospect-searches/${pathId(searchId)}`);
64
+ const data = prospectSearchCliResponse(search, config.apiUrl, options.appUrl);
65
+ printResult(config, {
66
+ label: prospectSearchLabel(data),
67
+ data,
68
+ });
69
+ });
70
+ });
71
+ const waitCommand = findPeople
72
+ .command("wait <search-id>")
73
+ .description("Poll a prospect search until it succeeds, needs refinement, fails, or is canceled")
74
+ .option("--timeout <seconds>", "seconds to wait for completion", "1800")
75
+ .option("--poll-interval <seconds>", "seconds between status checks", "3")
76
+ .option("--app-url <url>", "Ethos web app URL for table links")
77
+ .option("--open", "open the people table when the job succeeds");
78
+ waitCommand.action(async (searchId) => {
79
+ await withClient(waitCommand, async (client, config) => {
80
+ const options = waitCommand.opts();
81
+ const search = await waitForProspectSearch(client, searchId, options);
82
+ const data = prospectSearchCliResponse(search, config.apiUrl, options.appUrl);
83
+ printResult(config, {
84
+ label: prospectSearchLabel(data),
85
+ data,
86
+ });
87
+ if (options.open && data.status === "succeeded" && data.people_table_url) {
88
+ openInBrowser(data.people_table_url);
89
+ }
90
+ });
91
+ });
92
+ const interruptCommand = findPeople
93
+ .command("interrupt <search-id>")
94
+ .description("Cancel a queued or running prospect search job");
95
+ interruptCommand.option("--app-url <url>", "Ethos web app URL for table links");
96
+ interruptCommand.action(async (searchId) => {
97
+ await withClient(interruptCommand, async (client, config) => {
98
+ const options = interruptCommand.opts();
99
+ const search = await client.request(`/v1/prospect-searches/${pathId(searchId)}/interrupt`, {
100
+ method: "POST",
101
+ });
102
+ const data = prospectSearchCliResponse(search, config.apiUrl, options.appUrl);
103
+ printResult(config, {
104
+ label: prospectSearchLabel(data),
105
+ data,
106
+ });
107
+ });
108
+ });
109
+ }
110
+ async function waitForProspectSearch(client, searchId, options) {
111
+ const timeoutSeconds = parseWaitSeconds(options.timeout, "--timeout", 7200);
112
+ const pollIntervalMs = parseWaitSeconds(options.pollInterval, "--poll-interval", 300) * 1000;
113
+ const deadline = Date.now() + timeoutSeconds * 1000;
114
+ let lastSearch;
115
+ for (;;) {
116
+ let search;
117
+ try {
118
+ const requestTimeoutMs = Math.min(STATUS_REQUEST_TIMEOUT_MS, Math.max(1000, deadline - Date.now()));
119
+ search = await fetchProspectSearchStatus(client, searchId, requestTimeoutMs);
120
+ lastSearch = search;
121
+ }
122
+ catch (error) {
123
+ if (!isAbortError(error))
124
+ throw error;
125
+ }
126
+ if (search && terminalStatuses.has(search.status))
127
+ return search;
128
+ if (Date.now() >= deadline) {
129
+ const lastStatus = lastSearch
130
+ ? ` Last status: ${lastSearch.status}${lastSearch.progressMessage ? ` (${lastSearch.progressMessage})` : ""}.`
131
+ : "";
132
+ throw new Error(`Timed out after ${timeoutSeconds}s waiting for prospect search ${searchId}.${lastStatus} ` +
133
+ `Run \`ethos find-people get ${searchId}\` for current status, ` +
134
+ `\`ethos find-people wait ${searchId}\` to keep polling, or ` +
135
+ `\`ethos find-people interrupt ${searchId}\` to cancel.`);
136
+ }
137
+ await new Promise((resolve) => {
138
+ setTimeout(resolve, pollIntervalMs);
139
+ });
140
+ }
141
+ }
142
+ async function fetchProspectSearchStatus(client, searchId, requestTimeoutMs) {
143
+ const controller = new AbortController();
144
+ const timer = setTimeout(() => controller.abort(), requestTimeoutMs);
145
+ try {
146
+ return await client.request(`/v1/prospect-searches/${pathId(searchId)}`, {
147
+ signal: controller.signal,
148
+ });
149
+ }
150
+ finally {
151
+ clearTimeout(timer);
152
+ }
153
+ }
154
+ function prospectSearchCliResponse(search, apiUrl, appUrlOverride) {
155
+ const appUrl = (appUrlOverride || inferAppUrl(apiUrl)).replace(/\/+$/, "");
156
+ return {
157
+ ...search,
158
+ search_id: search.id,
159
+ people_table_id: search.peopleTableId,
160
+ company_table_id: search.companyTableId,
161
+ people_table_url: search.peopleTableId ? `${appUrl}/tables/${search.peopleTableId}` : null,
162
+ company_table_url: search.companyTableId ? `${appUrl}/tables/${search.companyTableId}` : null,
163
+ };
164
+ }
165
+ function prospectSearchLabel(search) {
166
+ if (search.status === "succeeded") {
167
+ return `Prospect search ${search.id} succeeded; people table ${search.people_table_id}`;
168
+ }
169
+ if (search.status === "needs_refinement") {
170
+ return `Prospect search ${search.id} needs refinement (${search.profileCount ?? "unknown"} profiles)`;
171
+ }
172
+ return `Prospect search ${search.id} is ${search.status}`;
173
+ }
174
+ function emitRichProspectSearchError(json, error) {
175
+ if (!(error instanceof EthosApiError) || error.status !== 400 || !isRecord(error.body))
176
+ return false;
177
+ if (!("parsedParams" in error.body) && !("suggestedAction" in error.body))
178
+ return false;
179
+ if (json) {
180
+ process.stdout.write(`${JSON.stringify({ success: false, error: error.body }, null, 2)}\n`);
181
+ return true;
182
+ }
183
+ const message = typeof error.body.message === "string" ? error.body.message : error.message;
184
+ process.stderr.write(`${message}\n${JSON.stringify(error.body, null, 2)}\n`);
185
+ return true;
186
+ }
187
+ function isRecord(value) {
188
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
189
+ }
190
+ function isAbortError(error) {
191
+ return Boolean(error && typeof error === "object" && "name" in error && error.name === "AbortError");
192
+ }
193
+ function parseWaitSeconds(value, name, max) {
194
+ const parsed = Number(value);
195
+ if (!Number.isFinite(parsed) || parsed < 1) {
196
+ throw new Error(`${name} must be a positive number of seconds.`);
197
+ }
198
+ return Math.min(parsed, max);
199
+ }
200
+ //# sourceMappingURL=find-people.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-people.js","sourceRoot":"","sources":["../../src/commands/find-people.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ethos-cli",
3
- "version": "0.7.6",
3
+ "version": "0.7.7",
4
4
  "description": "Commander-based CLI for Ethos table operations",
5
5
  "homepage": "https://github.com/cluster-software/ethos#readme",
6
6
  "repository": {
@@ -0,0 +1,176 @@
1
+ ---
2
+ name: find-people
3
+ description: Find relevant prospects in one shot from a natural-language ICP by using Ethos prospect search to parse company and person criteria, create linked company and people tables in the background, poll for completion, open the resulting people table, and refine or interrupt searches. Use when the user wants to find prospects, buyers, founders, leaders, contacts, or people matching an ICP without starting from an existing company CSV.
4
+ ---
5
+
6
+ # find-people
7
+
8
+ Use this when the user wants Ethos to find prospects from scratch. This skill
9
+ does not require a CSV upload. The production CLI default is
10
+ `https://api.ethos.hello-cluster.com`, so only pass `--api-url` for local
11
+ development or an explicitly requested environment.
12
+
13
+ ## Required CLI
14
+
15
+ The Ethos CLI (`ethos`) is required. If `ethos` is not installed or not on
16
+ `PATH`, install the latest CLI and retry:
17
+
18
+ ```sh
19
+ npm install -g ethos-cli@latest --prefer-online
20
+ ```
21
+
22
+ If a CLI command fails because the CLI is not authenticated, run:
23
+
24
+ ```sh
25
+ ethos auth login --agent-client auto
26
+ ```
27
+
28
+ then retry the failed command. Do not ask for API tokens unless the user
29
+ explicitly wants a non-browser setup.
30
+
31
+ ## Query Shape
32
+
33
+ Create one natural-language query that clearly includes both:
34
+
35
+ - Target companies: industry, geography, size, business model, technology,
36
+ funding/stage, or other ICP constraints.
37
+ - Target people: titles, functions, seniority, job status, and exclusions.
38
+
39
+ Good query:
40
+
41
+ ```text
42
+ Find VP Sales, Head of Revenue, and RevOps leaders at US B2B SaaS companies with 50-500 employees that sell to enterprise finance teams. Exclude agencies and consultants.
43
+ ```
44
+
45
+ Weak query:
46
+
47
+ ```text
48
+ Find sales people.
49
+ ```
50
+
51
+ If the user's request is underspecified, ask up to 3 concise followups before
52
+ starting the search. Prioritize missing dimensions in this order:
53
+
54
+ 1. Who the target people are: titles, functions, seniority.
55
+ 2. Which companies qualify: industry, product category, size, stage, business
56
+ model, or technologies.
57
+ 3. Geography or other hard exclusions.
58
+
59
+ Use an AskUserQuestion tool when available. If not, ask directly in chat. If the
60
+ user wants speed, make reasonable assumptions and include them in the query.
61
+
62
+ ## Start Search
63
+
64
+ Run:
65
+
66
+ ```sh
67
+ ethos find-people start --query "$QUERY" --json
68
+ ```
69
+
70
+ Save `response.search_id`, `response.parsedParams`, `response.status`, and
71
+ `response.progressMessage`.
72
+
73
+ If the command returns `success: false`, inspect `error.suggestedAction` and
74
+ `error.parsedParams`. When `suggestedAction` is not `combinedSearch`, tell the
75
+ user the parser understood only company criteria or only person criteria, then
76
+ rewrite the query so it includes both target companies and target individuals.
77
+
78
+ After a successful start, summarize the parsed params in plain language. Do not
79
+ paste the full JSON unless the user asks for it.
80
+
81
+ ## How To Communicate With The User
82
+
83
+ When a search starts successfully, do not talk about the parser or implementation
84
+ details. Say the search was queued, then describe the criteria in a short,
85
+ easy-to-scan list:
86
+
87
+ ```text
88
+ Ok, I queued up a search with these criteria:
89
+ - People: CFOs, VP Finance, Heads of Finance, Treasurers, and senior project finance leaders.
90
+ - Companies: infrastructure developers and operators in data centers, energy, toll roads, and bridges.
91
+ - Signals: project finance, capital raises, debt/equity funding, and active development projects.
92
+ - Exclusions: banks, funds, consultants, law firms, and EPC-only contractors.
93
+ ```
94
+
95
+ If the CLI response includes `unsupportedFilters`, mention them after the
96
+ criteria as caveats. Explain whether the search used proxy keywords/signals
97
+ instead of a native filter, but keep it short.
98
+
99
+ Always invite adjustment before or while polling:
100
+
101
+ ```text
102
+ If any of that looks off, tell me what to change and I can interrupt or refine
103
+ the search. I’ll poll this one now and send the table link when it’s ready.
104
+ ```
105
+
106
+ When the search succeeds, lead with the result count and table link. If
107
+ `progressMessage` says the table contains only part of the matching set, tell
108
+ the user directly, e.g. "I created a table with the first 1,000 of 5,000
109
+ matching profiles." Include the company table link only if useful or if the user
110
+ asks. Keep parsed params at the plain-English level unless the user asks for raw
111
+ JSON.
112
+
113
+ ## Poll
114
+
115
+ Poll the background table-creation job with status checks that return
116
+ immediately:
117
+
118
+ ```sh
119
+ ethos find-people get "$SEARCH_ID" --json
120
+ ```
121
+
122
+ Use `response.status`, `response.progressMessage`, `response.companyCount`,
123
+ `response.profileCount`, `response.people_table_url`, and
124
+ `response.company_table_url` to understand and explain what is happening. For
125
+ interactive agent work, prefer repeated `get` calls every 10-20 seconds over a
126
+ long-running `wait` command: `wait --json` is silent until the job reaches a
127
+ terminal state, which makes the agent blind while the job is running.
128
+
129
+ The job reaches one of these terminal statuses:
130
+
131
+ - `succeeded`: linked company and people tables were created. Open
132
+ `response.people_table_url` for the user. For valid searches with more than
133
+ 1,000 and up to 10,000 matching profiles, Ethos materializes the first 1,000
134
+ profiles instead of paginating the full result set.
135
+ - `needs_refinement`: more than 10,000 matching profiles were found. Use
136
+ `response.refinementSuggestions` and the parsed params to suggest narrower
137
+ criteria, then ask the user how to refine.
138
+ - `failed`: explain `response.error.message` and retry only after changing the
139
+ query or environment issue.
140
+ - `canceled`: the search was interrupted.
141
+
142
+ While the job is `queued` or `running`, report the latest `progressMessage` when
143
+ it adds useful information. Do not infer or guess phases from a silent command;
144
+ if you need status, run `get` again. Do not start a duplicate search unless the
145
+ user changed the criteria.
146
+
147
+ For non-interactive shell usage, `ethos find-people wait "$SEARCH_ID" --json`
148
+ is still available, but it should not be the default for agent polling.
149
+
150
+ ## Interrupt And Refine
151
+
152
+ If the user changes the search while a job is queued or running, interrupt the
153
+ old job before starting the new one:
154
+
155
+ ```sh
156
+ ethos find-people interrupt "$SEARCH_ID" --json
157
+ ```
158
+
159
+ Then build a revised query and run `ethos find-people start --query "$QUERY"
160
+ --json` again.
161
+
162
+ Fast refinements that can be handled in the table UI include person title,
163
+ seniority, job function, country, company, and company domain. Refinements that
164
+ depend on provider-side filters, such as company size, funding stage,
165
+ technologies, or broad industry expansion, should start a new search.
166
+
167
+ ## Open Result
168
+
169
+ When the search succeeds, open the people table URL from the CLI response:
170
+
171
+ - In Codex, use the in-app Browser when available.
172
+ - In shell clients, `ethos find-people wait "$SEARCH_ID" --open --json` can open
173
+ the table in the default browser.
174
+
175
+ The company table is linked to the people table and available at
176
+ `response.company_table_url`.