From openfunnel
Spots companies and people with active pain-points from live events using TAQ model (Trait, Activity, Qualifier). Guides B2B searches for buying signals like Heroku migrations or CISO hiring.
npx claudepluginhub openfunnel/openfunnel-skillsThis skill uses the workspace's default tool permissions.
Spot ICP companies with inferred pain-points from live company and people events — where a combination of who they are (trait), what they're doing right now or what pain-points they are facing (activity), and what they already have in place (qualifier). Uses the TAQ model to build a precise search through a guided walkthrough.
Builds targeted company and contact lists using Common Room Prospector for net-new prospects or existing accounts with signals. Clarifies object types and refines iteratively.
Finds, enriches, and qualifies companies and people matching ICP criteria from playbooks, segments, and personas. Outputs prospect lists with fit reasoning and sales approaches.
Identifies potential B2B clients matching service definitions and ideal client profiles using industry, size, location filters and 10-point fit scoring. Outputs prospects to Markdown files.
Share bugs, ideas, or general feedback.
Spot ICP companies with inferred pain-points from live company and people events — where a combination of who they are (trait), what they're doing right now or what pain-points they are facing (activity), and what they already have in place (qualifier). Uses the TAQ model to build a precise search through a guided walkthrough.
Inferred pain-points are leading indicators of buying behavior. Instead of picking signal types (hiring vs social vs tech), describe the pain and the agent infers pain-points by decomposing it into searchable components.
This skill bundles two scripts in the same directory as this SKILL.md file. Never read or reference API credentials directly.
signup.sh — handles authentication. Writes credentials to .env internally. Never exposes the API key.api.sh — handles all authenticated API calls. Reads credentials from .env internally.First, resolve the script paths relative to this file's location:
SKILL_DIR="$(dirname "$(find ~/.agents/skills -name SKILL.md -path "*/spot-companies-and-people-with-active-pain-points/*" 2>/dev/null | head -1)")"
API="$SKILL_DIR/api.sh"
SIGNUP="$SKILL_DIR/signup.sh"
Then use $SIGNUP for auth and $API for all other calls.
Before anything, test if credentials are working by running:
bash "$API" POST /api/v1/signal/get-signal-list '{"pagination": {"limit": 1, "offset": 0}}'
If the call succeeds (returns JSON with signals): skip to Step 1.
If the call fails (returns an error or missing credentials message):
### Welcome to OpenFunnel
OpenFunnel turns daily events in your market into pipeline
— using OpenFunnel's Event Intelligence engine.
To get started, I'll authenticate you via the API and fetch your key.
**Step 0: Agent auth** — what's your work email?
Wait for user input. Then:
Call bash "$SIGNUP" start "<user_email>"
If the call succeeds, tell the user a 6-digit verification code was sent and ask for it:
I sent a 6-digit verification code to **{email}**.
Reply with the code and I'll finish authentication.
bash "$SIGNUP" verify "<user_email>" "<code>"The response is: {"status": "authenticated", "user_id": "..."}. Credentials are written to .env and .gitignore is updated automatically.
If authentication succeeds → continue to Step 1.
If sign-up fails → tell the user the email could not be authenticated and ask them to retry.
If verify fails → tell the user the code was invalid or expired, explain they get up to 10 attempts within 24 hours, and ask whether to retry the code or send a new one by calling sign-up again.
### Let's build your search.
**What kind of company are you looking for?**
Describe what they do, what space they're in, or what they build. (Firmographics like size, funding, and location are handled by your ICP profile.)
**Examples:**
- "Companies building AI agents"
- "Developer tools companies in the observability space"
- "Companies that sell to healthcare providers"
- "B2B SaaS companies in the payments space"
- "Companies building voice AI products"
Wait for user input. Use their exact words — do not reframe.
After the user responds, show:
### Building your search...
| | Question | Your answer |
|---|----------|-------------|
| ✅ | **What kind of company?** | {user's answer} |
| ⬜ | **What are they doing right now?** | (next) |
| ⬜ | **Any must-haves?** | (next) |
This is the timing layer — the difference between a static list and an inferred pain-point.
**What are they doing right now that would signal they need what you sell?**
This is what makes your search timely instead of generic. Without it, you get a static list of companies that match the description — with it, you get companies showing active pain.
**Examples:**
- "VP of AI joined to implement agent evals"
- "Building out their AI GTM function from scratch"
- "Migrating off Netsuite"
- "Hiring their first Head of Security"
- "Posting about switching CRM platforms"
Or type **"skip"** to search by company description only.
Wait for user input. Use their exact words — do not reframe.
After the user responds, show:
### Building your search...
| | Question | Your answer |
|---|----------|-------------|
| ✅ | **What kind of company?** | {answer 1} |
| ✅ | **What are they doing right now?** | {answer 2 or "skipped"} |
| ⬜ | **Any must-haves?** | (next) |
A deal-breaker condition — something the company MUST ALREADY HAVE in place. Companies without this won't appear regardless of how well they match.
**Any deal-breaker requirements the company must already have?**
Companies that don't meet this condition won't show up in results.
**Examples:**
- "Must have more than 5 SDRs"
- "Must have SOC2 compliance"
- "Must have majority of Engineering team in the US"
- "Must already have a DevOps team"
- "Must be using AWS"
Or type **"skip"** — no hard filters.
Wait for user input. Use their exact words — do not reframe.
After the user responds, show the completed search:
### Your search
| Question | Your answer |
|----------|-------------|
| **What kind of company?** | {answer 1} |
| **What are they doing right now?** | {answer 2 or "none"} |
| **Any must-haves?** | {answer 3 or "none"} |
Fetch available ICP profiles via bash "$API" GET /api/v1/icp/list.
If ICPs exist:
**ICP Profile** — filter results to companies matching your ideal customer.
{list each ICP by name and ID}
→ I'd recommend **{first/most relevant ICP name}** to qualify results.
Or type **"skip"** to auto-create a broad fallback ICP.
Wait for user input.
If the user types "skip":
name: auto-generated descriptive name like "Broad Default ICP"target_roles: ["Any"]employee_ranges: ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001-5000", "5001-10000", "10001+"]location: ["Any"]bash "$API" POST /api/v1/icp/create '<json_body>' with:{
"name": "<auto_generated_broad_icp_name>",
"target_roles": ["Any"],
"employee_ranges": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001-5000", "5001-10000", "10001+"],
"location": ["Any"]
}
No ICP selected, so I created a broad fallback ICP: **{name}** (ID: {id})
Using this ICP for your search.
If no ICPs exist:
You don't have an ICP profile yet. A quick one will make results much sharper —
it filters by company size, location, and the roles you're targeting.
1. **Quick setup** (recommended) — takes 30 seconds
2. **Skip** — auto-create a broad fallback ICP and continue
Wait for user input.
If quick setup chosen:
Fetch bash "$API" GET /api/v1/icp/options to get valid values for locations.
Present the fields:
### Quick ICP Setup
**1. ICP Name** — a short label (e.g., "Mid-market SaaS US")
**2. Target Roles** — job titles you sell to (comma-separated)
Example: "VP Engineering", "CTO", "Head of Data"
**3. Company Size** — pick from:
- `1-10`
- `11-50`
- `51-200`
- `201-500`
- `501-1000`
- `1001-5000`
- `5001-10000`
- `10001+`
**4. Funding Stage** — optional. Pick one or a range from:
- `Any`
- `Acquired`
- `Angel`
- `Closed`
- `Convertible Note`
- `Corporate`
- `Corporate Round`
- `Debt Financing`
- `Equity Crowdfunding`
- `Funding`
- `Grant`
- `No Funding Yet`
- `Non Equity Assistance`
- `Other`
- `Pre Seed`
- `Private Equity`
- `Product Crowdfunding`
- `Public`
- `Secondary Market`
- `Seed`
- `Series A`
- `Series B`
- `Series C`
- `Series D`
- `Series E`
- `Series F`
- `Series G`
- `Series H`
- `Series J`
- `Series Unknown`
- `Undisclosed`
- `Initial Coin Offering`
- `IPO`
- `Post IPO Debt`
- `Post IPO Equity`
- `Post IPO Secondary`
- `Venture`
You can leave funding empty, or provide a single stage, or a min/max range.
**5. Company HQ Location** — pick from:
{list locations as "value — label" from options}
### ICP Summary
**Name:** {name}
**Target Roles:** {roles}
**Employee Ranges:** {ranges}
**Funding:** {funding or "none"}
**Location:** {location}
Create this ICP? (yes / edit)
bash "$API" POST /api/v1/icp/create '<json_body>' with:{
"name": "<name>",
"target_roles": ["<role1>", "<role2>"],
"employee_ranges": ["<range1>", "<range2>"],
"min_funding": "<optional_min_funding_or_null>",
"max_funding": "<optional_max_funding_or_null>",
"employee_count_funding_config": "<AND_or_OR_or_null>",
"location": ["<location_code>"]
}
ICP created: **{name}** (ID: {id})
Using this ICP for your search.
If skip chosen instead of quick setup:
{
"name": "<auto_generated_broad_icp_name>",
"target_roles": ["Any"],
"employee_ranges": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001-5000", "5001-10000", "10001+"],
"location": ["Any"]
}
No ICP details provided, so I created a broad fallback ICP: **{name}** (ID: {id})
This keeps the search deployable while using the least restrictive valid ICP.
Present the full search configuration:
### Ready to deploy
| Field | Value |
|-------|-------|
| **Trait** | {trait} |
| **Activity** | {activity or "none"} |
| **Qualifier** | {qualifier or "none"} |
| **Signal Name** | {auto-generated descriptive name} |
| **ICP** | {selected icp name or auto-created fallback icp name} |
**Options** (all default off — set any before deploying):
- **Repeat daily** — re-run every day for continuous monitoring
- **Auto-enrich emails** — find work emails for discovered contacts
- **Credit limit** — cap spending on this signal
- **Auto-add to CRM** — push accounts to Salesforce/HubSpot automatically
⚡ *This will use credits from your plan.*
**Deploy?** (yes / edit / cancel)
Wait for user input.
If "edit" → ask what to change, update, re-confirm.
If "yes" → deploy:
bash "$API" POST /api/v1/signal/deploy/deep-company-search-agent '<json_body>' with:
{
"name": "<auto-generated name>",
"trait": "<trait>",
"activity": "<activity or null>",
"qualifier": "<qualifier or null>",
"icp_id": "<selected_or_fallback_icp_id>",
"run_daily": false,
"account_audience_name": "<signal_name> - Accounts",
"people_audience_name": "<signal_name> - People",
"max_credit_limit": null,
"enable_safe_crm_addition": false,
"auto_enrich_people_emails": false
}
Post-deploy:
Signal deployed: **{name}** (ID: {signal_id})
This agent is now searching for companies matching your pain point.
Results come in as they're found — say "check on {signal_name}" anytime.
Account audience: **{signal_name} - Accounts**
People audience: **{signal_name} - People**
The user can check anytime — during or after the signal run.
bash "$API" POST /api/v1/signal/ '{"signal_id": <signal_id>}'
### Signal: {signal_name}
**Status:** {status}
**{total_accounts} accounts found | {total_people} people found**
Pull the account audience to get IDs, then fetch full account details with signal reasoning.
bash "$API" GET '/api/v1/audience/<audience_id>' → returns account_idsbash "$API" POST /api/v2/account/batch '{"account_ids": [<ids>], "icp_people_page": 1, "icp_people_page_size": 100}'Present as a sheet. Activity is the headline — it's the "why reach out now." Trait and Qualifier are the qualifying context.
### Accounts — {signal_name}
| Account | Activity (why now) | Trait | Qualifier |
|---------|-------------------|-------|-----------|
| {company_name} | {signal reasoning from activity match} | {trait match} | {qualifier match} |
| ... | ... | ... | ... |
Pull the people audience to get IDs, then fetch full people details. People get account-level TAQ reasoning — the pain is at the company level, people are the contacts involved.
bash "$API" GET '/api/v1/audience/<audience_id>' → returns people_idsbash "$API" POST /api/v1/people/batch '{"people_ids": [<ids>]}'Present as a sheet. Activity is still the lead — it's the account-level "why now" for each person.
### People — {signal_name}
| Person | Role | Account | Activity (why now) | Trait | Qualifier |
|--------|------|---------|-------------------|-------|-----------|
| {name} | {role} | {company} | {account-level signal reasoning} | {trait match} | {qualifier match} |
| ... | ... | ... | ... | ... | ... |