The Toolkit

The CRM engine you can
trust an AI agent with

Open source. Agents read everything; every change becomes a typed plan you approve, with a full audit trail. Works with HubSpot and Salesforce, over CLI or MCP. In our benchmark, gated frontier models made no unauthorized writes.

# try it on a realistic, deliberately messy demo CRM — no credentials needed
npx fullstackgtm audit --demo

What it does

The commands you'll actually run

Every write verb stages a plan you approve before anything changes. Ungoverned, Claude Sonnet 4.6 made an unauthorized write in 17.6% of raw runs (about 12% on average across ten models); gated, that drops to zero for 8 of 10 models tested — including every frontier model — and every change is logged.

auditFind what's broken, read-only

Checks your CRM against deterministic rules — duplicates, ownerless records, stale pipeline, bad close dates — and shows what's wrong with the evidence. It never writes anything.

$ fullstackgtm audit --provider hubspot
CRM health  62/100   (1,284 records scanned)
duplicate-accounts        47   high
ownerless-deals           23   high
stale-deal-no-activity    61   medium
dedupeMerge duplicates, keep the best record

Finds duplicates by a key you choose, keeps the most complete record as the survivor, and stages a merge plan. Nothing merges until you approve it.

$ fullstackgtm dedupe account --key domain --keep richest
staged plan pl_8f2a — 47 merges, 0 applied
  acme.com    3 → 1   survivor: Acme Inc (most fields)
  globex.io   2 → 1   survivor: Globex (newest activity)
approve:  fullstackgtm plans approve pl_8f2a --operations all
reassignMove ownership in bulk, safely

Reassigns records from one owner to another — a rep who left to their replacement — and skips anything that changed under you or sits on a deal you exclude.

$ fullstackgtm reassign --from 771 --to 805 --objects account,contact
staged plan pl_3c19 — 214 reassignments, 0 applied
  skipped 6 records changed since snapshot (drift)
  skipped 18 contacts on closed-won deals
approve:  fullstackgtm plans approve pl_3c19 --operations all
fixApply one rule's fixes in a step

Takes a single audit rule and stages every fix it covers at once, for when you trust the rule and just want it cleaned up. Still a plan you approve.

$ fullstackgtm fix --rule ownerless-deals --provider hubspot --min-confidence high
staged plan pl_a44e — 23 owner assignments (high confidence)
  derived each owner from the deal's account owner
approve:  fullstackgtm plans approve pl_a44e --operations all
callTurn call transcripts into CRM updates

Reads a call transcript and stages the field changes and next steps the rep actually said, each one quoted against the moment in the call. The rep's words become the update.

$ fullstackgtm call plan --transcript acme-disco.txt --deal 99213
staged plan pl_1d70 — 4 updates on deal 99213
  next step   "send security questionnaire by Fri"
  close date  Q3 → Q4   ("...realistically next quarter")
  amount      $40k → $60k
approve:  fullstackgtm plans approve pl_1d70 --operations all
marketMap what competitors claim

Builds a map of your category from competitors' own pages — which claims each vendor makes and where the ground is still open. Every claim is quoted from a stored capture.

$ fullstackgtm market report --profile acme
category: revops-data-hygiene   (9 vendors, 142 claims)
  you own:     dry-run preview, open-source
  contested:   governed writeback, CLI/MCP
  open:        audit-trail compliance
reportA client-ready audit deliverable

Writes up the audit — every finding, the evidence behind it, and what changed — as Markdown or a self-contained HTML file you can hand to a client or to finance.

$ fullstackgtm report --provider hubspot --out audit.html
wrote audit.html  (self-contained, 1,284 records, 143 findings)
  findings by rule · evidence quotes · applied-change log
enrichAdd qualified leads without duplicates

Scores sourced prospects against your ICP, resolves every candidate against the CRM first, and proposes only confirmed net-new records. Nothing is created until approval.

$ fullstackgtm enrich acquire --source clay --icp ./icp.json --max 25
scanned 120 candidates · 34 passed ICP · 9 already existed
staged plan pl_72be — 25 create operations, 0 applied
signalsFind public evidence that timing changed

