fullstackgtm 0.40.0 → 0.41.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/CHANGELOG.md +40 -0
- package/README.md +30 -1
- package/dist/cli.js +615 -6
- package/dist/connectors/atsBoards.d.ts +60 -0
- package/dist/connectors/atsBoards.js +179 -0
- package/dist/connectors/prospectSources.d.ts +7 -5
- package/dist/connectors/prospectSources.js +82 -47
- package/dist/draft.d.ts +182 -0
- package/dist/draft.js +333 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/judge.d.ts +209 -0
- package/dist/judge.js +490 -0
- package/dist/judgeEval.d.ts +141 -0
- package/dist/judgeEval.js +331 -0
- package/dist/llm.d.ts +13 -0
- package/dist/llm.js +18 -2
- package/dist/schedule.js +11 -1
- package/dist/signals.d.ts +197 -0
- package/dist/signals.js +515 -0
- package/package.json +1 -1
- package/src/cli.ts +696 -7
- package/src/connectors/atsBoards.ts +242 -0
- package/src/connectors/prospectSources.ts +94 -43
- package/src/draft.ts +463 -0
- package/src/index.ts +94 -0
- package/src/judge.ts +661 -0
- package/src/judgeEval.ts +459 -0
- package/src/llm.ts +31 -2
- package/src/schedule.ts +11 -1
- package/src/signals.ts +685 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,46 @@ The path to 1.0 is planned in [docs/roadmap-to-1.0.md](./docs/roadmap-to-1.0.md)
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.41.0] — 2026-06-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Signal-based outbound: `signals`, `icp judge`/`icp eval`, `draft`.** A timing
|
|
15
|
+
layer on top of CRM hygiene — reach an account the week something changes, not
|
|
16
|
+
from a rented list. `signals fetch/list/outcome/weights` captures buying
|
|
17
|
+
triggers into a local, profile-scoped ledger (Detect-side — it writes nothing
|
|
18
|
+
to the CRM), sorted into five weighted buckets
|
|
19
|
+
(`demand`/`funding`/`job`/`company`/`social`); public ATS boards (Greenhouse,
|
|
20
|
+
Lever, Ashby) are the free, no-auth source in the box, while
|
|
21
|
+
funding/company/social arrive via staged ingest and `demand` is reserved for a
|
|
22
|
+
privileged source. A reposted role outweighs a first-time post, and recorded
|
|
23
|
+
outcomes (`signals outcome`) re-weight which buckets earn a touch. `icp judge`
|
|
24
|
+
scores each account on timing × fit × memory into `send`/`nurture`/`skip` —
|
|
25
|
+
every *why-now* must quote a real trigger verbatim (the same evidence gate as
|
|
26
|
+
`call`/`market`), with a deterministic baseline when no LLM key is set.
|
|
27
|
+
`icp eval` grades the judge against a golden set (and hot-vs-cold outcomes),
|
|
28
|
+
exiting `2` below the bar — the calibration gate that blocks a miscalibrated
|
|
29
|
+
judge from a live send. `draft` writes one trigger-grounded opener per hot
|
|
30
|
+
account as a governed `create_task` plan through the existing approve → apply
|
|
31
|
+
gate; it has no send capability and adds none. All four are read/plan-side and
|
|
32
|
+
schedulable; none can auto-apply or send.
|
|
33
|
+
- **LLM base-URL override.** `ANTHROPIC_API_BASE_URL` / `OPENAI_API_BASE_URL` let
|
|
34
|
+
every LLM feature run against an Anthropic/OpenAI-compatible endpoint (e.g. a
|
|
35
|
+
GLM/z.ai endpoint or a local Ollama) with no code change; unset preserves the
|
|
36
|
+
default endpoints.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **pipe0 resolution runs chunks in parallel (bounded) with exponential backoff.**
|
|
41
|
+
`pipe0ResolveWorkEmails` and `pipe0ResolveCompanyDomains` previously issued one
|
|
42
|
+
serial HTTP call per chunk — a few hundred leads took tens of minutes. They now
|
|
43
|
+
run up to `concurrency` chunks at once (default 3) with exponential backoff on
|
|
44
|
+
transient failures (throttle/5xx/network: 500ms → 4s, up to 5 attempts). Bounded
|
|
45
|
+
concurrency + real backoff cuts wall-clock several-fold while keeping coverage:
|
|
46
|
+
an early concurrency-6 + single-retry build throttled pipe0 at scale and dropped
|
|
47
|
+
the work-email hit-rate from ~79% to ~17%, so the pairing matters. Chunk size
|
|
48
|
+
stays small (the waterfall's batch failure is all-or-nothing).
|
|
49
|
+
|
|
10
50
|
## [0.40.0] — 2026-06-23
|
|
11
51
|
|
|
12
52
|
### Added
|
package/README.md
CHANGED
|
@@ -206,6 +206,35 @@ LinkedIn is just another discovery source on the same scored → deduped → met
|
|
|
206
206
|
|
|
207
207
|
**Leads are never born ownerless.** An `acquire.assign` policy stamps an owner onto every created lead at create time (mapped to HubSpot `hubspot_owner_id`), routed by one of four strategies — `fixed`, `round-robin` (distributed deterministically, no rotation state to drift), `territory` (by geo / industry / size / department / title), or `account-owner` (inherit the matched company's owner). With no policy and a single-owner portal, acquire defaults every lead to that owner (or pass `--assign-owner <id>`); with multiple owners and no policy it warns and leaves them unassigned rather than guess. To clear *existing* ownerless records, `reassign --assign-unowned --to <ownerId>` applies the same intent as a backfill.
|
|
208
208
|
|
|
209
|
+
## Signal-based outbound: reach accounts the week something changes
|
|
210
|
+
|
|
211
|
+
Cleaning and filling the CRM tells you *who* to reach; it never tells you *when*. The **signal → judge → draft** loop adds timing — and, like everything else, it stays on the dry-run → approve → apply spine and sends nothing.
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# 1. Watch for movement. Free, no-auth public job boards in the box; funding/company/social via staged ingest.
|
|
215
|
+
fullstackgtm signals fetch --bucket job --source greenhouse,lever,ashby --keywords "revops,growth" --save
|
|
216
|
+
fullstackgtm signals list --since 7d # ranked triggers, each with a verbatim source quote
|
|
217
|
+
|
|
218
|
+
# 2. Decide who's worth a touch — and who isn't. Scores timing × fit × memory into send/nurture/skip.
|
|
219
|
+
fullstackgtm icp judge --signals-from latest --with-history --save
|
|
220
|
+
fullstackgtm icp eval --golden default # gate: prove the judge is calibrated before any send (exits 2 if not)
|
|
221
|
+
|
|
222
|
+
# 3. Draft the opener from the trigger. A create_task plan — proposed, never transmitted.
|
|
223
|
+
fullstackgtm draft --from-judge latest --min-score 80 --save
|
|
224
|
+
fullstackgtm plans approve <id> --operations all && fullstackgtm apply --plan-id <id> --provider hubspot
|
|
225
|
+
|
|
226
|
+
# 4. Close the loop. Outcomes re-weight which signals earn a touch.
|
|
227
|
+
fullstackgtm signals outcome --account acme.com --result replied
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**`signals`** is Detect-side — it captures triggers into a local, profile-scoped ledger and writes *nothing* to your CRM. The five buckets (`demand`, `funding`, `job`, `company`, `social`) are not equal: a fresh round outweighs a lone social like, and a *reposted* role — the first hire fell through — outweighs a first-time post. Public ATS boards (Greenhouse, Lever, Ashby) are the free, no-auth source shipped in the box; funding/company/social arrive through `--from` staged ingest (an agent or a feed supplies them — the CLI scrapes no one), and `demand` (first-party intent) is reserved for a privileged source.
|
|
231
|
+
|
|
232
|
+
**`icp judge`** turns raw signals into a short ranked list: it scores each account on **timing × fit × memory** — the signal's weight and recency, your ICP fit, and whether you've touched the account in the last 7 days — and returns `send` / `nurture` / `skip`. Every *why-now* it produces must quote a real trigger **verbatim** (the same evidence gate as `call` and `market`); an ungrounded why-now is never stored. With no LLM key it runs a deterministic baseline. **`icp eval`** is the gate the demos skip: it grades the judge against a labeled golden set (and, once outcomes exist, checks that accounts scored hot actually book more than cold), exiting `2` below the bar so a miscalibrated judge can't reach a live send.
|
|
233
|
+
|
|
234
|
+
**`draft`** writes one opener per hot account whose first line quotes the trigger in the buyer's own words — no "Hi {{firstName}}", one ask, no manufactured urgency. It emits a `create_task` plan through the normal approval gate; it has **no send capability** and adds none — execution stays in your sender of choice. Without an LLM key it emits a clearly-labeled stub, never wooden copy passed off as a draft.
|
|
235
|
+
|
|
236
|
+
**Runs on any model.** Every LLM step honors `ANTHROPIC_API_BASE_URL` / `OPENAI_API_BASE_URL`, so the same loop runs on Claude, a GLM/z.ai endpoint, or a local Ollama by pointing one env var — `--model` picks the model id.
|
|
237
|
+
|
|
209
238
|
## Schedules: declare a cadence once, keep the governance contract under automation
|
|
210
239
|
|
|
211
240
|
Everything the CLI produces is accurate the moment it runs and silently stale afterward. The **schedule layer** is the horizontal fix — any read/plan-side command on a cron cadence, one component, every verb (no feature owns its own cron logic):
|
|
@@ -220,7 +249,7 @@ fullstackgtm schedule status --runs 5 # last runs, exit codes, artifa
|
|
|
220
249
|
fullstackgtm schedule uninstall # remove the managed block, touch nothing else
|
|
221
250
|
```
|
|
222
251
|
|
|
223
|
-
**Scheduling never auto-approves.** Schedulable commands are read/plan-side only — `audit`, `snapshot`, `enrich append|refresh`, `market capture|refresh`, `suggest`, `report`, `doctor` — so unattended runs accumulate *proposals* (plans in the queue, run records, reports), never CRM writes. `apply` is schedulable only as `apply --plan-id <id>`, and every firing re-checks the plan's status is approved: an unapproved plan records a `plan_not_approved` no-op run instead of executing, and no flag relaxes this. Arbitrary shell is not schedulable — an entry's argv must resolve to a known fullstackgtm command (validated at `add` time and re-checked at run time), and the crontab line you audit is always `fullstackgtm schedule run <id>` and nothing else.
|
|
252
|
+
**Scheduling never auto-approves.** Schedulable commands are read/plan-side only — `audit`, `snapshot`, `enrich append|refresh`, `market capture|refresh`, `signals fetch`, `icp judge`, `icp eval`, `draft`, `suggest`, `report`, `doctor` — so unattended runs accumulate *proposals* (plans in the queue, run records, reports), never CRM writes. `apply` is schedulable only as `apply --plan-id <id>`, and every firing re-checks the plan's status is approved: an unapproved plan records a `plan_not_approved` no-op run instead of executing, and no flag relaxes this. Arbitrary shell is not schedulable — an entry's argv must resolve to a known fullstackgtm command (validated at `add` time and re-checked at run time), and the crontab line you audit is always `fullstackgtm schedule run <id>` and nothing else.
|
|
224
253
|
|
|
225
254
|
`install` renders enabled entries into a sentinel-delimited block (`# >>> fullstackgtm <profile> >>>` … `# <<< fullstackgtm <profile> <<<`) in your user crontab; re-install replaces the block wholesale and never touches lines outside it. Honest limitation: local cron has no catch-up — a laptop asleep at firing time means a missed run. `schedule status` surfaces missed firings by comparing expected-vs-actual run history, so the gap is at least visible. Entries are provider-agnostic; cloud providers (Modal, AWS) arrive as scaffold generators that call the same `schedule run <id>` contract, and are refused as "not yet implemented" until then.
|
|
226
255
|
|