keinsaasforever/gtm-pipeline-skills/gtm-signal-search

Claude Code and agent skill by keinsaasforever/gtm-pipeline-skills

Trust tier 2
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Find buying intent signals for target companies and score them for purchase intent. Runs a Python script (signal_search.py) that orchestrates Parallel web search (always on), Firecrawl crawl (opt-in), Parallel structured enrichment (opt-in), and a Signal Assessment LLM that scores 1-100. Universal templates live in the script; client-specific prompts come from the working directory's context/ files. Runs standalone or in either pipeline workflow — does NOT require ICP scoring as input. Also triggers on "signal search", "find signals for", "buying intent".

Install

npx vskill@latest install keinsaasforever/gtm-pipeline-skills/gtm-signal-search

SKILL.md

Signal Search

Find buying intent signals for target companies and score each 1–100. Universal extraction prompts, scoring rubric, and request shapes are baked into signal_search.py (ported from the live n8n workflow lE1svjQ5TrgZ0bQy). Anything client-specific — what we sell, who the ICP is, what kinds of signals matter — is loaded from {client-slug}-gtm/context/ files at runtime.

Read `~/.claude/skills/gtm-pipeline/_shared/conventions.md` before executing.


When to Use

  • Standalone: Score signals on any company list (raw or pre-filtered)
  • Company-First workflow: Run on ICP-scored companies (gate at icp_score >= 70 to save credits)
  • Signal-First workflow: Run as the discovery step

The skill does not require ICP scoring as input. It does require an ICP definition (text) so the scoring step understands fit.


The Three Required Context Files

Before the script can run, the working directory must contain:

{client-slug}-gtm/context/
├── icp.md ← ICP definition (industries, geography, size, roles, exclusions)
├── offering.md ← What we sell, to whom, key value props (used in the scoring prompt)
└── signal_criteria.md ← What counts as a buying signal for THIS offering: an INCLUDE list + a short "not a signal" EXCLUDE list

If any of these are missing, collect them from the user before running the script. Do not invent them. Do not copy them from a previous client's gtm folder.

Fallback: If offering.md is missing but profile.md exists (written by gtm-setup), the script will use profile.md instead. Prefer offering.md when possible — profile.md is broader (includes tone, customer segments, etc.) and produces a noisier scoring prompt. If profile.md is the only thing available, consider asking the user to extract the offering-specific paragraphs into a dedicated offering.md.

Step 1 — Check for context files
bash
ls {client-slug}-gtm/context/

If icp.md, offering.md, and signal_criteria.md all exist, proceed to Step 4.

Step 2 — Ask the user for what's missing

Use AskUserQuestion (or a direct prose ask) to collect each missing piece. Suggested wording for each:

ICP (`icp.md`):

  • Industries (include / exclude)
  • Geography
  • Company size (employees, revenue)
  • Decision-maker roles
  • Anything else that disqualifies a company (e.g. "must have a public website", "exclude pure consultancies")

Offering (`offering.md`):

  • What you sell (one paragraph)
  • The 3–5 main capabilities
  • Who it's for (target buyer profile)
  • The primary outcome you deliver
  • Any flagship product or differentiator

Signal criteria (`signal_criteria.md`) — INCLUDE *and* EXCLUDE:

This file is the heart of the prompt — it feeds the Parallel search objective, both extraction LLMs, and the Firecrawl crawl hint. Unless the user hands you a ready-made list, help them build one by walking the same dimensions the n8n workflow uses. Capture two blocks:

