@amdahl/cli 0.4.1 → 0.4.9
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 +240 -5
- package/dist/amdahl.js +2758 -1225
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -319,7 +319,13 @@ amdahl whoami # the account, workspace and role you are signed in
|
|
|
319
319
|
amdahl status # can this workspace optimize, and what blocks it
|
|
320
320
|
amdahl optimize draft.md # rewrite one message (or pipe it in with -, or run it bare and paste)
|
|
321
321
|
amdahl optimize --list drafts.csv # rewrite a whole list in one batch
|
|
322
|
+
amdahl optimize --list drafts.csv --for lemlist --channel email # and a CSV lemlist imports
|
|
323
|
+
amdahl grade draft.md # grade a message: a score and the lines behind it
|
|
324
|
+
amdahl prompt prompt.md # grade or improve a reusable prompt by the emails it writes
|
|
322
325
|
amdahl search "what objections came up in lost deals?" # ask about your customers
|
|
326
|
+
amdahl recipes # the console's questions; amdahl search --recipe <id> runs one
|
|
327
|
+
amdahl data # what the workspace holds, and what a search can filter on
|
|
328
|
+
amdahl runs # your latest runs; amdahl run <run-id> opens one
|
|
323
329
|
amdahl connections # what is connected, and whether it is healthy
|
|
324
330
|
amdahl connect hubspot # open the console's add page, to add a CRM or call recorder
|
|
325
331
|
amdahl open # open this workspace in the console
|
|
@@ -363,8 +369,18 @@ amdahl auth token
|
|
|
363
369
|
amdahl status
|
|
364
370
|
amdahl optimize [<file>... | -] [--channel email|linkedin] [--evidence off|workspace]
|
|
365
371
|
[--on-unsupported flag|remove] [--tries] [--context <file.json>]
|
|
366
|
-
amdahl optimize --list <file.csv|file.jsonl> [--no-wait] [--batch <id>] [--force] [the optimize flags]
|
|
372
|
+
amdahl optimize --list <file.csv|file.jsonl> [--no-wait] [--batch <id>] [--force] [--for <tool>] [the optimize flags]
|
|
373
|
+
amdahl grade <file|-> [--channel email|linkedin] [--evidence off|workspace] [--context <file.json>]
|
|
374
|
+
amdahl prompt <file|-> [--mode improve|grade] [--recipients <file.json>] [--channel email|linkedin]
|
|
375
|
+
[--context <file.json>] [--no-wait]
|
|
376
|
+
amdahl prompt --run <id> [--no-wait]
|
|
377
|
+
amdahl runs [--limit <n>]
|
|
378
|
+
amdahl run <run-id>
|
|
379
|
+
amdahl data [--surface interactions|deals|deal_qualification]
|
|
380
|
+
amdahl recipes
|
|
367
381
|
amdahl search "<question>" [--research] [--limit <n>]
|
|
382
|
+
amdahl search --recipe <id> [--account|--products|--messages|--objection <text>]
|
|
383
|
+
amdahl search --research-id <id>
|
|
368
384
|
amdahl connections [--all]
|
|
369
385
|
amdahl connect [<connector>] [--no-browser]
|
|
370
386
|
amdahl open [--no-browser]
|
|
@@ -421,6 +437,35 @@ cited answer, then what the answer rests on under `Details:` (its
|
|
|
421
437
|
`content_blocks`, in the order the job presented them), then up to three
|
|
422
438
|
questions to ask next.
|
|
423
439
|
|
|
440
|
+
When a research job starts, the CLI prints its id (`Research id: ...`) and how
|
|
441
|
+
to read it later. `amdahl search --research-id <id>` reads a job started
|
|
442
|
+
earlier and waits for it, then prints it as `--research` does (with
|
|
443
|
+
`--json`, `{ok, research}`). It needs a key that can read research (a
|
|
444
|
+
Customer agent key); a sign-in gets exit 4 and the line on the key. A job
|
|
445
|
+
that is still running at the end of the wait exits 1 and gives the id again.
|
|
446
|
+
|
|
447
|
+
### Recipes
|
|
448
|
+
|
|
449
|
+
```sh
|
|
450
|
+
amdahl recipes
|
|
451
|
+
amdahl search --recipe account-brief --account "Acme"
|
|
452
|
+
amdahl search --recipe whitespace --products "Analytics, Forecasting"
|
|
453
|
+
amdahl search --recipe stalled-deals
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
`recipes` lists the console's recipe library: the same ids, titles,
|
|
457
|
+
fill-ins and search questions (`src/recipes-data.ts` names the file and commit
|
|
458
|
+
they are copied from). Twelve of the library's recipes run as a search; the
|
|
459
|
+
rest are prompts for an AI client and are in the console. `search --recipe
|
|
460
|
+
<id>` asks a recipe's question with its fill-in in place. A fill-in is a flag
|
|
461
|
+
named for it (`--account`, `--products`, `--messages`, `--objection`); one the
|
|
462
|
+
recipe needs and was not given, or one it has no use for, exits 2 before any
|
|
463
|
+
request. A fill-in is cut at 300 characters, as the console cuts it, and the
|
|
464
|
+
CLI says so. `--research` and `--limit` work with a recipe; a question beside
|
|
465
|
+
`--recipe` is refused. With `--json` the result is the same answer a search
|
|
466
|
+
gives, and `amdahl recipes --json` lists every recipe with its question and
|
|
467
|
+
fill-ins.
|
|
468
|
+
|
|
424
469
|
Each table prints as a plain ASCII table that fits 80 columns: a long cell
|
|
425
470
|
wraps (a column is narrowed to its longest word first, so an id or a timestamp
|
|
426
471
|
stays whole), a cell past four lines is cut with `...`, a word wider than its
|
|
@@ -444,6 +489,115 @@ prints its message, which carries the console link, then
|
|
|
444
489
|
`Connect your CRM or call recorder: amdahl connect`. With no rows, it prints
|
|
445
490
|
the server's one line on how fresh the data is, or `Nothing matched.`
|
|
446
491
|
|
|
492
|
+
## Grade a message
|
|
493
|
+
|
|
494
|
+
```sh
|
|
495
|
+
amdahl grade draft.md --evidence workspace
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
`grade` grades a draft and writes nothing (`POST /messages/optimize` with
|
|
499
|
+
`mode: "grade"`). The file is the message; `-` reads stdin; with no file, at a
|
|
500
|
+
terminal, you paste it. It takes `--channel`, `--evidence` and `--context`;
|
|
501
|
+
`--tries` and `--on-unsupported` belong to a rewrite, which a grade is not,
|
|
502
|
+
so they are unknown options here.
|
|
503
|
+
|
|
504
|
+
```
|
|
505
|
+
Grade 4.2 of 5: 4 of 5 lines passed.
|
|
506
|
+
It meets the bar of 4.2.
|
|
507
|
+
|
|
508
|
+
The lines it rests on:
|
|
509
|
+
pass Relevant positioning
|
|
510
|
+
It names what Corvid shipped.
|
|
511
|
+
...
|
|
512
|
+
fail Differentiation
|
|
513
|
+
It reads like boilerplate.
|
|
514
|
+
|
|
515
|
+
Checked against your calls.
|
|
516
|
+
|
|
517
|
+
This is one reading by claude-sonnet-5-5. It measures the message against the
|
|
518
|
+
rubric and your evidence. It does not predict replies. ...
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
The score is printed as the API returns it, and it always comes with the five
|
|
522
|
+
lines it rests on, each with its verdict and reason. Without
|
|
523
|
+
`--evidence workspace` only the ask is evaluated: the four lines that read your
|
|
524
|
+
customers' calls say "Not evaluated", and the score says it rests on 1 of the 5
|
|
525
|
+
lines. A line that could not be evaluated is not a fail. When no line could be,
|
|
526
|
+
the grade is `Not graded.`, never 0. Every grade says it is one reading and does
|
|
527
|
+
not predict replies. The run id comes last; `amdahl run <id>` opens it. With
|
|
528
|
+
`--json` it prints `{ok, file, result}`: the grade is `.result.grade`.
|
|
529
|
+
|
|
530
|
+
## Grade or improve a prompt
|
|
531
|
+
|
|
532
|
+
```sh
|
|
533
|
+
amdahl prompt prompt.md --recipients recipients.json
|
|
534
|
+
amdahl prompt prompt.md --mode grade
|
|
535
|
+
amdahl prompt --run <id>
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
`prompt` grades or improves a reusable prompt (the instructions a writer
|
|
539
|
+
follows to write an outbound email to any recipient) by the emails it writes
|
|
540
|
+
(`POST /messages/optimize_prompt`, then `GET /messages/optimize_prompt/:id`).
|
|
541
|
+
One message is for `optimize`: a prompt that names one recipient is refused.
|
|
542
|
+
`--mode improve` (the default) revises the prompt and returns it only when the
|
|
543
|
+
revision wrote better email on recipients held out of the revising; `--mode
|
|
544
|
+
grade` writes one email per recipient and grades each. `--recipients` is a
|
|
545
|
+
JSON file of 1 to 6 `{"recipient": {...}}` objects (`name`, `company`, `email`,
|
|
546
|
+
`domain`, `linkedin_url`, `attributes`; also `recipient_notes` and `label`).
|
|
547
|
+
Improve needs two or more. Left out, Amdahl picks up to six of your workspace's
|
|
548
|
+
accounts. `--channel` and `--context` are as in `optimize`.
|
|
549
|
+
|
|
550
|
+
A run takes a few minutes. The command prints the run id at once and waits
|
|
551
|
+
(one read of up to 30 seconds after another, up to 20 minutes); `--no-wait`
|
|
552
|
+
starts it and stops, and `--run <id>` reads it later. The revised prompt, when
|
|
553
|
+
there is one, goes to stdout and the report to stderr, so
|
|
554
|
+
`amdahl prompt p.md > better.md` saves the prompt. The report gives the
|
|
555
|
+
prompt's grade, the emails it wrote that the grade rests on, and a lift only
|
|
556
|
+
when it is reportable (otherwise why not: for example fewer than 3 held-out
|
|
557
|
+
emails on a side). Without a reportable lift it prints the original's mean
|
|
558
|
+
alone and says a revision was kept: the revised and the original means are set
|
|
559
|
+
against each other only when the lift is reportable. The emails that trained the revision are not lift and are
|
|
560
|
+
in `--json`. A grade is one reading and does not predict replies; a mean of
|
|
561
|
+
null is "not graded". Exit 1 when the run failed or is still going. With `--json`
|
|
562
|
+
it prints `{ok, file, started, result}`.
|
|
563
|
+
|
|
564
|
+
## Your runs
|
|
565
|
+
|
|
566
|
+
```sh
|
|
567
|
+
amdahl runs
|
|
568
|
+
amdahl run 9fd4f2e3-bc8e-436b-86d7-a677a89e8d16
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
`run <run-id>` shows one optimize run you made (`GET
|
|
572
|
+
/messages/optimize/runs/:id`): your draft, then the message Amdahl returned,
|
|
573
|
+
what it left out and how much context you sent. Only the person who made a run
|
|
574
|
+
can open it. A grade writes no message, and says so. A prompt run's id starts
|
|
575
|
+
with `opt_`: read it with `amdahl prompt --run <id>`.
|
|
576
|
+
|
|
577
|
+
`runs` lists the latest runs made **from this computer**: the API has no read
|
|
578
|
+
that lists a person's runs (the console keeps its own list in the browser), so
|
|
579
|
+
the CLI keeps the ids it started in `runs.json` beside `config.json`: the run
|
|
580
|
+
id, when, the kind (`optimize`, `grade` or `prompt`), the channel and the
|
|
581
|
+
workspace, for the last 50 runs, in an owner-only file. Never a
|
|
582
|
+
message, a draft or a prompt. Runs made in the console or an AI client are not
|
|
583
|
+
in it, but their ids open with `amdahl run`. `--limit <n>` shows more than the
|
|
584
|
+
latest ten; `--json` prints `{ok, source, note, total, runs}`.
|
|
585
|
+
|
|
586
|
+
## What the workspace holds
|
|
587
|
+
|
|
588
|
+
```sh
|
|
589
|
+
amdahl data
|
|
590
|
+
amdahl data --surface deals
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
`data` shows what a search can read: each surface's live row count and the
|
|
594
|
+
span of its dates (`GET /search/overview`), then the fields a search can
|
|
595
|
+
filter on (`GET /search/fields`). A count that could not be read says
|
|
596
|
+
`unknown`, never 0. `--surface interactions|deals|deal_qualification` lists
|
|
597
|
+
one surface's fields with their type, meaning and the values they are known to
|
|
598
|
+
hold. Every line fits 80 columns. With `--json` it prints `{ok, overview,
|
|
599
|
+
fields}`.
|
|
600
|
+
|
|
447
601
|
## Connections
|
|
448
602
|
|
|
449
603
|
```sh
|
|
@@ -507,7 +661,8 @@ The list is a CSV file with a header row, or a JSONL file (`.jsonl` or
|
|
|
507
661
|
`.ndjson`) with one batch item, a JSON object, per line. A CSV has a
|
|
508
662
|
`message` column and may have `item_id`, `channel`, `evidence`,
|
|
509
663
|
`on_unsupported`, `facts` and `rules`; facts and rules take one per line
|
|
510
|
-
inside the cell
|
|
664
|
+
inside the cell, and a channel is read in any case (`LinkedIn` is `linkedin`).
|
|
665
|
+
Any other column (a CRM export has many) is not sent: one
|
|
511
666
|
line names it, and it is copied to the results file in its place. Only a
|
|
512
667
|
missing `message` column, or a column Amdahl reads that appears twice (a
|
|
513
668
|
doubled `message`, say), is refused. A JSONL item takes any field a single
|
|
@@ -544,6 +699,65 @@ results go next to that list and the list must have as many messages as the
|
|
|
544
699
|
batch has items (exit 2 otherwise), otherwise they go to `<id>.optimized.jsonl`
|
|
545
700
|
here. `--no-wait` with `--batch` exits 2: it only queues a new list.
|
|
546
701
|
|
|
702
|
+
### Send the list to your sequencer
|
|
703
|
+
|
|
704
|
+
```sh
|
|
705
|
+
amdahl optimize --list drafts.csv --for lemlist --channel email
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
`--for <tool>` (a CSV list only) also writes the messages Amdahl wrote as a
|
|
709
|
+
file that tool imports, next to the results, and prints three steps: where to
|
|
710
|
+
import it, what to map, and what to paste into the step. The file is
|
|
711
|
+
`<list>-<tool>.csv`: `drafts.csv` for lemlist gets `drafts-lemlist.csv`. The
|
|
712
|
+
console's Send to writes the same file for the same list.
|
|
713
|
+
|
|
714
|
+
```
|
|
715
|
+
Results: drafts.optimized.csv
|
|
716
|
+
Import file for lemlist: drafts-lemlist.csv
|
|
717
|
+
38 messages ready for lemlist. 2 left out: 1 failed, 1 with no email.
|
|
718
|
+
1. Import: In your campaign, open Leads list > Import new leads > CSV.
|
|
719
|
+
2. email and the name columns map on their own. amdahl_subject and
|
|
720
|
+
amdahl_message become custom variables.
|
|
721
|
+
3. Paste into your step: Subject {{amdahl_subject}}, Body {{amdahl_message}}
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
- **Tools:** `instantly`, `smartlead`, `lemlist`, `heyreach`, `reply_io`,
|
|
725
|
+
`apollo`, `outreach`, `salesloft`, `hubspot`, `lgm` (La Growth Machine),
|
|
726
|
+
`woodpecker`, and `other` for any tool with a CSV import. Gmail and Outlook
|
|
727
|
+
send from a mailbox, so they have no import file.
|
|
728
|
+
- **Channel:** a file is for one channel. A tool that takes one channel needs no
|
|
729
|
+
flag: HeyReach and La Growth Machine are LinkedIn, and the rest are email,
|
|
730
|
+
except lemlist, Reply.io and `other`, which take both. For those, add
|
|
731
|
+
`--channel email` or `--channel linkedin`, or put the channel in the list's
|
|
732
|
+
`channel` column. A list with both channels is refused.
|
|
733
|
+
- **Rows:** only leads Amdahl wrote. A lead that failed, needed input or was not
|
|
734
|
+
written is left out, and so is one with no email (no LinkedIn URL for
|
|
735
|
+
LinkedIn; HeyReach also needs a first and a last name). The line after the
|
|
736
|
+
count says how many and why.
|
|
737
|
+
- **Columns:** your list's `email`, `first_name`, `last_name`, `company` and
|
|
738
|
+
`linkedin_url`, found by header in any common spelling and named as the tool
|
|
739
|
+
names them (lemlist `firstName`, `companyName`; Instantly and Smartlead
|
|
740
|
+
`company_name`), then `amdahl_subject` and `amdahl_message` (just
|
|
741
|
+
`amdahl_message` for LinkedIn), then every other column of your list in its
|
|
742
|
+
order, as lowercase snake_case. The column the message came from (the first
|
|
743
|
+
whose header names a draft, such as `message`, `draft` or `body`) and the columns Amdahl
|
|
744
|
+
reads itself (`message`, `channel`, `evidence`, `on_unsupported`, `facts`,
|
|
745
|
+
`rules` and `item_id`, matched on the snake_case header, so `Item ID` too)
|
|
746
|
+
are not in the file. Your tool imports a value as it is, so no cell gets the `'`
|
|
747
|
+
guard that the results file has: a `-20% off` subject or a `+1 415...` phone
|
|
748
|
+
number arrives as written. Line breaks are CRLF, and there is no byte-order
|
|
749
|
+
mark.
|
|
750
|
+
- **Checked first:** before anything is queued, a list the tool cannot import
|
|
751
|
+
exits 2: no email column for an email file, no LinkedIn URL column for a
|
|
752
|
+
LinkedIn one, a JSONL list (the file keeps your columns), a file that already
|
|
753
|
+
exists (`--force` replaces it). `--no-wait` queues the batch, and the line it
|
|
754
|
+
prints to pick it up carries `--for` and `--channel`.
|
|
755
|
+
- **Under `--json`:** the file is still written, no steps are printed, and the
|
|
756
|
+
batch gains `send_to`: `tool`, `channel`, `file` (null when no lead was
|
|
757
|
+
ready), `ready`, `left_out` (`failed`, `not_written`, `needs_input`,
|
|
758
|
+
`no_contact`) and `over_limit`. With no lead ready, no file is written and
|
|
759
|
+
the exit is 1.
|
|
760
|
+
|
|
547
761
|
## After you send
|
|
548
762
|
|
|
549
763
|
```sh
|
|
@@ -564,8 +778,9 @@ stores two.
|
|
|
564
778
|
(`POST /messages/report_send`). A report from a CLI sign-in is stored as
|
|
565
779
|
`reported_via: cli`. The flags are the report's fields: `--provider`
|
|
566
780
|
(`lemlist`, `instantly`, `outreach`, `salesloft`, `hubspot`, `salesforce`,
|
|
567
|
-
`gmail`, `heyreach`, `apollo`, `
|
|
568
|
-
list, so use `other` for a sender that
|
|
781
|
+
`gmail`, `heyreach`, `apollo`, `smartlead`, `reply_io`, `lgm`, `woodpecker`,
|
|
782
|
+
`linkedin_manual`, `other`; the server's list, so use `other` for a sender that
|
|
783
|
+
is not on it), `--channel` (`email`,
|
|
569
784
|
`linkedin_invite`, `linkedin_message`, `linkedin_inmail`; `linkedin` is
|
|
570
785
|
accepted and means `linkedin_message`, as in `amdahl optimize --channel`),
|
|
571
786
|
`--sent-as` (`returned` or `edited`) and `--sent-at` (a time with a time
|
|
@@ -592,6 +807,26 @@ server's limits first, and a mistake is a usage error that names the flag. It
|
|
|
592
807
|
counts a text's length as the server does, in UTF-16 units, so an emoji counts
|
|
593
808
|
as two. A send the server did not store prints why and exits 1.
|
|
594
809
|
|
|
810
|
+
### Asking what is missing
|
|
811
|
+
|
|
812
|
+
At a terminal, `feedback` and `sent` ask for what you leave out instead of
|
|
813
|
+
exiting 2, with a default for each, and never more than three questions.
|
|
814
|
+
`feedback <run-id>` asks how you know (`--evidence`), then what happened
|
|
815
|
+
(`--outcome`) when you gave no outcome, text or comment. `sent <run-id>` asks
|
|
816
|
+
where it went out (the providers, a menu), who it went to (a recipient, when
|
|
817
|
+
you gave no send id or recipient) and whether you changed it first (paste the
|
|
818
|
+
message as sent, or press Enter for as returned; with `--sent-text` given, a
|
|
819
|
+
yes or no). It never asks for the channel. When it asks for something else
|
|
820
|
+
and `--channel` is not given, it picks one and prints it before it sends: email
|
|
821
|
+
for an email address as the recipient, LinkedIn for a LinkedIn profile, else the
|
|
822
|
+
run's channel (when this computer made the run), else the provider's. If
|
|
823
|
+
`--channel` is the only thing missing, it is a usage error: give it. What you gave is checked first,
|
|
824
|
+
so a typo costs no answers, and Ctrl+C sends nothing. With `--json`, in an
|
|
825
|
+
agent (`CLAUDECODE`, `CURSOR_AGENT`), in CI, with `AMDAHL_NO_PROMPT=1` or with
|
|
826
|
+
stdin or stdout not a terminal (`amdahl sent <id> | tee`), nothing is asked and a
|
|
827
|
+
missing flag is the usage error it always was. `grade` and `prompt` with no
|
|
828
|
+
file paste only under the same rule.
|
|
829
|
+
|
|
595
830
|
## Next steps
|
|
596
831
|
|
|
597
832
|
Human output names the next step where there is one, in at most two extra
|
|
@@ -858,7 +1093,7 @@ code shown in the terminal; then the key is printed once and stored nowhere.
|
|
|
858
1093
|
| code | meaning |
|
|
859
1094
|
|---|---|
|
|
860
1095
|
| 0 | ok |
|
|
861
|
-
| 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) |
|
|
1096
|
+
| 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 prompt run that failed or is still going, a `skills add` refusal, `invalid_config`, bare `amdahl` with no terminal that found no client) |
|
|
862
1097
|
| 2 | usage (also bare `amdahl` in CI, with `AMDAHL_NO_PROMPT=1` or with `--json`) |
|
|
863
1098
|
| 3 | not signed in (401, `invalid_grant`, no credential) |
|
|
864
1099
|
| 4 | forbidden (403, `oauth_required`, `cli_client_required`, `not_admin`, `missing_scope`; also research that started but this credential cannot read) |
|