A reference GTM engineering toolkit — nine plug-and-play automations covering the revenue-side workflows a modern B2B SaaS revenue org actually needs to ship.
Each automation maps to one revenue-org responsibility — event lead capture, ABM, knowledge discovery, forecasting, QBR generation, competitive briefs, AI sales decks, interactive lead magnets, closed-lost revival — and ships as a self-contained folder under automations/ you can run on its own.
Underneath: a typed Python library (gtm_engine) with idempotent CRM clients for HubSpot, Salesforce, Marketo, and Pardot; an LLM provider abstraction across OpenAI, Perplexity, and Gemini; a battery of analytical SQL queries against a typical revenue warehouse; and n8n workflows that wire it all to webhooks, crons, Slack, and Drive.
Built with deliberate restraint: dependencies are pinned and SBOM'd, every secret comes through one config layer, every external API has a retry policy and a dry-run mode. The kind of code that survives a security review and a Procurement questionnaire.
- The nine automations
- Why I built this
- Repo layout
- GTM stack coverage
- n8n workflows
- SQL queries
- Quick start
- Module deep-dive
- Architecture
- Configuration
- Testing
- About
Each folder under automations/ is independently runnable. Drop into the folder, read its README, run its script.
| # | Folder | What it does |
|---|---|---|
| 1 | 01-ai-tool-evaluator | Reproducible benchmark harness for AI tools across GTM jobs — cost, latency, rubric-graded quality |
| 2 | 02-event-automation | Pre-event registrant sync → post-event lead routing → session-transcript → social/blog content |
| 3 | 03-knowledge-discovery | HTTP + Slack /ask surfaces over a TF-IDF Sales/CS knowledge base with cited LLM answers |
| 4 | 04-abm-orchestrator | Target list → personalized 1:1 packets → multi-channel CSV exports → closed-loop SQL attribution |
| 5 | 05-forecasting-suite | Weekly tracker + scikit-learn renewal risk model + Slack digest |
| 6 | 06-interactive-lead-magnet | FastAPI web app: License Risk Quiz + SBOM Readiness Scorer + OSS Compliance Cost Calculator |
| 7 | 07-reporting-automation | QBR generator + competitive battlecard + weekly business review from warehouse data |
| 8 | 08-ai-sales-decks | Role × stage-aware .pptx generator via python-pptx |
| 9 | 09-closed-lost-revival | Trigger monitor (champion change, funding, regulatory, CVE) drafting re-engagement that acknowledges the original lost reason |
I spend my days as a BDM selling regulatory and compliance SaaS into Quality, Food Safety, and Supply Chain leaders. The patterns are the same in every revenue org I've sat in: AEs lose 6 hours a week pulling QBRs together by hand, SDRs send the same first-touch email shape 80 times a week, marketing exports a CSV from the event platform and prays a few hot leads survive the routing, and the closed-lost list compounds quietly while no one watches it.
A "GTM Engineer" doesn't fix that with a Zapier zap. It gets fixed with the same posture an SRE brings to infra: identify the loop, instrument it, ship a thin automation, measure, harden, repeat. This repo is what that looks like for nine of the highest-leverage loops in a revenue org — wired so each piece works alone or together, with the same config and provider abstraction underneath.
I built it around OSS compliance and SBOM-specific examples because that's the domain I find most interesting right now: the regulatory tailwinds (CRA, EO 14028, FDA premarket) make this an unusually clear bet over the next 36 months, and the buyer mix (Security + Legal + Engineering, all in the same room) makes the GTM problem genuinely hard.
gtm-engineering/
├── automations/ 9 plug-and-play folders (see table above)
├── src/gtm_engine/
│ ├── crm/ HubSpot + Salesforce + Marketo + Pardot
│ ├── events/ Event lead capture pipeline
│ ├── abm/ Account intel + outreach packet generation
│ ├── knowledge/ TF-IDF + LLM Sales/CS KB
│ ├── forecasting/ Stage-weighted EV + LLM scoring
│ ├── qbr/ Markdown QBR generator
│ ├── competitive/ Battlecard generator
│ ├── presentations/ Role-aware sales deck outlines
│ ├── lead_magnets/ License Risk Quiz + SBOM Readiness Scorer
│ ├── reengagement/ Closed-lost trigger monitor
│ ├── config.py One pydantic Settings, one .env
│ ├── llm.py OpenAI / Perplexity / Gemini behind one API
│ └── cli.py `gtm-engine <subcommand>` entrypoint
├── n8n/ Importable n8n workflow JSON exports
├── sql/ Warehouse queries used by the automations
├── scripts/ Standalone library demo scripts
├── examples/ Sample inputs and outputs
├── tests/ Pure-logic pytest
├── .github/workflows/ CI + FOSSA license/vuln scan
├── .fossa.yml FOSSA project config
├── sbom.cyclonedx.json CycloneDX 1.5 SBOM
└── pyproject.toml
| Layer | Tools wired |
|---|---|
| CRM (system of record) | Salesforce, HubSpot |
| Marketing automation | Marketo, Pardot, HubSpot |
| Enrichment | Apollo (jobs / contacts), Clearbit (companies) |
| LLM providers | OpenAI, Perplexity, Gemini |
| Notifications | Slack (webhook + slash command) |
| Warehouse | Anything DB-API 2.0 (Postgres, Snowflake, BigQuery via SQLAlchemy); DuckDB for local |
| Orchestration | n8n (workflows in n8n/) |
| Slides | python-pptx |
| ML | scikit-learn (renewal risk model) |
Importable JSON workflow exports in n8n/ — open n8n, hit Import from File, and the nodes appear pre-wired. Each ends in an Execute Command node that hands off to a Python automation in this repo. n8n is the glue; Python does the work.
| Workflow | Trigger | Wraps |
|---|---|---|
post-event-lead-routing.json |
Drive folder change | 02-event-automation/post_event.py |
abm-trigger-orchestration.json |
Weekly cron + GitHub org events | 04-abm-orchestrator/orchestrator.py |
closed-lost-monitor.json |
Webhook (LinkedIn change feed) | 09-closed-lost-revival/monitor.py |
champion-job-change.json |
Webhook + Apollo enrich → Salesforce task | 09-closed-lost-revival/monitor.py |
weekly-forecast-digest.json |
Sundays 9pm ET | 05-forecasting-suite/* |
The JD called out "basic SQL/data querying" — sql/ ships six queries against a typical revenue warehouse schema. Each carries a -- USED BY: line at the top pointing to the automation that runs it.
| Query | Purpose |
|---|---|
account_health.sql |
Composite 0-100 score (adoption + support + commercial) |
conversion_funnel.sql |
Stage-to-stage conversion rates by segment from opportunity_history |
pipeline_velocity.sql |
Days-in-stage + 1.5× median slip detection |
renewal_risk_features.sql |
Feature set that feeds the scikit-learn renewal model |
abm_attribution.sql |
U-shaped multi-touch attribution for ABM campaigns |
event_lead_attribution.sql |
Event-sourced leads → opportunity outcome |
git clone https://github.com/elikem2021/gtm-engineering.git
cd gtm-engineering
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # fill in OPENAI_API_KEY, HUBSPOT_PRIVATE_APP_TOKEN, etc.
pytest -qEnd-to-end demo runs against the included sample data — no live CRM required:
# Process event registrants, score, bucket, write SDR digest (dry-run, no HubSpot write)
python scripts/run_lead_capture.py --csv examples/event_registrants.csv \
--event "KubeCon NA 2026" --out outputs/digest.md --dry-run
# Stage-weighted forecast from CSV
python scripts/forecast_pipeline.py --csv examples/pipeline.csv \
--out outputs/forecast.json
# Generate a QBR deck from YAML inputs
python scripts/generate_qbr.py --inputs examples/qbr_inputs.yaml \
--out outputs/qbr_northwind.md
# Closed-lost re-engagement drafts
python scripts/monitor_closed_lost.py --triggers examples/triggers.json \
--out outputs/reengagement.json
# Competitive battlecard with win/loss data
python scripts/generate_battlecard.py --competitor "Black Duck" \
--win-loss examples/win_loss.csv --out outputs/battlecard_blackduck.mdSample outputs from real runs are checked into examples/ — start with output_qbr_northwind.md and output_battlecard_blackduck.md to see the shape.
Detail on the library code under src/gtm_engine/ that the automations call into.
src/gtm_engine/events/lead_capture.py
CSV in (Luma, Hopin, Goldcast, Google Form), HubSpot contacts + SDR digest out. Each registrant is scored on a tunable ICP rubric for an OSS compliance buyer (titles like AppSec, OSPO, DevSecOps, Supply Chain Security — weighted by seniority), deduped on email keeping the most complete record, and bucketed into hot / warm / nurture lanes. Hot leads get an LLM-drafted personalized first-touch that references the actual event. The digest is markdown — paste it into Slack or Notion as-is.
Why this matters: Field marketing pours money into events and loses 30-60% of the value to slow, hand-routed follow-up. This is the cheapest motion to automate and the one with the highest immediate ROI.
src/gtm_engine/abm/account_intel.py
Given a target account list, this module pulls public signals — GitHub org footprint (repo count, language mix, license mix), hiring signals around AppSec/OSPO/Supply Chain Security roles — into an account dossier. The dossier feeds an LLM packet generator that emits a personalized email, LinkedIn DM, and display ad copy per account.
The personalization angle is deliberately narrow: for an OSS compliance buyer, public OSS footprint is the single highest-signal data point. We lean into it rather than pasting "I noticed your company is in [industry]" boilerplate.
src/gtm_engine/knowledge/searchable_kb.py
Sales reps ask the same 30 questions every week. This is a TF-IDF retrieval engine over a folder of markdown (battlecards, FAQs, RFP responses, call transcripts) with LLM-synthesized answers and inline source citations. No vector DB — under ~5K chunks, TF-IDF with proper IDF weighting outperforms naive embedding retrieval and ships in a single pip install.
python scripts/ask_kb.py --kb docs/knowledge --q "How do we handle Cargo dependencies vs Snyk?"src/gtm_engine/forecasting/pipeline_forecast.py
Two layers. The first is a stage-weighted expected value using historical conversion rates by stage — the floor your CRO will defend in a board meeting. The second is an LLM pass over each open opp that returns a commit / best-case / pipeline / omitted category against a fixed rubric, with rationale text and proposed next steps. The AE reviews and owns the final call — the model removes the 6 hours of stage-by-stage spelunking, not the judgment.
python scripts/forecast_pipeline.py --csv examples/pipeline.csv --llm --out outputs/forecast.jsonsrc/gtm_engine/qbr/deck_generator.py
Inputs: account 360 from Salesforce, product usage from the data warehouse, support summary, expansion signals. Output: a structured markdown deck (one H2 per slide) ready to paste into Gamma/Pitch or render to PPTX. Each slide narrative is LLM-written from the actual data — the CSM tightens, doesn't write from scratch. See examples/output_qbr_northwind.md for the shape.
src/gtm_engine/competitive/battlecard.py
A single-page battlecard for any named competitor (Black Duck, Snyk, Sonatype, Mend, …) combining:
- Win/loss CSV — the internal source of truth, quoted with attribution
- Perplexity research — public positioning, recent news, G2 reviews, every claim sourced with a URL
- Trap-setting discovery questions the AE can actually use mid-call
See examples/output_battlecard_blackduck.md for a trimmed sample.
src/gtm_engine/presentations/sales_deck.py
The same product story told four different ways depending on who's in the room: Security (CVE response time, SBOM accuracy), Legal (license policy enforcement, attribution, M&A due diligence), Engineering (developer workflow friction, false positive rate), Procurement (TCO, deployment options, ROI math), Executive (regulatory tailwinds, board-level risk reduction).
Takes a DealContext — persona × stage × account signals — and returns a 10-slide outline tuned to the buyer in the room. The CISO doesn't care about the same things the GC cares about; this stops AEs from running the same generic deck into every room.
src/gtm_engine/lead_magnets/interactive.py
Two examples shipped here, both designed to be embedded behind a LinkedIn ad CTA:
- License Risk Quiz — six questions about the prospect's OSS posture, weighted scoring, LLM-written 1-page action plan tied to the weak areas. Each completion lands in the funnel with rich context an AE can use on first call.
- SBOM Readiness Scorer — scores reported tooling against three regulatory frameworks (EO 14028, EU CRA, FDA premarket) and returns a verdict the prospect can take to their security team.
src/gtm_engine/reengagement/closed_lost.py
The most under-monetized list in any CRM. People leave the champion job, vendors get acquired, regulations change, board mandates flip — but no one's watching. This monitor consumes trigger events (champion job change, funding round, regulatory mandate, security incident in their stack, competitor displacement signal) and drafts a re-engagement email that references the actual trigger and acknowledges the original lost reason. The pretend-the-prior-conversation-didn't-happen email is what burns this motion — this module specifically doesn't do that.
┌───────────────────────────────────────┐
│ gtm_engine.cli │
└──────────────────┬────────────────────┘
│
┌──────────────┬──────────────┬────┴────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼ ▼ ▼
events/ abm/ knowledge/ forecasting/ qbr/ competitive/
lead_capture account_intel searchable_kb pipeline_fc deck_gen battlecard
│ │ │ │ │ │
└──────────────┴──────┬───────┴─────────┴──────────────┴──────────────┘
│
▼
┌───────────────────────────────────┐
│ gtm_engine.llm (provider │
│ abstraction: OpenAI / Perplexity │
│ / Gemini, retries, JSON parsing) │
└───────────────────────────────────┘
│
▼
┌───────────────────────────────────┐
│ gtm_engine.config (one pydantic │
│ Settings, .env, .require()) │
└───────────────────────────────────┘
│
▼
┌───────────────────────────────────┐
│ External: HubSpot, Salesforce, │
│ Marketo, Apollo, Perplexity, ... │
└───────────────────────────────────┘
Design choices worth calling out:
- One config layer. Every credential lives in
Settings. Modules calls.require(...)up front so they fail with a clear error, not a 401 deep in an API call. - Provider-agnostic LLM. OpenAI is the default workhorse; Perplexity is preferred when sourced/cited answers matter (competitive briefs, account intel); Gemini for long-context summarization (QBR ingestion). Swapping providers is a one-line change at the call site.
- Idempotent CRM writes. HubSpot upserts go through a search-then-patch flow so a re-run never duplicates contacts.
- Dry-run everywhere. Every script that writes externally takes
--dry-run. Default to safe. - Retries with backoff.
tenacityon every external call. No barehttpx.postin the codebase. - SBOM and FOSSA scan in CI. Pinned deps, CycloneDX SBOM checked in, FOSSA Action runs on every push. The repo eats its own dogfood.
Copy .env.example to .env and fill in only what you need. The toolkit fails clearly when a module is missing credentials — nothing silently no-ops.
| Variable | Required for |
|---|---|
OPENAI_API_KEY |
All LLM generation (default provider) |
PERPLEXITY_API_KEY |
Competitive battlecards (sourced research) |
GEMINI_API_KEY |
Long-context QBR ingestion (optional) |
HUBSPOT_PRIVATE_APP_TOKEN |
Lead capture, closed-lost monitor |
SALESFORCE_* |
Live forecasting, account 360 |
MARKETO_*, PARDOT_* |
Future marketing-automation hooks |
APOLLO_API_KEY |
Hiring signals enrichment |
SLACK_WEBHOOK_URL |
SDR digest push (optional) |
pytest -qTests cover pure logic — scoring, bucketing, forecasting math, KB retrieval, lead-magnet grading. No network, no LLM, no CRM. The integration paths get covered with cassette-based recording in a separate suite (not shipped here to avoid leaking real org schemas).
The current modules are the highest-leverage motions. Next on the list, in order of expected impact:
- Renewal risk scoring — leading-indicator model from product usage + support + sentiment in support emails
- Champion change detection — webhook into LinkedIn change feeds to drop a Salesforce task the day a champion changes role
- CI-time policy violation re-engagement — for prospects who once trialed but didn't buy, surface their public CVE exposure and re-engage with concrete data
- Marketo + Pardot adapters — bring the email send/track loop into the same config layer
- Multi-source forecast ensembling — blend stage-weighted EV, LLM commit, and a gradient boost on historical features
Built by Elikem Agbodovie (@elikem2021).
I'm a B2B SaaS Business Development Manager based in Mississauga, Ontario, currently selling regulatory & compliance software (SGS DigiComply, FOODAKAI) into Quality, Food Safety, and Supply Chain leaders. On the side I run Avalux, a B2B AI agency where I build voice/chat agents and revenue automation for HVAC, legal, healthcare, real-estate, and SaaS clients.
This repo is a working portfolio of what I'd build as a GTM Engineer at an open source compliance / SBOM platform. Happy to walk through any module on a call.
- Email: elikemagbodovie@gmail.com
- GitHub: @elikem2021
MIT.