Include — what counts as a buying signal for THIS offering. Ask: "What would a company be doing right now that suggests they need our product?" Offer this category palette (adapt to the offering, don't paste verbatim):

  • Funding / acquisitions tied to relevant budget
  • New leadership in roles relevant to the offering
  • Hiring for roles adjacent to the problem we solve
  • Technology adoption / migration relevant to our offering
  • Stated pains, transformation projects, or efficiency goals
  • Expansion / growth plans, entry into new markets
  • Product launches that imply the underlying need
  • Vendor consolidation / SaaS-spend optimization

Exclude — what must NOT be treated as a signal. End the file with a short "Not a signal:" block. Typical excludes:

  • Generic "we're growing" marketing copy or evergreen About-page text
  • News older than the lookback window
  • Developments unrelated to the offering
  • Activity at a same-name-but-different-company or a different domain

Tuning parameters — ask unless the user already specified them. These mirror the knobs in the n8n Firecrawl / Parallel configs; only the client-specific ones are worth asking about (the rest are baked defaults):

ParameterAsk the userDefaultWhere it goes
Max age of signals"How recent must a signal be?"4 months--lookback-months (gates Parallel after_date and the freshness filter on search results and crawled pages)
Web results per company"How many web results per company should we scan?"12--max-results (raise for large/noisy companies, lower to save credits)
Firecrawl on/off"Does on-site content (careers/blog/press) carry the signal?"off--firecrawl or --firecrawl-pages-dir — see Step 4
Enrichment on/off"Do you need structured fields (funding stage, job URLs, tech stack) as their own columns?"off--parallel-enrichment

Baked defaults — don't ask, only change in the script if a client truly needs it: the crawl excludePaths (privacy/legal/cart/shop, plus agent-directed files like agents.md/llms.txt), the scrapeOptions (markdown, main-content-only, ad-block), and the Parallel-enrichment JSON schema (funding / hiring / digital-initiatives / tech-stack).

Step 3 — Save the context files

Write each user-supplied answer to its file. Keep them concise but complete — the LLM sees these on every scoring call.

Step 4 — Pick which sources to enable

Use AskUserQuestion to confirm. Defaults:

SourceDefaultWhen to enable
Parallel web searchON (always)—
Firecrawl website crawlOFFEnable when on-site content matters — e.g. the offering targets companies where careers pages, blog, or product pages reveal the buying signal. Skip for generic prospects where news is enough.
Parallel structured enrichmentOFFEnable when structured fields are required downstream — funding stage, hiring signals with job URLs, tech stack indicators that need to live in their own CSV columns. Skip if the scored signals JSON is enough.

Two ways to run Firecrawl (pick based on how you have Firecrawl access):

RouteFlagNeeds FIRECRAWL_API_KEY?How it works
Native API--firecrawlYesThe script crawls each site via the Firecrawl API. One command, fully automated.
MCP / pre-crawled--firecrawl-pages-dir DIRNoYou crawl the sites with the Firecrawl MCP (or any tool) and drop DIR/{domain}.json files — each a JSON array of {"markdown": ..., "metadata": {"ogUrl": ..., "article:published_time": ...}}. The script reads those, applies the same freshness filter + extraction, and never touches the Firecrawl API.

Use the MCP route when this machine has Firecrawl only via MCP and no FIRECRAWL_API_KEY in the env file. When orchestrating the MCP route, prefer delegating the crawl to sub-agents so the heavy page markdown stays out of the main context — they write the {domain}.json files, then the script does the rest.

Step 5 — Run the script
bash
# Resolve the .env path (from $GTM_ENV_PATH, else _shared/local.md, else ~/.env.gtm),
# then inject only the keys this run needs. Default backend "agent" needs ONLY PARALLEL_API_KEY.
source "$HOME/.claude/skills/gtm-pipeline/_shared/resolve_env.sh" && \
while IFS= read -r line; do export "$line"; done < <(grep -E '^(PARALLEL_API_KEY|FIRECRAWL_API_KEY)=' "$GTM_ENV_PATH") && \
python3 ~/.claude/skills/gtm-signal-search/signal_search.py \
--client-dir {client-slug}-gtm \
--limit 5 \
--lookback-months 2 \
--max-results 12 \
[--firecrawl | --firecrawl-pages-dir {client-slug}-gtm/firecrawl_pages] \
[--parallel-enrichment]

Backends (see Model Routing below): the default --llm-backend agent makes the script collect-only — it runs Parallel/Firecrawl and writes raw evidence per company to csv/intermediate/signals_raw/{domain}.json (and inline in the CSV), leaving overallScore empty with overallSummary = PENDING_AGENT_PROCESSING. You (the agent) then extract + score each company in-context per the Agent Scoring Rubric below and write the scores back — no third-party LLM, no nested claude -p. This is the path both interactively and under a deployed claude -p webhook. For a fully autonomous run with no agent in the loop, pass --llm-backend claude-cli (shells claude -p --model opus) or the legacy --llm-backend openrouter.

Env path: the resolve_env.sh helper finds your .env even when GTM_ENV_PATH isn't exported — it reads the GTM_ENV_PATH= line from ~/.claude/skills/gtm-pipeline/_shared/local.md, falling back to ~/.env.gtm. All GTM keys live in that one file.

OPENROUTER_API_KEY/GEMINI_API_KEY are needed only for --llm-backend openrouter. FIRECRAWL_API_KEY is only needed for the native --firecrawl route, not for --firecrawl-pages-dir.

Lookback default is 2 months (~60 days) — signals older than that are not buying intent.

Start with --limit 5 as a test batch. Review the output, then re-run without --limit for the full list.

Step 5b — Agent Scoring Rubric (backend = agent)

After the collect-only run, score each company yourself (use the opus model per Model Routing — directly, or an Opus subagent). Read the raw evidence from csv/intermediate/signals_raw/{domain}.json (or the webSearchSignals/websiteSignals columns). Score each candidate on two axes, in order:

Axis 1 — Attribution / proximity (the gate). Does the development genuinely stem from this company (or the named person at it), or is it a generic industry / peer / market story bent onto it?

  • Direct (company or its named leader is the actor) → passes.
  • Adjacent (a named partner/customer/competitor acts) → keep only if it forces an action *at this

company*; otherwise drop.

  • Generic (sector trend, "companies like this…", a trend piece that merely lists the company) →

not a signal. Score 0. Never invent a connection between industry news and this company.

Only a signal that passes Axis 1 proceeds. Then apply the remaining keep-gates:

  • Fresh — within the lookback window (≤ --lookback-months). No parseable date ⇒ not fresh ⇒ drop.
  • Sourced — has a live source_url and a date. Drop unlinkable/undated signals.
  • Real & on-target — the source text actually supports the claim (re-read it; a "CTO hiring" post

can be a mislabeled lab role), and the geo/segment matches the ICP.

  • Intent ≠ incumbency — "already owns a competing/adjacent solution" is neutral/negative, not hot;

reposition as complement/ICP-fit.

Axis 2 — Offering fit (priority + hook). For signals that pass Axis 1, how tightly does the development connect to what we sell? This sets the score band and the outreach hook: a company-real signal that directly implies our need = high-priority; a company-real signal only loosely related = low-priority ICP-fit, not hot intent. Proximity decides *whether* to reach out; offering fit decides *how hard* and *with what hook*.

Then write overallScore (0–100), signalCount, scoredSignals (each with source_url + date

  • attribution of direct/adjacent/generic),

and a one-line actionable overallSummary back into signals.csv. Companies with no surviving signal are demoted to ICP-fit (score reflects that) — never force-fit a stale/weak signal as intent. Downstream sanitize.py drops any signal still lacking a source/date or left PENDING.

Hiring signals: job feeds (ATS and Arbeitsagentur)

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
61
Repository forks
6
7-day trend score
21

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/keinsaasforever/gtm-pipeline-skills/gtm-signal-search/badge)](https://verified-skill.com/skills/keinsaasforever/gtm-pipeline-skills/gtm-signal-search)

Something wrong with this skill or its page? Tell us.