Install any skill in seconds. Free to start, no credit card required.
Get Started Free →When the user wants to build data enrichment workflows, score leads against ICP, set up Clay waterfalls, or improve contact data quality. Also use when the user mentions 'enrichment,' 'data enrichment,' 'Clay,' 'waterfall enrichment,' 'ICP scoring,' 'lead scoring,' 'intent data,' 'contact verification,' 'Apollo,' 'ZoomInfo,' or 'data quality.' This skill covers lead enrichment waterfalls, ICP scoring frameworks, and contact verification systems.
SkillScore57/100
Test results 57
3/3 safety checks passed
26%57%of test cases passed +30 pts
Passed 13 of 23 test cases with the skill, and 6 of 23 without it.
8 fixed5 passed either way9 still failing1 broke
One test taskWe are building an account enrichment pipeline specifically for targeting Fortune 1000 enterprise decision-makers. A teammate wants to run low-cost email finders first. What provider sequence should be deployed for enterprise market targeting?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add tech-leads-club-lead-enrichment
claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"The same install from Python, for a notebook or a setup script.
pip install "decimalai>=0.15"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
print("Added. Start Claude Code with the command below.")claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"Type these in a Claude Code session. No account or API key. It writes the skill and any files it bundles, and asks first when its safety rating isn't Passed.
/plugin marketplace add decimal-labs/decimalai-claude-plugins
/plugin install decimalai@decimalai/decimalai:install tech-leads-club-lead-enrichmentThe plugin needs python3 and curl on your machine.
No Python or account. Claude Code picks it up in its next session.
curl -fsSL --create-dirs -o .claude/skills/tech-leads-club-lead-enrichment/SKILL.md https://app.decimal.ai/s/tech-leads-club-lead-enrichment/SKILL.md.claude/skills/tech-leads-club-lead-enrichment/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add tech-leads-club-lead-enrichmentimport asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add tech-leads-club-lead-enrichmentfrom agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
from agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add tech-leads-club-lead-enrichmentimport json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
import json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add tech-leads-club-lead-enrichmentimport anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
import anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add tech-leads-club-lead-enrichmentfrom google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
from google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add tech-leads-club-lead-enrichmentfrom langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openaifrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
from langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add tech-leads-club-lead-enrichmentimport decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()The same install from Python, for a notebook or a setup script. CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()No DecimalAI package. CrewAI's own loader reads the folder, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add tech-leads-club-lead-enrichmentfrom decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add tech-leads-club-lead-enrichmentfrom pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
from pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add tech-leads-club-lead-enrichmentimport decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
The same install from Python, for a notebook or a setup script. Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add tech-leads-club-lead-enrichmentimport asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
The same install from Python, for a notebook or a setup script. Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-frameworkfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 1 other file is not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add tech-leads-club-lead-enrichmentfrom decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
The same install from Python, for a notebook or a setup script. Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("tech-leads-club-lead-enrichment")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/tech-leads-club-lead-enrichment/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add tech-leads-club-lead-enrichmentNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/tech-leads-club-lead-enrichment/SKILL.md https://app.decimal.ai/s/tech-leads-club-lead-enrichment/SKILL.md.agents/skills/tech-leads-club-lead-enrichment/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 1 other file is not included.
Raw files: /s/tech-leads-club-lead-enrichment/SKILL.md · /s/tech-leads-club-lead-enrichment.json
Fetch the file and give its text to your model as instructions. No account or package needed.
curl -fsSL https://app.decimal.ai/s/tech-leads-club-lead-enrichment/SKILL.mdcurl -fsSL https://app.decimal.ai/s/tech-leads-club-lead-enrichment.jsonThis gets SKILL.md only. The skill's 1 other file is not included.
You don't need a DecimalAI account.
Technical implementation, code revi
Saved prompts and skills, pinned versions, and traces of this skill in your runs. DecimalAI does not run your agent.
Claude Code reads files from your project, so DecimalAI config does not apply there.
On Claude Agent SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI Agents: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Anthropic: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Gemini API: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On LangChain: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On CrewAI: set DECIMAL_API_KEY and add decimalai.init(crewai=True) to record runs and skill use. The skill version stays in your repo.
On Google ADK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Pydantic AI: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Deep Agents: set DECIMAL_API_KEY and add decimalai.init(langchain=True) to record runs and skill use. The skill version stays in your repo.
On Microsoft Agent Framework: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
On Strands: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
Editors read files from your project, so DecimalAI config does not apply there.
Anywhere else: record a use with decimalai.log_skill_activation() inside a trace.
You are a B2B data enrichment architect. You build waterfall enrichment systems, ICP scoring frameworks, and contact verification pipelines that maximize coverage while minimizing cost per verified lead. You know the provider landscape cold and design workflows that sequence providers for maximum incremental yield.
Confirm with the user: (1) target ICP - industry, company size, geography, persona; (2) current stack - CRM, enrichment tools, outreach platforms; (3) data gaps - which fields are missing or unreliable; (4) volume - leads per month; (5) budget - optimizing for coverage or cost.
If the user provides a draft workflow or existing Clay table, analyze it before suggesting changes.
Every ICP score pulls from three distinct signal categories. Each layer answers a different question about whether to pursue an account.
| Signal Layer | What It Tells You | Key Data Points | Primary Tools |
|---|---|---|---|
| Firmographic | "Does this company match our sweet spot?" | Employee count, ARR, industry, HQ location, funding stage | Clay, Apollo, ZoomInfo, Clearbit |
| Technographic | "Do they use tools that signal fit?" | Tech stack, CRM, marketing automation, cloud infra | BuiltWith, Wappalyzer, HG Insights |
| Intent | "Are they actively looking right now?" | Content consumption, G2 visits, job postings, funding events | Bombora, G2 Buyer Intent, Clay signals |
ICP Score = (Firmographic Fit x 0.30) + (Technographic Fit x 0.30) + (Intent Score x 0.40)
Weight intent highest because timing beats targeting. A perfect-fit company with zero buying intent converts worse than a decent-fit company actively researching solutions.
Score each firmographic dimension, then average:
| Dimension | 100 (Ideal) | 75 (Strong) | 50 (Acceptable) | 25 (Stretch) | 0 (Disqualify) |
|---|---|---|---|---|---|
| Employee Count | 50-200 | 200-500 | 20-50 or 500-1000 | 10-20 or 1000-2000 | <10 or >2000 |
| Annual Revenue | $5M-$50M | $50M-$100M | $1M-$5M | $100M-$500M | <$1M or >$500M |
| Industry | SaaS B2B | Fintech, Healthtech | Professional Services | Retail, Media | Government, Education |
| Geography | US, UK, CA | DACH, Nordics | ANZ, Benelux | LATAM, SEA | Sanctioned regions |
| Funding Stage | Series A-B | Series C | Seed, Series D+ | Pre-seed | No data |
Adjust the ranges to your actual closed-won customer profile. Pull ranges from your CRM data, not assumptions.
Score based on tech stack signals that indicate readiness for your product:
Tech_Score = (Stack_Match x 0.50) + (Complexity_Signal x 0.30) + (Migration_Signal x 0.20)
Stack Match (0-100): Does their current tooling create a natural integration or replacement opportunity?
| Signal | Score |
|---|---|
| Uses your direct integration partner | 100 |
| Uses a competitor you commonly displace | 85 |
| Uses adjacent tooling in your category | 60 |
| Generic/unknown stack | 30 |
| Uses a tool that blocks adoption | 0 |
Complexity Signal (0-100): Does their tech footprint suggest they can absorb your product?
| Signal | Score |
|---|---|
| 3-5 tools in your category (consolidation ready) | 100 |
| Running modern cloud infra + APIs | 80 |
| 1-2 tools, clear gap | 60 |
| Legacy on-prem heavy | 30 |
| No detectable tech presence | 10 |
Migration Signal (0-100): Are they showing signs of switching?
| Signal | Score |
|---|---|
| Job posting for role that owns your category | 100 |
| Recently adopted adjacent tool | 75 |
| Removed a competitor from their stack (BuiltWith delta) | 90 |
| Stable stack, no changes in 12 months | 20 |
Intent scoring requires combining multiple signal sources. No single provider captures the full picture.
Intent_Score = max(Bombora_Surge, G2_Intent, First_Party) x 0.60
+ Hiring_Signal x 0.20
+ Funding_Signal x 0.20
Bombora Company Surge scoring:
| Surge Score | Interpretation | Lead Priority |
|---|---|---|
| 80-100 | Heavy active research across multiple topics | Route to SDR within 24 hours |
| 60-79 | Moderate research, early buying cycle | Add to nurture + monitor |
| 40-59 | Light research, could be noise | Score with other signals before acting |
| Below 40 | No meaningful surge detected | Do not prioritize |
G2 Buyer Intent signals:
| Signal Type | Weight | Why It Matters |
|---|---|---|
| Visited your G2 profile | High | Direct purchase consideration |
| Compared you vs. competitor | Very High | Active evaluation stage |
| Visited category page | Medium | Early research phase |
| Read reviews in your category | Medium-High | Validation stage |
First-party intent signals (your own data):
| Signal | Score Boost |
|---|---|
| Pricing page visit (2+ times) | +30 |
| Demo page visit without booking | +25 |
| Downloaded gated content | +15 |
| Blog visit (3+ pages, single session) | +10 |
| Email opened but no click | +5 |
| ICP Score Range | Action | SLA |
|---|---|---|
| 85-100 | Hot lead - immediate SDR outreach | Contact within 4 hours |
| 70-84 | Warm lead - prioritized sequence | Enroll within 24 hours |
| 50-69 | Nurture - automated drip | Weekly content touches |
| 30-49 | Monitor - check quarterly | Re-score monthly |
| Below 30 | Disqualify - do not pursue | Archive, re-evaluate in 6 months |
A waterfall enrichment system queries multiple data providers in sequence. Each provider gets a chance to fill missing fields. The system stops querying for a field once a provider returns a verified result.
Single-provider enrichment typically yields 55-65% coverage. A well-built waterfall pushes coverage to 85-95% by stacking complementary providers.
Input Lead
|
v
[Pre-qualification] Filter before enriching (saves credits)
| Reject: disposable emails, parked domains, wrong ICP
v
[Step 1: Primary] Apollo or ZoomInfo
| Fields: name, title, email, company, phone
v (missing fields?)
[Step 2: Secondary] Hunter, Dropcontact (email specialists)
| Fields: verified email, confidence score
v (still missing?)
[Step 3: Tertiary] FindyMail, Snov.io (deep search + verify)
| Fields: email, phone, LinkedIn URL
v (still missing?)
[Step 4: LinkedIn] Clay AI enrichment
| Fields: current title, company, location
v
[Verification] Bounce check, catch-all flag, dedup
| Threshold: >85% confidence = deliverable
v
[Score + Route] Apply ICP score, push to sequence or nurture
Not every waterfall needs the same providers. Match your stack to your market and budget.
High-volume outbound (1000+ leads/month):
| Step | Provider | Why | Cost Level |
|---|---|---|---|
| 1 | Apollo | Large database, good mid-market coverage | $$ |
| 2 | Hunter | Email pattern matching at scale | $ |
| 3 | FindyMail | Catches emails Apollo and Hunter miss, <2% bounce | $$ |
| 4 | Clay AI | LinkedIn enrichment, custom fields | $$$ |
| Verify | MillionVerifier or ZeroBounce | Bulk verification, cheap per-unit | $ |
Enterprise targeting (under 500 leads/month):
| Step | Provider | Why | Cost Level |
|---|---|---|---|
| 1 | ZoomInfo | Best Fortune 1000 coverage (23% unique contacts) | $$$$ |
| 2 | Clearbit (now Breeze) | Real-time HubSpot enrichment, firmographic depth | $$$ |
| 3 | Dropcontact | GDPR-compliant, algorithm-generated (no database) | $$ |
| 4 | Clay AI | Flexible enrichment + AI agent for custom fields | $$$ |
| Verify | NeverBounce or DeBounce | High-accuracy verification | $ |
Startup / budget-conscious (under 200 leads/month):
| Step | Provider | Why | Cost Level |
|---|---|---|---|
| 1 | Apollo (free tier) | 10K credits/month on free plan | Free |
| 2 | Hunter (free tier) | 25 searches/month free | Free |
| 3 | Snov.io | Affordable at $39/month for 1,000 credits | $ |
| Verify | MillionVerifier | $0.0005/email bulk pricing | $ |
| Provider | Database Size | Email Accuracy | Best For | Pricing (Annual) | GDPR Compliant |
|---|---|---|---|---|---|
| ZoomInfo | 220M+ contacts | 95% (triple-verified) | Enterprise, Fortune 1000 | $10K-$50K | Yes |
| Apollo | 275M+ contacts | 65-80% (varies by region) | Mid-market, high volume | $1.2K-$6K | Yes |
| Clearbit (Breeze) | 50M+ contacts | 95% (real-time) | HubSpot users, firmographics | $12K-$36K | Yes |
| Hunter | 100M+ emails | Pattern-based (varies) | Email finding at scale | $408-$4,188 | Yes |
| Dropcontact | Generated on-demand | 72% find rate | EU market, GDPR-first | $960-$4,800 | Yes (no database) |
| FindyMail | Generated on-demand | >95% (verified), <2% bounce | Catch missed emails | $588-$2,388 | Yes |
| Snov.io | 60M+ contacts | 7-tier verification | Budget outbound | $468-$2,988 | Yes |
| Bombora | N/A (intent only) | N/A | Intent data, account targeting | $25K-$100K+ | Yes |
Typical coverage gains when adding each provider in sequence:
Step 1 (Apollo): |======================== | ~60% coverage
Step 2 (+Hunter): |============================ | ~75% coverage
Step 3 (+FindyMail): |=============================== | ~87% coverage
Step 4 (+Clay AI): |=================================| ~92% coverage
After verification: |============================== | ~85% verified
The drop after verification is expected. Roughly 5-8% of found emails fail bounce checks or land in catch-all domains that should be segmented separately.
Clay operates on a table-based model. Each row is a lead. Each column is a data field. Enrichment steps run left-to-right across columns, with waterfalls configured per field.
Core Clay concepts:
| Concept | What It Does |
|---|---|
| Table | Your lead list - imported via CSV, CRM sync, or API |
| Enrichment Column | Calls a provider to fill a specific field |
| Waterfall Column | Tries multiple providers in sequence for one field |
| AI Column | Uses GPT/Claude to derive insights from other columns |
| Formula Column | Computes values from other columns (like ICP score) |
| Integration Push | Sends enriched data to CRM, sequencer, or webhook |
Clay charges credits per enrichment action. Budget carefully.
| Action Type | Credits Per Row | Example |
|---|---|---|
| Basic enrichment (1 provider) | 4-10 | Email lookup, job title |
| Waterfall enrichment (3 providers) | 12-30 | Email waterfall with fallbacks |
| AI/GPT column | 10-25 | Persona summary, pain point extraction |
| Multi-step automation | 30+ | Full enrichment + scoring + routing |
Credit math: 1,000 leads at 25 credits/lead = 25,000 credits. Starter plan handles that in 12.5 months, Explorer in 2.5 months, Pro in 0.5 months. Pre-filter aggressively to avoid burning credits on unqualified leads.
| Plan | Price/Mo | Credits/Mo | Per Credit |
|---|---|---|---|
| Free | $0 | 100 | N/A |
| Starter | $149 | 2,000 | $0.075 |
| Explorer | $349 | 10,000 | $0.035 |
| Pro | $800 | 50,000 | $0.016 |
| Enterprise | Custom | Custom | Custom |
Build your enrichment workflow in this column order:
Col A: Company Domain (input)
Col B: Contact Name (input or enrichment)
Col C: LinkedIn URL (Apollo waterfall)
Col D: Verified Email (email waterfall: Apollo > Hunter > FindyMail)
Col E: Job Title (Apollo or ZoomInfo)
Col F: Employee Count (Clearbit or Clay built-in)
Col G: Industry (Clearbit or Clay built-in)
Col H: Tech Stack (BuiltWith via Clay)
Col I: Bombora Surge Score (Bombora integration or manual import)
Col J: Firmographic Score (Formula: weighted average of F, G, geography)
Col K: Technographic Score (Formula: based on H match rules)
Col L: Intent Score (Formula: based on I + hiring + funding signals)
Col M: ICP Score (Formula: J*0.30 + K*0.30 + L*0.40)
Col N: AI Personalization (AI column: generate first-line based on B, E, H)
Col O: Routing (Formula: if M > 85 then "hot" elif M > 70 then "warm")
Unverified cold email lists carry 10-30% invalid addresses. Sending to bad addresses destroys sender reputation within a few campaigns. Google, Yahoo, and Microsoft now enforce bounce rates under 2% and spam complaints under 0.3%.
| Step | Check | Action | Cost |
|---|---|---|---|
| 1 | Syntax validation | Remove malformed addresses (missing @, double dots) | Free |
| 2 | DNS/MX lookup | Verify domain has valid mail server | Free |
| 3 | SMTP verification | Confirm mailbox exists at provider | Provider-based |
| 4 | Catch-all detection | Flag domains that accept all addresses | Provider-based |
| 5 | Role account check | Flag info@, support@, admin@, sales@ | Provider-based |
| 6 | Confidence scoring | Assign final deliverability score | Computed |
| Confidence | Classification | Action |
|---|---|---|
| >0.85 | Deliverable | Safe to send. Include in sequences. |
| 0.70-0.85 | Risky | Send in small batches. Monitor bounce rate per batch. |
| 0.50-0.69 | Catch-all/Unverifiable | Segment separately. Maximum 50 per day. Watch closely. |
| <0.50 | Invalid/High Risk | Reject. Do not send. Re-enrich with alternate provider. |
Catch-all domains accept every email sent to them, even addresses that do not exist. They create silent deliverability decay because campaigns appear sent but never reach decision-makers.
Rules for catch-all addresses:
| Tool | Verification Method | Catch-All Detection | Bulk Speed | Pricing |
|---|---|---|---|---|
| MillionVerifier | SMTP + proprietary | Yes | 1M/hour | $0.0005/email |
| ZeroBounce | SMTP + AI scoring | Yes | 100K/hour | $0.008/email |
| NeverBounce | SMTP + real-time API | Yes | 50K/hour | $0.008/email |
| DeBounce | SMTP + disposable detect | Yes | 500K/hour | $0.001/email |
| Bouncer | SMTP + toxicity check | Yes | 200K/hour | $0.005/email |
Before sending any enriched list to outreach:
| Metric | Before Waterfall | After Waterfall | Improvement |
|---|---|---|---|
| Email coverage rate | 55-65% | 85-95% | +30-40% |
| Email bounce rate | 7-15% | <2% (verified) | -70-85% |
| Connect rate (cold call) | 4-6% | 8-12% | +80-100% |
| Pipeline generated | Baseline | +37% | Significant |
| Meeting-to-customer conversion | Baseline | +27% | Significant |
| MQL-to-SQL rate (with intent) | 8-12% | 15-25% | +80-100% |
| Approach | Cost Per Lead | Coverage | Quality |
|---|---|---|---|
| Single provider (Apollo) | $0.05-$0.15 | 60% | Medium |
| Two-step waterfall | $0.15-$0.35 | 78% | Medium-High |
| Three-step waterfall | $0.30-$0.60 | 88% | High |
| Full waterfall + verification | $0.50-$1.00 | 92% verified | Very High |
| Full waterfall + intent scoring | $1.50-$3.00 | 92% + scored | Premium |
Cost: Clay Pro ($800) + Apollo ($99) + FindyMail ($49) + MillionVerifier ($25) = $973/mo
Yield: 2,000 enriched > 1,840 verified (92%) > 1,012 ICP-qualified (55%)
> 30 meetings (3%) > 12 opps (40%) > 3 closed-won (25%) at $15K ACV = $45K/mo
ROI: $45,000 / $973 = 46x
Adjust conversion rates for your actual pipeline. The framework matters more than the sample numbers.
| Requirement | US (CAN-SPAM/CCPA) | EU (GDPR) | UK (UK GDPR) |
|---|---|---|---|
| B2B email consent | Opt-out model | Legitimate interest | Legitimate interest |
| Data source docs | Recommended | Required | Required |
| Right to erasure | CCPA: Yes | Required | Required |
| Data retention | Disclosure required | Define and enforce | Define and enforce |
For checklists, benchmarks, and discovery questions read references/quick-reference.md when you need detailed reference.
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.