Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Mine the highest-converting ad angles from customer reviews, Reddit complaints, support tickets, and competitor ads. Extracts actual pain language, competitor weaknesses, and outcome phrases that real buyers use. Outputs a ranked angle bank with proof quotes and recommended ad formats per angle.
SkillScore45/100
Test results 45
3/3 safety checks passed
27%45%of test cases passed +18 pts
Passed 10 of 22 test cases with the skill, and 6 of 22 without it.
8 fixed2 passed either way8 still failing4 broke
This benchmark measured an earlier version of the skill.
One test taskWhen gathering customer sentiment and discussions from Twitter, Instagram, or TikTok posts, should we default to running web searches or use a specialized social API tool?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add gooseworks-ai-ad-angle-miner
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("gooseworks-ai-ad-angle-miner")
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 gooseworks-ai-ad-angle-minerThe 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/gooseworks-ai-ad-angle-miner/SKILL.md https://app.decimal.ai/s/gooseworks-ai-ad-angle-miner/SKILL.md.claude/skills/gooseworks-ai-ad-angle-miner/SKILL.mdThis gets SKILL.md only. The skill's 2 other files are 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 gooseworks-ai-ad-angle-minerimport 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerfrom 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerimport 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerimport 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerfrom 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerfrom 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerimport 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerfrom 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerfrom 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add gooseworks-ai-ad-angle-minerimport 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add gooseworks-ai-ad-angle-minerimport 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add gooseworks-ai-ad-angle-minerfrom 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("gooseworks-ai-ad-angle-miner")
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/gooseworks-ai-ad-angle-miner/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/gooseworks-ai-ad-angle-miner/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 2 other files are 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 gooseworks-ai-ad-angle-minerNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/gooseworks-ai-ad-angle-miner/SKILL.md https://app.decimal.ai/s/gooseworks-ai-ad-angle-miner/SKILL.md.agents/skills/gooseworks-ai-ad-angle-miner/SKILL.mdThis gets SKILL.md only. The skill's 2 other files are not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 2 other files are not included.
Raw files: /s/gooseworks-ai-ad-angle-miner/SKILL.md · /s/gooseworks-ai-ad-angle-miner.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/gooseworks-ai-ad-angle-miner/SKILL.mdcurl -fsSL https://app.decimal.ai/s/gooseworks-ai-ad-angle-miner.jsonThis gets SKILL.md only. The skill's 2 other files are not included.
You don't need a DecimalAI account.
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.
Summary. Research advertising promises and match them to creatives the brand can make. Video research produces a structured bank the script writer can reuse, with stable angle ids, separate product facts and customer language, and template compatibility. Research scores rank test candidates; they do not predict conversions.
An ad is copy plus creative. This skill finds the angles real buyers respond to and turns each into an ad idea the user can make:
Core principle: combine audience relevance with a supported product promise and a feasible creative. Customer language, demonstrations, first-party performance and advertiser persistence provide different evidence. Long-running ads and variants are observations, not proof of profit. A product-led angle can start from verified facts without reviews; label missing evidence.
Do only the work the chosen output needs. Copy and static never search for videos or read video formats. Copy never looks at templates. Video reuses available reviews for language and insight; collect more only when the angle needs them. A video request may name a selected template or angle: preserve both.
scrapecreators-api,
competitor-ad-intelligence) and web search. Static and video ideas then describe the layout or
format in words instead of naming a library entry, and there is no hand-off step.Read it from the request:
| The user says | Output |
|---|---|
| static, image ads, banners, "what image ads" | static |
| video, UGC, reels, TikTok, "what video should I make" | video |
| copy, headlines, primary text, "what should our ads say" | copy |
| "ads" or "angles" with no hint | ask once: "Static ad ideas, video ad ideas, or just the copy?" |
The user can pick more than one (for example static and video); then run the union of their sources, once. Never widen the scope on your own.
| Source | static | video | copy |
|---|---|---|---|
| Brand context (1-0) | yes | yes | yes |
| The brand's own ads (1A) | yes | yes | yes |
| Competitor ads (1B) | yes, image ads first | yes, video ads first | yes, the copy |
| Customer voice: reviews + comments (1C) | yes | reuse reviews; comments on top posts | yes |
| Organic short-form reach (1D) | no | yes | no |
| Internal data (1E) | if provided | if provided | if provided |
| Reddit and forums (1F) | only if asked | only if asked | only if asked |
| Template library (2.5) | yes | no | no |
| Video format catalogue and full recipes (2.5) | no | yes | no |
Take what the request and the brand context already answer; ask only for what's missing, in one message:
Never invent a customer, a result or a claim: an angle may only promise what the brand's own facts support.
Run only the sections Phase 0B selected. ScrapeCreators calls go through scrapecreators-api
(GooseWorks: data_call_provider with provider scrapecreators, GET). Each is billed per call:
before the first one, say roughly how many you'll run and ask one yes/no. Free sources never need
asking. Large results are saved to a file by some hosts: request a full page and parse the saved
file rather than paging in small pieces.
With the GooseWorks MCP: brand_read (one brand in the org means use it and say which), with
sections summary, products, competitors, accounts and learnings (the reply is large: parse the
saved file); add kit when you need claims,
voice or photos. Note what it sells, who buys it, its claims and can't-say rules, its offers, which
products have clean photos (check the files: an SVG logo or a small thumbnail is not a clean
product photo), and whether it has screen recordings or footage. competitor_read lists tracked
competitors; with none, its suggestions view names likely ones. Say them in one line and carry on.
What the brand already runs decides what is new.
ads_template_read in competitor mode, one tracked competitor at a time
(filter by its source id). Rows are heavy; keep the source ad id, primary text, CTA, start and
end dates and ratio. Today most imported ads are images; their copy is still evidence.What buyers say in their own words. This is what keeps angles from being guesses.
The brand's own reviews: its product pages (review widgets often load by script, so a plain web fetch shows only a few; fetch the raw page HTML and read the review blocks and any "customers say" summary in it), its TikTok Shop reviews if it sells there (/v1/tiktok/shop/product/reviews), its Amazon listing (web search and fetch). Keep 4-5 star reviews for outcomes and proof, and 1-3 star reviews for objections to answer.
Competitors' bad reviews: 1-2 star reviews of the top 2 competitors' products, from the same kinds of sources. These suggest possible gaps to investigate. Claim a gap only when this product independently supports the promised difference.
Comments on what's working: most ads link to a landing page, not a post, so their comments usually can't be read. Read comments instead on:
Comments paths: TikTok /v1/tiktok/video/comments, Instagram /v2/instagram/post/comments, YouTube /v1/youtube/video/comments, Facebook /v1/facebook/post/comments. Look for questions, objections and "I switched because…".
Keep every quote verbatim with its link. Never paraphrase a quote into something the buyer didn't say.
What is getting earned reach right now.
Free first: the competitor dossiers (competitor_read with a slug) and social_inspiration_library
/ social_inspiration_search. These are often empty; then go to the paid searches.
Paid searches (one yes/no for the batch). Terms: the user's own first, then the category, the main problem it solves, each competitor's name.
| Platform | Path | Query | Notes |
|---|---|---|---|
| TikTok | /v1/tiktok/search/keyword | query, date_posted last-3-months, sort_by most-liked | About 2MB per call: parse it; keep url (tiktok.com/@author/video/id), author, followers, statistics.play_count, create_time, desc, commerce_info |
| Instagram Reels | /v2/instagram/reels/search | query, date_posted last-month | Google-indexed, best-effort, about 9 results a page; no follower count |
| YouTube Shorts | /v1/youtube/search | query, type shorts, nothing else | Adding uploadDate or sortBy with type shorts returns nothing. Rows have only url, title and views: for the 3-5 you'd cite, call /v1/youtube/video for channel, publishDate and isPaidPromotion. YouTube evidence is evergreen: cite its date |
| X | none | none | No X keyword search: use competitor_research (mentions) with platform x, or /v1/twitter/user-tweets for a handle |
The full list is the official OpenAPI (docs.scrapecreators.com/openapi.json). If a call errors, read it there; never guess a path.
Keep vertical videos only, far above their account's usual views, from the last ~90 days.
Watch the 3-5 strongest (the watch skill, or social_inspiration_watch for saved posts). When
neither is available, read the transcript (YouTube /v1/youtube/video/transcript; otherwise the
caption and first spoken line) rather than guessing from the title.
Support tickets, NPS comments, sales call notes the user provides. Treat them as customer voice.
Only when the user asks, or for a product whose buyers mainly talk there (developer tools, some
software). Use reddit-post-finder or /v1/reddit/search. A thread is one person's view: it counts
as customer voice only when the same point also shows up in reviews or comments.
Reviews and comments are customer voice, a third kind of evidence. Label them as such.
Read buyer case and supported product role.
Before naming an angle, extract a specific current consumer task or decision and
explain why this exact product can help. Record the buyer's inputs, current approach,
constraint and desired output, plus the supported product action and useful role.
Keep source limits and authored scenarios explicit. Carry these as buyer_case and
product_role in the video handoff; a generic pain label or ingredient list is not
enough. Preserve human feedback separately from model ranking.
| Category | What to look for |
|---|---|
| Pain | Specific frustrations with the status quo or competitors |
| Outcome | Results buyers describe in their own words |
| Identity | How buyers describe themselves or want to be seen |
| Switching | Why people left a competitor |
| Proof | Outcomes, ratings or credentials buyers and the brand can back up |
| Contrast | Old way vs new way, them vs us |
| Objection | The doubt that stops a purchase, answered |
For each angle record: the one-sentence angle, relevant verbatim quotes with links when available, and the sourced product facts or observations that support it. Do not invent quotes to meet a quota or require a complaint for a product-led discovery angle. State which kinds of evidence back it (customer voice, product facts, organic reach, sustained ads), whether the brand already runs it (1A: measured winner, persistent, inactive, or never observed) and the competitor gap it exploits, if any.
Every output gets the words: a headline (8 words or fewer for static, 12 or fewer as a video hook) and 1-2 sentences of primary text, in the brand's voice.
Claims: only what the brand's own data says (certifications, guarantees, ingredients, offers), checked for the exact product the ad shows: two products of one brand can differ (one has no added sugar, the other does). Flag anything the brand should approve, such as review counts, health benefits, price comparisons or a named person, rather than writing it as fact. When the brand's sources disagree (two different numbers for the same claim), flag both.
The template library grows every week, so never rely on a remembered list of templates or layouts.
ads_template_read in query mode, with the brand id and that sentence as the
query. It searches the whole library by meaning and returns each match with its description,
search tags and a score, so templates added tomorrow are found the same way. Rank by score.
Run one search per angle; when the best similarity is under about 0.5, try a second phrasing.goose-ads as a
community ad id, a template as a template id.Read the live video format catalogue for the brand. Only listed formats can be made. When the brief already chooses a template, use it. For plausible candidates, fetch the full template recipe before calling the idea make-ready: a card description is not a production contract.
Match the angle to the recipe's story mechanism, speakers, timing, text slots, proof device, permitted visuals and required assets. Keep the quoted catalogue description for display, and record the actual template id and compatibility reason. A physical demo needs a real product; a screen demo needs usable recordings; a silent reveal needs a visual payoff. Do not turn all angles into testimonials. An unmet essential input makes the pair provisional or incompatible.
For dialogue directions, return an observed same-format reference alongside the angle. Reuse collected sources before retrieving more. A caption, format description or imagined beat map cannot establish human dialogue.
Street ads require a complete commercial interaction, with full visual timeline and
spoken exchange inspected. Match physical/service/digital offering and the actual
interaction (sampling, mic-only conversation, or challenge). Preserve source, observation
method/limits, timestamped words and actions, visible setup, participation reason, hook,
brand connection, payoff, and unseen recruitment as explicitly unknown. Label paraphrases
and retain full transcript evidence. Partial hooks and editorial radio excerpts cannot
fill this gap; seed summaries are source leads until inspected in full. The selected
render-street-interview skill's guide and writer's files reference define the record.
For podcasts, an appropriate editorial interview can provisionally teach turn structure, with commercial and delivery limitations recorded. Neither real performers nor an observed transcript establishes human authorship or conversion performance.
Carry audience, objective, offer, CTA and exact product through this match. When the angle or format is fixed, do not replace it to improve a ranking. Report a conflict and suggest a compatible execution. Never infer that a renderer can make a scene from a generic model name.
No template or format. Give 2-3 headline and primary-text variants per angle instead.
Adapt the pattern, never copy: take the shape, structure and angle, never another brand's words, claims, faces, footage or offer. Spread the list: no more than 3 ideas on one template or format, and no more than 3 on one angle (variants of one angle count toward that 3).
| Factor | Weight | Description |
|---|---|---|
| Evidence | 40% | How many kinds back it (customer voice, organic reach, sustained ads) and how strong each is |
| Gap | 20% | Never run by the brand, and weak or absent in competitors' ads |
| Fit | 20% | The brand can claim it with its own facts, and buyers like its own customers say it |
| Make-ready | 20% | The template or format fits and the brand has what it needs (copy: 100%) |
Reject unsupported product promises and impossible angle–template pairs before scoring. Score the remaining pairs out of 100 and rank as research priorities. These weights and caps are heuristics, not calibrated probabilities of performance. Keep a measured first-party winner separate from the research score. Do not pad the list when evidence is thin.
Print one table in the chat, best first, with up to 10-15 distinct, supported ideas. Every idea needs at least one link a tool actually returned; no link, no idea.
Static:
| # | Headline | Primary text | Angle | Template (why it fits) | Evidence | Needs | Score |
|---|
Video:
| # | Hook | Angle | Format (quoted card) | Evidence | Needs | Score |
|---|
Copy:
| # | Angle | Headline variants | Primary text | Evidence | Score |
|---|
In Evidence, label each link: customer voice, organic (with views vs usual), or paid (with days running and variants).
Under the table:
For video, read the video-handoff reference and save video-angle-bank.v1 with stable angle ids, brand and product scope, audience/objective/offer/CTA, sourced facts, verbatim quotes, observed references and compatible template ids. Save it with the workspace file tools in the brand and product's video-scripts area as angle-bank.json, beside customer-words.json. Also keep a copy in this run. If workspace writes fail, retain the run copy and pass it directly; say cross-session reuse is unavailable. Do not pretend a bank was persisted.
A human-readable angle-bank Markdown and ideas JSON remain useful for static and copy output. For video they may accompany the shared bank, but do not replace it. The script writer consumes the bank rather than trying to reconstruct research from a chat table.
Then ask: "Which ones should I make? Pick up to 5, or say 'the top 3'." (Copy: skip this.)
For the picked ideas, with no manual step in between:
goose-ads skill as the source and the brief.video_create (brand id, style set to the template
id, and the idea's products). Never put several ideas in one plan: each plan holds one idea.
Then make them one after another with goose-video-local; each idea is that plan's brief.
Pass the complete selected idea and shared bank into goose-video-local, including the chosen
angle id, product id, template id, evidence and proof requirements. Its script step must fetch
write-video-ad-script and prepare a validated angle context; never pass only the hook. Keep raw
buyer records outside remixable review data. The local-template path needs a terminal agent;
hosted/server formats have their own runtime and require the same strategy contract there.Up to 5 per request; offer the rest after. Each paid step of making an ad is approved before it runs.
brand_read, competitor_read, competitor_research,
ads_template_read, social_inspiration_library, social_inspiration_search,
data_call_provider, video_formats, video_createscrapecreators-api: ad libraries, comments, reviews, social searchcompetitor-ad-intelligence: deeper teardown of one competitor's ads, when askedcomment-mining: structured mining of a long comment threadreddit-post-finder: only when Reddit is asked for (1F)write-video-ad-script skill — consumes the video handoff and fits it to the recipe.Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.