@amdahl/cli 0.3.7 → 0.4.0
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/README.md +236 -8
- package/dist/amdahl.js +1677 -588
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# @amdahl/cli
|
|
2
2
|
|
|
3
3
|
The `amdahl` command line. It signs you in with your console account, checks
|
|
4
|
-
that a workspace can optimize, rewrites messages
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
that a workspace can optimize, rewrites messages one at a time or a whole
|
|
5
|
+
list at once, answers questions about your customers, calls and deals, shows
|
|
6
|
+
and adds connected sources, records what happened to a message after you
|
|
7
|
+
sent it, manages API keys (each one approved in the console), points MCP
|
|
8
|
+
clients at Amdahl, and installs skills from the library at
|
|
9
|
+
https://amdahl.ai/skills.
|
|
7
10
|
|
|
8
11
|
## Using the Claude or ChatGPT app? You do not need this CLI
|
|
9
12
|
|
|
@@ -40,8 +43,10 @@ Full steps: https://amdahl.ai/connect
|
|
|
40
43
|
|
|
41
44
|
## Install
|
|
42
45
|
|
|
43
|
-
Needs Node.js
|
|
44
|
-
|
|
46
|
+
Needs Node.js 22 or later. Node.js 20 reached end of life in April 2026 and
|
|
47
|
+
gets no security fixes. `amdahl` still starts on it, but npm warns when it
|
|
48
|
+
installs. On a Node older than 20, `amdahl` stops before it does anything,
|
|
49
|
+
names the version it found, and links the Node.js download page.
|
|
45
50
|
|
|
46
51
|
```sh
|
|
47
52
|
# Run once, with no install
|
|
@@ -203,6 +208,18 @@ If not: quit and reopen Claude Code, type /mcp, pick amdahl, sign in.
|
|
|
203
208
|
Want to try it here instead? Run: npx -y amdahl optimize
|
|
204
209
|
```
|
|
205
210
|
|
|
211
|
+
If you are already signed in here (a saved `amdahl login` for this API host,
|
|
212
|
+
or a key in `--api-key` or the environment), the last line is replaced by
|
|
213
|
+
what to do next in this terminal:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
Try it here: amdahl optimize or amdahl search "your question"
|
|
217
|
+
Add data: amdahl connect, see it all: amdahl open
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
It still reads nothing from the network. An agent's run and a run with no
|
|
221
|
+
terminal print exactly what they did before.
|
|
222
|
+
|
|
206
223
|
An old copy of the Amdahl skill is brought up to date on the way. A tool it
|
|
207
224
|
finds that does not point at Amdahl yet brings the menu back.
|
|
208
225
|
`npx -y amdahl --verbose` also prints the files it wrote, the profile and
|
|
@@ -302,6 +319,13 @@ amdahl login # sign in through the browser with your console acc
|
|
|
302
319
|
amdahl whoami # the account, workspace and role you are signed in as
|
|
303
320
|
amdahl status # can this workspace optimize, and what blocks it
|
|
304
321
|
amdahl optimize draft.md # rewrite one message (or pipe it in with -, or run it bare and paste)
|
|
322
|
+
amdahl optimize --list drafts.csv # rewrite a whole list in one batch
|
|
323
|
+
amdahl search "what objections came up in lost deals?" # ask about your customers
|
|
324
|
+
amdahl connections # what is connected, and whether it is healthy
|
|
325
|
+
amdahl connect hubspot # open the console's add page, to add a CRM or call recorder
|
|
326
|
+
amdahl open # open this workspace in the console
|
|
327
|
+
amdahl feedback <run-id> --evidence did_it_myself --outcome used # what happened to it
|
|
328
|
+
amdahl sent <run-id> --provider gmail --channel email --sent-as returned --provider-send-id "<msg-id@mail>" # it went out
|
|
305
329
|
amdahl install claude-code # connect an AI client and add the Amdahl skill (also codex, cursor)
|
|
306
330
|
amdahl skills add <publisher>/<skill> # add a skill from amdahl.ai/skills to this project
|
|
307
331
|
```
|
|
@@ -340,6 +364,18 @@ amdahl auth token
|
|
|
340
364
|
amdahl status
|
|
341
365
|
amdahl optimize [<file>... | -] [--channel email|linkedin] [--evidence off|workspace]
|
|
342
366
|
[--on-unsupported flag|remove] [--tries] [--context <file.json>]
|
|
367
|
+
amdahl optimize --list <file.csv|file.jsonl> [--no-wait] [--batch <id>] [--force] [the optimize flags]
|
|
368
|
+
amdahl search "<question>" [--research] [--limit <n>]
|
|
369
|
+
amdahl connections [--all]
|
|
370
|
+
amdahl connect [<connector>] [--no-browser]
|
|
371
|
+
amdahl open [--no-browser]
|
|
372
|
+
amdahl feedback <run-id> --evidence did_it_myself|reported_to_me|inferred
|
|
373
|
+
[--outcome used|used_with_edits|not_used|unsure] [--sent-text <file>|-] [--comment <text>]
|
|
374
|
+
amdahl sent <run-id> --provider <provider> --channel <channel> --sent-as returned|edited
|
|
375
|
+
(--provider-send-id <id> | --recipient <email|url> | --recipient-key-hash <sha256>)
|
|
376
|
+
[--sent-at <time>] [--provider-campaign-id <id>] [--sequence-step <n>]
|
|
377
|
+
[--provider-variant-id <id>] [--provider-lead-id <id>] [--thread-id <id>]
|
|
378
|
+
[--sent-text <file>|-]
|
|
343
379
|
amdahl keys create --name <name> [--preset read-only|agent|internal|admin] [--expires 30d|90d|365d] [--no-browser]
|
|
344
380
|
amdahl keys list
|
|
345
381
|
amdahl keys revoke <id|prefix> [--yes] [--no-browser]
|
|
@@ -353,6 +389,198 @@ Global flags: `--profile`, `--api-url`, `--api-key`, `--json`, `--no-color`,
|
|
|
353
389
|
stderr. An unknown option prints `Unknown option --foo.` and `Run \`amdahl
|
|
354
390
|
--help\`.` (exit 2).
|
|
355
391
|
|
|
392
|
+
## Search
|
|
393
|
+
|
|
394
|
+
```sh
|
|
395
|
+
amdahl search "What objections came up in lost deals last quarter?"
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
`search` asks one question about the workspace's customers, calls and deals
|
|
399
|
+
(`POST /search/query`, with `answer: true`). It prints a short answer, with
|
|
400
|
+
each citation said in plain words, and the rows it came from under `From:`,
|
|
401
|
+
at most five. With no written answer it prints up to ten rows. Each row is
|
|
402
|
+
one line (its title, who and when) and up to three lines of its text, in 80
|
|
403
|
+
columns. `--limit <n>` asks for at most `n` rows, and `--json` prints the
|
|
404
|
+
server's whole answer, every row included.
|
|
405
|
+
|
|
406
|
+
Research is something search starts, never a command of its own. Search
|
|
407
|
+
hands a statistical or long question to a research job by itself, and
|
|
408
|
+
`--research` asks it to (`route: "research"`). The CLI then waits for the
|
|
409
|
+
job (`GET /research/:id`, 45 seconds a read, up to 15 minutes) and prints its
|
|
410
|
+
cited answer, then what the answer rests on under `Details:` (its
|
|
411
|
+
`content_blocks`, in the order the job presented them), then up to three
|
|
412
|
+
questions to ask next.
|
|
413
|
+
|
|
414
|
+
Each table prints as a plain ASCII table that fits 80 columns: a long cell
|
|
415
|
+
wraps (a column is narrowed to its longest word first, so an id or a timestamp
|
|
416
|
+
stays whole), a cell past four lines is cut with `...`, a word wider than its
|
|
417
|
+
column is split with a `-`, and a table with more columns than 80 columns hold
|
|
418
|
+
prints each row as `label: value` lines, so no column is dropped. A table
|
|
419
|
+
prints at most 25 rows and counts the rest. Text, callout, citation, metric and
|
|
420
|
+
theme blocks print as plain text (an `<unverified>` figure is marked
|
|
421
|
+
`(unverified)`). A chart prints one line that says so, and so does any block
|
|
422
|
+
type this version does not know: both point to `--json`, where the whole block
|
|
423
|
+
is. Starting research needs
|
|
424
|
+
`conversations:write` and reading it back `conversations:read`. A CLI
|
|
425
|
+
sign-in has neither, so the server runs the search instead and the CLI adds
|
|
426
|
+
one line:
|
|
427
|
+
|
|
428
|
+
```
|
|
429
|
+
A deeper answer needs a Customer agent key: amdahl keys create --name research --preset agent
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
A workspace with nothing connected answers with `setup_needed`: the CLI
|
|
433
|
+
prints its message, which carries the console link, then
|
|
434
|
+
`Connect your CRM or call recorder: amdahl connect`. With no rows, it prints
|
|
435
|
+
the server's one line on how fresh the data is, or `Nothing matched.`
|
|
436
|
+
|
|
437
|
+
## Connections
|
|
438
|
+
|
|
439
|
+
```sh
|
|
440
|
+
amdahl connections
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
HubSpot crm healthy synced 2026-11-11
|
|
445
|
+
Gong (Sales calls) calls needs sign-in never synced
|
|
446
|
+
Sign in to it again: https://console.amdahl.ai/acme/connections/c1
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`connections` lists what the workspace has connected (`GET /connections`),
|
|
450
|
+
each with its health in words and its last sync. Under the list, one line
|
|
451
|
+
says where to fix what needs attention: the one connection's console page,
|
|
452
|
+
or the Connections page when there are several. `--all` also lists
|
|
453
|
+
disconnected and never-synced sources. With nothing connected it says so and
|
|
454
|
+
names `amdahl connect`.
|
|
455
|
+
|
|
456
|
+
`amdahl connect hubspot` checks the connector against the catalog
|
|
457
|
+
(`GET /connections/catalog`; a type or a name, in any case), then opens the
|
|
458
|
+
console's add page,
|
|
459
|
+
`<console>/<workspace>/settings/connections?add=1&connector=hubspot`. The
|
|
460
|
+
`connector` only fills the search box on that page: you pick HubSpot there and
|
|
461
|
+
sign in to it. With no connector it opens the add page with an empty search
|
|
462
|
+
box. The CLI never creates a connection itself. An unknown connector exits 2
|
|
463
|
+
and lists the ones you can connect; one that is not offered yet exits 1 and
|
|
464
|
+
says it is coming soon. It opens the browser only for a person at a terminal:
|
|
465
|
+
stdin and stdout are terminals, `AMDAHL_NO_PROMPT=1` is not set, no agent runs
|
|
466
|
+
it (`CLAUDECODE`, `CURSOR_AGENT`), it is not CI and there is no `--json`. So
|
|
467
|
+
`amdahl connect hubspot | cat` opens nothing. Everywhere else, with
|
|
468
|
+
`--no-browser`, or when the browser does not open, it prints the link on
|
|
469
|
+
stdout instead (under `--json`, as `url` with `opened: false`).
|
|
470
|
+
|
|
471
|
+
`amdahl open` opens this workspace in the console (the console home when you
|
|
472
|
+
are not signed in), on the same terms. `--no-browser` prints the link.
|
|
473
|
+
|
|
474
|
+
## Optimize a list
|
|
475
|
+
|
|
476
|
+
```sh
|
|
477
|
+
amdahl optimize --list drafts.csv
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
```
|
|
481
|
+
Queued 40 messages as batch 7c1e....
|
|
482
|
+
Ctrl+C stops waiting, not the batch. To pick it up later: amdahl optimize --list drafts.csv --batch 7c1e...
|
|
483
|
+
12 of 40 done, about 3 min left
|
|
484
|
+
40 of 40 messages optimized.
|
|
485
|
+
Results: drafts.optimized.csv
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
`--list` sends a whole list as one batch (`POST /messages/optimize/batch`),
|
|
489
|
+
which the server runs on spare capacity and never refuses as busy, then
|
|
490
|
+
reads it back (`GET /messages/optimize/batches/:id`) until it completes. A
|
|
491
|
+
file given without `--list` is still one message, as before.
|
|
492
|
+
|
|
493
|
+
The list is a CSV file with a header row, or a JSONL file (`.jsonl` or
|
|
494
|
+
`.ndjson`) with one batch item, a JSON object, per line. A CSV has a
|
|
495
|
+
`message` column and may have `item_id`, `channel`, `evidence`,
|
|
496
|
+
`on_unsupported`, `facts` and `rules`; facts and rules take one per line
|
|
497
|
+
inside the cell. Any other column is refused by name before anything is
|
|
498
|
+
sent, so a misspelled column is never dropped without a word (use JSONL for
|
|
499
|
+
any other field a single optimize takes). The optimize flags (`--channel`,
|
|
500
|
+
`--evidence`, `--on-unsupported`, `--tries`, `--context`) apply to every
|
|
501
|
+
item that does not set its own; a row's facts and a `--context` file's rules
|
|
502
|
+
and voice examples are both sent.
|
|
503
|
+
|
|
504
|
+
The whole file is read and checked first. A header the CLI does not read, or a
|
|
505
|
+
missing `message` column, says which headers it expects. Progress goes to
|
|
506
|
+
stderr, in place at a terminal. When the batch completes, the results go next
|
|
507
|
+
to the list: `drafts.csv` gets `drafts.optimized.csv` (every input column,
|
|
508
|
+
then `optimized_message`, `status`, `what_changed`, `run_id` and `error`), and
|
|
509
|
+
`x.jsonl` gets `x.optimized.jsonl` (one batch item per line, its `result`
|
|
510
|
+
what a single optimize returns). With `--json`, the batch and every item go
|
|
511
|
+
to stdout and no file is written. A failed item exits 1. A refused list
|
|
512
|
+
names the line of the first item the server refused.
|
|
513
|
+
|
|
514
|
+
A spreadsheet runs a cell that starts with `=`, `+`, `-` or `@` as a formula,
|
|
515
|
+
so in the results CSV such a cell (and one that starts with a tab or a
|
|
516
|
+
carriage return) starts with a `'`. The CLI does not replace a results file
|
|
517
|
+
that already exists: it exits 2 before it queues anything, and `--force`
|
|
518
|
+
replaces the file.
|
|
519
|
+
|
|
520
|
+
`--no-wait` queues the batch, prints its id and the command that picks it up,
|
|
521
|
+
and exits. `--batch <id>` picks up a batch queued earlier; with `--list`, the
|
|
522
|
+
results go next to that list and the list must have as many messages as the
|
|
523
|
+
batch has items (exit 2 otherwise), otherwise they go to `<id>.optimized.jsonl`
|
|
524
|
+
here. `--no-wait` with `--batch` exits 2: it only queues a new list.
|
|
525
|
+
|
|
526
|
+
## After you send
|
|
527
|
+
|
|
528
|
+
```sh
|
|
529
|
+
amdahl feedback <run-id> --evidence did_it_myself --outcome used_with_edits --sent-text sent.txt
|
|
530
|
+
amdahl sent <run-id> --provider gmail --channel email --sent-as edited --provider-send-id "<msg-id@mail.gmail.com>"
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
`feedback` says what happened to the message one optimize run returned
|
|
534
|
+
(`POST /messages/optimize/runs/:id/feedback`). `--evidence` is required:
|
|
535
|
+
`did_it_myself`, `reported_to_me` or `inferred`. Send at least one of
|
|
536
|
+
`--outcome` (`used`, `used_with_edits`, `not_used`, `unsure`), `--comment`
|
|
537
|
+
(the sender's own words) and `--sent-text` (a file with the text as sent, or
|
|
538
|
+
`-` for stdin). Amdahl learns the sender's preferences from an edit, unless
|
|
539
|
+
the evidence is `inferred`. Each call stores one event, so running it twice
|
|
540
|
+
stores two.
|
|
541
|
+
|
|
542
|
+
`sent` is for the system that sent the message: it reports that it went out
|
|
543
|
+
(`POST /messages/report_send`). A report from a CLI sign-in is stored as
|
|
544
|
+
`reported_via: cli`. The flags are the report's fields: `--provider`
|
|
545
|
+
(`lemlist`, `instantly`, `outreach`, `salesloft`, `hubspot`, `salesforce`,
|
|
546
|
+
`gmail`, `heyreach`, `apollo`, `linkedin_manual`, `other`), `--channel`
|
|
547
|
+
(`email`, `linkedin_invite`, `linkedin_message`, `linkedin_inmail`),
|
|
548
|
+
`--sent-as` (`returned` or `edited`) and `--sent-at` (a time with a time
|
|
549
|
+
zone; the current time when left out), then the optional ids.
|
|
550
|
+
|
|
551
|
+
The server stores a report only when it can tell which send it is, so one of
|
|
552
|
+
`--provider-send-id`, `--recipient` (an email address, or a LinkedIn profile
|
|
553
|
+
URL for a LinkedIn channel) or `--recipient-key-hash` (a SHA-256) is required.
|
|
554
|
+
A campaign, a lead and a step are not enough. Without one, the CLI exits 2
|
|
555
|
+
before it sends anything. The id is the provider's own: for gmail, the
|
|
556
|
+
`Message-ID` header with its angle brackets; never an email address (give that
|
|
557
|
+
as `--recipient`; Amdahl stores only a hash of it). The command reports one
|
|
558
|
+
send, so give one run id. To report many at once, call
|
|
559
|
+
`POST /messages/report_send`, which takes up to 100 items. Give `--recipient`
|
|
560
|
+
or `--recipient-key-hash`, not both: the server refuses the pair as
|
|
561
|
+
`invalid_recipient`, so the CLI exits 2 first. `--sent-at` needs an uppercase
|
|
562
|
+
`T` and `Z`, as the server does. The CLI checks each value against the
|
|
563
|
+
server's limits first, and a mistake is a usage error that names the flag. It
|
|
564
|
+
counts a text's length as the server does, in UTF-16 units, so an emoji counts
|
|
565
|
+
as two. A send the server did not store prints why and exits 1.
|
|
566
|
+
|
|
567
|
+
## Next steps
|
|
568
|
+
|
|
569
|
+
Human output names the next step where there is one, in at most two extra
|
|
570
|
+
lines; `--json` never carries them.
|
|
571
|
+
|
|
572
|
+
- `amdahl optimize` on a workspace with no data connected ends with
|
|
573
|
+
`Connect calls or a CRM so Amdahl checks claims against them: amdahl connect`.
|
|
574
|
+
The CLI asks `GET /setup/status` beside the first rewrite, so it adds no
|
|
575
|
+
wait, and says nothing when it cannot tell. Only a person at a terminal
|
|
576
|
+
gets the line and the request (the same test as `optimize` with no file): a
|
|
577
|
+
pipe, an agent, CI, `AMDAHL_NO_PROMPT=1` and `--json` make exactly the
|
|
578
|
+
requests they made before.
|
|
579
|
+
- `amdahl status` gives each blocked item its fix: no data, `amdahl connect`;
|
|
580
|
+
a connection that needs attention, its console page; a used-up quota, the
|
|
581
|
+
day it resets; a role too low, ask a workspace admin.
|
|
582
|
+
- Bare `amdahl`, signed in, with every tool set up: what to try here.
|
|
583
|
+
|
|
356
584
|
## Skills
|
|
357
585
|
|
|
358
586
|
`skills add` installs one skill from the library at https://amdahl.ai/skills.
|
|
@@ -569,10 +797,10 @@ code shown in the terminal; then the key is printed once and stored nowhere.
|
|
|
569
797
|
| code | meaning |
|
|
570
798
|
|---|---|
|
|
571
799
|
| 0 | ok |
|
|
572
|
-
| 1 | general (`login_timeout`, `state_mismatch`, optimize `ok: false`, a `skills add` refusal, `invalid_config`, bare `amdahl` with no terminal that found no client) |
|
|
800
|
+
| 1 | general (`login_timeout`, `state_mismatch`, optimize `ok: false`, a failed item in `optimize --list`, a send `sent` could not store, research that failed or is still running, a `skills add` refusal, `invalid_config`, bare `amdahl` with no terminal that found no client) |
|
|
573
801
|
| 2 | usage (also bare `amdahl` in CI, with `AMDAHL_NO_PROMPT=1` or with `--json`) |
|
|
574
802
|
| 3 | not signed in (401, `invalid_grant`, no credential) |
|
|
575
|
-
| 4 | forbidden (403, `oauth_required`, `cli_client_required`, `not_admin`) |
|
|
803
|
+
| 4 | forbidden (403, `oauth_required`, `cli_client_required`, `not_admin`, `missing_scope`; also research that started but this credential cannot read) |
|
|
576
804
|
| 5 | no workspace |
|
|
577
805
|
| 6 | rate limited or quota (429) |
|
|
578
806
|
| 7 | approval denied, expired or locked out |
|
|
@@ -582,7 +810,7 @@ code shown in the terminal; then the key is printed once and stored nowhere.
|
|
|
582
810
|
|
|
583
811
|
## Development
|
|
584
812
|
|
|
585
|
-
Needs Node.js
|
|
813
|
+
Needs Node.js 22 or later and pnpm 9 (`corepack enable` picks up the version
|
|
586
814
|
pinned in `package.json`).
|
|
587
815
|
|
|
588
816
|
```sh
|