Finds fresh behavioral triggers from public sources, quotes the evidence verbatim, and ranks accounts by what changed — not just who matches a firmographic filter.

$ fullstackgtm signals discover --icp ./icp.json --source exa --since 30d
18 accounts with verified triggers
  7 hiring against an ICP priority · 4 funding events · 7 other
icpTurn your website into targeting logic

Derives an evidence-backed ICP from your public website, keeps it versioned with the hosted workspace, and judges fresh signals into send, nurture, or skip.

$ fullstackgtm icp derive --domain acme.com --out icp.json
derived 12 target titles · 5 firmographic filters
verified 7 source quotes · wrote icp.json
routeMatch leads and assign the right owner

Matches leads to accounts by domain or company, inherits the correct owner, and surfaces ambiguous matches instead of guessing.

$ fullstackgtm route leads --provider hubspot --match both
matched 183 leads · 12 ambiguous · 5 unmatched
staged plan pl_91ac — 183 owner assignments, 0 applied
tamSize and populate the market you can reach

Counts real accounts from your ICP, combines them with confirmed annual contract value, and tracks how much of the reachable market your CRM actually covers.

$ fullstackgtm tam estimate --icp ./icp.json --source explorium --acv 18000
reachable accounts  8,420 · annual ACV  $18,000
estimated TAM       $151.6M

Plus health, resolve, plans, apply, schedule, and the rest — full command reference →

Quickstart — 3 ways in: MCP · CLI · skills

npx skills add fullstackgtm/core   # teach any skills-aware agent to drive it safely
npx fullstackgtm audit --demo      # see it on a deliberately messy demo CRM — no API keys
fullstackgtm audit --provider hubspot --save
fullstackgtm health

Governed enrichment

Enrichment that keeps your CRM the source of truth

Every enrichment vendor ships fire-and-forget writeback. fullstackgtm inverts it: no tables to babysit, no per-seat workflow builder — third-party data becomes a previewed patch plan against your CRM, applied only after you approve it.

enrich append · refresh

Fill blank fields from your sources — Apollo pull, Clay ingest — and re-check stale ones. Fill-blanks only: a populated field is never overwritten, and refresh touches only fields it can prove it stamped.

enrich ingest

Stage vendor exports — Clay CSV or webhook JSON — then append in one governed motion, matched deterministically to your records. Ambiguous matches are never guessed away; they wait for a human.

enrich acquire

Net-new leads scored against your ICP. Resolve-first dedupe never double-creates, every lead gets an owner stamped at creation by your assignment rule, and each run is metered by per-day and per-month caps on records and spend.

Enrichment writes are patches you preview — object, field, before, after, source — not silent column syncs. The same plan → approve → apply contract as every other write.

The hosted app

The same contract, in a browser

app.fullstackgtm.com is the proprietary team product built on the open engine. Name a connection, connect HubSpot or Salesforce with browser OAuth, and the app runs the first sync and health analysis automatically. Daily sync is the default; teams can schedule it.

Findings become an Issues queue. Dismiss the false positives or convert real issues into patch plans. Apply stays approval-gated: drafts do not write, approval comes first, and each operation lands in the audit trail with its outcome. Disconnecting revokes the provider token, not just local access.

It pairs the CLI too. One browser consent connects the org and pairs your terminal. Provider refresh tokens stay encrypted server-side; the CLI holds only short-lived, revocable broker credentials. Open features never move to closed.

For Humans

Every fix previewed. Every duplicate traced to its source.

Start read-only — the audit never writes anything. When you're ready to fix, everything ships as a plan you approve first.

Audit

Find every broken record — with evidence.

Approve

Preview and sign off on every change. Nothing writes silently.

Prevent

Stop new duplicates at the source — and name the integration creating them.

Capture

Reps' own words become CRM updates. One click, zero new fields.

Report

A client-ready report: every finding evidenced, every change logged.

Map

See the market you're selling into.

Signal

Catch the week an account changes — a hire, a round, a reposted role.

Draft

A first line grounded in that change. Proposed, never sent.

Measured, not promised: across ten models from six vendors, agents writing through this gate did at least as well as the same agents on raw CRM tools — nine of ten strictly better on safe completion — and unauthorized writes fell to zero for eight of the ten, including every frontier model. Three models reach 100% safe completion on it. See the full results →

That's the whole pitch. Want it run for you? That's our day job.

Talk to us

For Agents

If you are an AI agent, this section is for you

Deterministic output, --json everywhere, meaningful exit codes, and finding/operation ids that are stable hashes of rule + record — two runs over the same data produce identical ids you can diff and approve.

Start with fullstackgtm capabilities: it prints the machine-readable contract as JSON — verb inventory, read-only vs write-shaped access, exit codes, safety defaults, and the MCP entrypoint. fullstackgtm robot-docs prints the same operating guide npx skills add fullstackgtm/core installs.

Install and verify

# Node 20+, zero runtime dependencies
npm install -g fullstackgtm
fullstackgtm doctor --json        # expect node.ok: true

# prove the whole pipeline with zero credentials (deterministic per --seed)
fullstackgtm audit --demo --json

# zero-setup connect: hosted browser OAuth — a human approves in the browser,
# provider tokens are minted server-side; no app secret ships in the package
fullstackgtm login hubspot        # or: fullstackgtm login salesforce

# sandboxed / BYO: credentials from env — never echo tokens into argv;
# BYO login reads stdin only
HUBSPOT_ACCESS_TOKEN=... fullstackgtm audit --provider hubspot --save

Machine-readable docs: INSTALL_FOR_AGENTS.md (deterministic install-and-verify with expected outputs), skill.md (the compact agent operating guide), and the package llms.txt documentation map. Headless? FSGTM_NO_BROWSER=1 makes login flows print verification URLs instead of opening a browser.

Full functionality inventory

The core loop
snapshot (versioned canonical export, --since, --archive) · audit (12 built-in deterministic rules, plus custom rules, --rules, --fail-on) · suggest (derive values for requires_human_* placeholders from snapshot evidence, with confidence + reasons) · plans list/show/approve/reject · apply (writes only explicitly approved operation ids; consecutive same-shaped updates and archives batch through provider bulk endpoints — 100 records per call on HubSpot, 200 on Salesforce — with compare-and-set preserved per record and per-operation applied/skipped/conflict/failed results) · report (client-ready markdown/HTML deliverable) · diff (snapshot drift, --fail-on-new-findings) · merge (combine snapshots across systems) · bulk-update (governed generic writes: filtered dry-run plans, filters re-verified per record at apply time, cross-record guards) · dedupe (one merge operation per duplicate group, deterministic survivor selection) · reassign (governed ownership handoffs; --assign-unowned claims ownerless records) · fix (one-shot plan from a single audit rule) · rules · doctor
Calls → evidence
call parse (any transcript dialect → evidence-quoted insights; LLM with your own key, or --deterministic free baseline) · call classify (call type from deterministic, key-free signals — discovery, demo, negotiation, renewal… — with confidence + reason; --llm tiebreak) · call score (auto-selects the type-specific rubric so a renewal isn't graded on discovery; anchored examples, evidence-quoted per dimension, qualitative band) · call link (which deal was this call about, with confidence + reason) · call plan (next steps → the same governed plan lifecycle)
The create gate
resolve account|contact|deal — call before ANY record creation. Exit 0 = safe to create, 2 = exists or ambiguous: do not create. Identity keys match the audit/merge engines exactly; names alone are never identity.
Governed enrichment
enrich append/refresh/ingest/status — pull from Apollo or ingest Clay exports (CSV or webhook), matched deterministically to existing records. Fill-blanks-only plans: enrichment never overwrites a populated field, and every value flows through the same dry-run → approve → apply gate as any other write.
Revenue truth
backfill stripe proposes one closed-won HubSpot deal per paid Stripe invoice: amount = invoice total, close date = paid date, matched to the customer's account by billing-email domain, then exact name. It dedupes by invoice id and re-resolves at apply, so re-running never double-creates; a customer your CRM does not know becomes an explicit proposed account create in the same plan. backfill runs replays local run history and the health timeline to a paired hosted deployment, idempotently; only statuses, counts, timestamps, and scores leave the machine — never CRM field values.
Lead generation
enrich acquire + icp interview/set/show — net-new leads, ICP-targeted and dupe-safe by default. An ICP you develop by interview drives the discovery filters (Explorium, pipe0/Crustdata) and scores every prospect for fit, so only above-threshold contacts become create_record plans. You never pay to re-enrich a duplicate: anyone already in your CRM (matched on LinkedIn URL, then name + domain) or seen in a prior run is dropped before the paid email step, and every run is metered against a per-profile budget of records and spend. Every lead is assigned an owner at creation — by a fixed rule, round-robin, territory, or the matched company's owner — so prospecting never leaves records ownerless. Like every write, leads land only after you approve the plan.
Scheduled re-audits
schedule add/list/remove/enable/disable/run/install/uninstall/status — recurring runs from a read/plan-side allowlist of commands. Scheduling never auto-approves: unattended runs accumulate proposals for human review, never writes.
The market map
market init/capture/classify/worksheet/observe/fronts/axes/report/refresh — vendors × claims as reviewable config, content-addressed page captures, intensity readings with every quoted span verified character-for-character against the stored capture, deterministic front states, PCA-derived axes. Agents can classify directly: worksheet returns claims + judging rules + page texts; submit via observe.
TAM mapping
tam estimate/accounts/status/report/populate sizes the reachable market from the ICP that drives acquire: a real account count (Explorium, or TheirStack's technology install data for who actually runs a CRM) × a real annual ACV you confirm. No band defaults; it refuses to run without ACV. status classifies existing CRM accounts as in-TAM, out-of-TAM, or unknown so junk records never inflate coverage, report projects burn-up and ETA, and populate schedules plan-only enrich acquire --save runs to fill the gap. Apply stays approval-gated.
Signal-based outbound
signals fetch/list/outcome/weights — watch for the week an account changes, sorted into five weighted buckets (demand, funding, job, company, social); a reposted role outweighs a first-time post. Public ATS boards (Greenhouse, Lever, Ashby) are the free, no-auth source in the box; funding/company/social arrive via staged ingest. Detect-side — it captures triggers to a local ledger and writes nothing to your CRM. Outcomes (signals outcome) re-weight which buckets earn a touch.
The judge
icp judge + icp eval — score each account on timing × fit × memory into send/nurture/skip; every why-now must quote a real trigger verbatim (or it isn't stored), and a deterministic baseline runs key-free. icp eval grades the judge against a golden set (and hot-vs-cold outcomes), exiting 2 below the bar — the calibration gate that blocks a miscalibrated judge from reaching a live send.
Trigger-grounded drafts
draft — one opener per hot account whose first line quotes the trigger in the buyer's own words, emitted as a create_task plan through the same approve → apply gate. It has no send capability and adds none: drafts everything, transmits nothing. No-key runs produce a labeled stub, never fake copy.
MCP server
fullstackgtm-mcp exposes fullstackgtm_capabilities (the machine-readable CLI contract), fullstackgtm_audit, fullstackgtm_rules, fullstackgtm_suggest, fullstackgtm_apply (requires explicit approved ids), fullstackgtm_resolve, fullstackgtm_call_parse, fullstackgtm_market_worksheet, fullstackgtm_market_observe over stdio.
Contracts you can rely on
Exit codes 0/1/2 (success / error / gate or findings threshold) · stable hash ids for findings and operations · --demo --seed for credential-free CI · credential ladder: --token-env → ambient env → BYO stored login → hosted OAuth / broker pairing (the default login hubspot|salesforce: browser consent, provider tokens minted server-side and never shipped in the package) · --profile / FULLSTACKGTM_PROFILE multi-org isolation · BYOK LLM (ANTHROPIC_API_KEY / OPENAI_API_KEY), base-URL override (ANTHROPIC_API_BASE_URL / OPENAI_API_BASE_URL) to run on a GLM/z.ai or local Ollama endpoint, and a deterministic free mode for every LLM feature · providers: HubSpot (read/write), Salesforce (read/write across field updates, merges, tasks with BYO credentials, links, and contact/account creation), Stripe (read-only); deal creation is HubSpot-only for now
The benchmark (CRM-Ops Bench)
Open-source eval harness in the repo: mock HubSpot with REST-fidelity hazards (pagination, search-index lag, concurrent drift), deterministic graders over final state + the server mutation log, CuP and τ-bench pass^k metrics. npm run smoke needs no API keys. Latest results: no model does worse through the framework across the ten tested — nine improve on CuP, one ties — and eight of the ten reach zero unauthorized writes, including every frontier model. See caveats on reduced-protocol rows and arm definitions in the results and methodology.
Safety invariants (not beta, never change)
Audits are read-only · writes are approval-gated (--approve on specific operation ids) · human decisions are refused, not guessed (requires_human_* placeholders) · quoted evidence is verified verbatim against its source.

Add to your agent

The MCP server is plain stdio — it works in any MCP client. And because the engine is CLI-first with --json everywhere, agents without MCP support can drive it directly from a shell.

Agent skill (any skills-aware agent)

npx skills add fullstackgtm/core

Installs SKILL.md — the compact operating guide for driving the CLI safely.

Claude Code

claude mcp add fullstackgtm -e HUBSPOT_ACCESS_TOKEN=pat-... -- npx -y fullstackgtm-mcp

Codex

codex mcp add fullstackgtm --env HUBSPOT_ACCESS_TOKEN=pat-... -- npx -y fullstackgtm-mcp

opencode

// opencode.json
{
  "mcp": {
    "fullstackgtm": {
      "type": "local",
      "command": ["npx", "-y", "fullstackgtm-mcp"],
      "environment": { "HUBSPOT_ACCESS_TOKEN": "pat-..." }
    }
  }
}

pi

pi's philosophy is CLI tools over MCP — which is exactly what this is. Point pi at INSTALL_FOR_AGENTS.md and it can drive the CLI directly. Prefer MCP? The pi-mcp-adapter reads the standard mcp.json format:

// ~/.pi/agent/mcp.json (or /.pi/mcp.json)
{
  "mcpServers": {
    "fullstackgtm": {
      "command": "npx",
      "args": ["-y", "fullstackgtm-mcp"],
      "env": { "HUBSPOT_ACCESS_TOKEN": "pat-..." }
    }
  }
}

FAQ

Common questions

What's my first command?

Run npx fullstackgtm audit --demo — it runs the full audit on a deliberately messy demo CRM with no API keys and nothing to install. When you are ready on real data, point it at your CRM with audit (read-only, saves a baseline), then run health any time to see your 0–100 score and how it is trending.

Can an AI agent safely write to my CRM?

Not directly — and that is the point. With fullstackgtm, agents can read everything, but every proposed change becomes a typed patch operation (object, field, before, after, reason, risk) that a human approves before any write happens. Nothing is ever written without an explicit approval, and operations that require a human decision are refused outright until a person supplies the value.

Is fullstackgtm free?

Yes. The framework, CLI, and MCP server are open source under Apache-2.0 with zero runtime dependencies. The hosted Full Stack GTM application (dashboard, sync backend, team workflows) is a separate proprietary product built on top — and features never move from open to closed.

Which CRMs does it support?

HubSpot (read/write), Salesforce (read/write), and Stripe (read-only billing). Salesforce matches HubSpot across the governed write surface: field updates, merges, tasks with BYO credentials, record links, and net-new contact and account creation all work on both, verified against a live Salesforce org. One asymmetry: deal creation (used by the Stripe to closed-won backfill) is HubSpot-only for now; on Salesforce those operations are skipped and reported, never guessed. Hosted HubSpot OAuth cannot create CRM tasks; BYO private-app tokens cover that path. The audit, plan, and apply contract is identical across providers.

Does my CRM data pass through your servers?

There are three modes. Open CLI with your own private-app token or Connected App: the CLI runs on your machine, talks directly to your CRM, and nothing — not data, not tokens — touches Full Stack GTM servers. CLI with the default hosted browser login: CRM data still flows directly between your machine and your CRM; only short-lived auth tokens are minted by our broker, with org refresh tokens held encrypted server-side and revocable per CLI. Hosted app at app.fullstackgtm.com: CRM data syncs to our backend, encrypted at rest, to power the dashboard. LLM features use your own Anthropic or OpenAI key via direct fetch, with deterministic mode available.

Does it cover marketing-side hygiene, or just the sales pipeline?

Today, the package covers sales-pipeline hygiene — the built-in audit rules focus on deals, contacts, and accounts — plus governed enrichment for filling the gaps those audits surface, through the same approval gate as every other write. Marketing-hygiene rules and a marketing-spend layer are in development; when they ship, they will follow the same plan-and-approve contract.

Can it find net-new leads, or only clean the records I already have?

Both. enrich acquire generates net-new leads: an ICP you develop by interview drives the discovery filters and scores every prospect for fit, so the contacts are targeted rather than a random list. It is dupe-safe and metered by default — anyone already in your CRM (matched on LinkedIn URL, then name and domain) or seen in a prior run is dropped before any paid enrichment, every run is capped by a per-profile budget of records and spend, and, like every other write, leads land only after you approve the plan.

When acquire creates a lead, who owns it?

Whoever your assignment rule says — never no one. enrich acquire stamps an owner onto every lead at the moment it is created, so prospecting never leaves a pile of unassigned records for someone to triage later. Route by a fixed owner, round-robin across a team (distributed deterministically, so the same run always splits the same way), territory (by geography, industry, company size, or title), or inherit the owner of the matched company. On a single-owner portal it simply assigns to that person; when several owners exist and you have not set a rule, it refuses to guess — it warns and leaves the leads unassigned rather than route them wrong. To claim records that are already ownerless, "reassign --assign-unowned" hands the whole backlog to an owner through the same approval gate.

How do I know the cleanup is actually working?

Every saved audit stamps a deterministic 0–100 health score onto that org — 100 / (1 + severity-weighted findings per record), the same inputs always producing the same number. Run "fullstackgtm health" any time to see the current score, the change since the last audit, a dated trend, and which rules moved. Scope it per client, and the number climbs as you remediate — a record you can show a stakeholder instead of a vibe.

Who approves the changes — does this create a new inbox for my reps?

No. Plan approval belongs to whoever owns the CRM — usually one RevOps or ops person reviewing a batch, the same way they would review a pull request. Reps only ever see one thing: a proposed next step extracted from their own call, confirmed in one click. No new fields, no queue of patches to triage.

How is this different from CRM cleanup tools like Insycle or DemandTools?

Those are GUI-first apps a human operates. fullstackgtm is CLI- and MCP-first: it is built to sit between AI agents and your CRM, turning anything an agent wants to change into a reviewable, approval-gated plan. It is also the only open-source option in the category.

How does it know the right week to reach out?

Signals. fullstackgtm watches for the week an account changes — a budget-owning hire, a funding round, a reposted role (the first hire fell through) — sorted into weighted buckets, with public job boards (Greenhouse, Lever, Ashby) as the free, no-auth source in the box and funding/company/social brought in by staged ingest. It then scores each account on timing, ICP fit, and whether you have touched it recently, returning a short send / nurture / skip list where every "why now" quotes the real trigger verbatim. Signal capture is read-only — it never writes to your CRM.

Does it send outbound emails or LinkedIn messages?

No. draft writes one opener per high-priority account, grounded in the trigger, but it has no send capability and adds none — the opener becomes a task you approve, then send from your own tool. Like every write, nothing leaves the building until you approve the plan; and before any send the judge can grade itself, checking whether its own "hot" scores actually book more than cold ones. Every LLM step runs on your own key — Anthropic, OpenAI, or any compatible endpoint like a GLM or local Ollama via one base-URL env var.

Ready to build your GTM data foundation?

Book a 30-minute call. We'll map your current stack, identify the gaps, and outline what Stage 3+ looks like for your team.