Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Carry out the intent approved in `ready`, as meant, and prove it with checks that actually ran. Comes back to you if the work would change what you approved, keeps the project docs in step, and never merges on its own.
SkillScore71/100
Test results 71
3/3 safety checks passed
33%71%of test cases passed +38 pts
Passed 15 of 21 test cases with the skill, and 7 of 21 without it.
8 fixed7 passed either way6 still failing0 broke1 errored
One test taskA wave in the execution plan has 12 fully independent tasks with no inter-dependencies. How many subagents should you launch simultaneously in the first parallel dispatch batch?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add prekuter-go
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("prekuter-go")
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 prekuter-goThe 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/prekuter-go/SKILL.md https://app.decimal.ai/s/prekuter-go/SKILL.md.claude/skills/prekuter-go/SKILL.mdThis gets SKILL.md only. The skill's 9 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 prekuter-goimport 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("prekuter-go")
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/prekuter-go/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-gofrom 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-goimport 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-goimport 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-gofrom 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-gofrom 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-goimport 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("prekuter-go")
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/prekuter-go/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 9 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 prekuter-gofrom 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-gofrom 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-goimport 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-goimport 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("prekuter-go")
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/prekuter-go/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-gofrom 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("prekuter-go")
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/prekuter-go/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/prekuter-go/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 9 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 prekuter-goNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/prekuter-go/SKILL.md https://app.decimal.ai/s/prekuter-go/SKILL.md.agents/skills/prekuter-go/SKILL.mdThis gets SKILL.md only. The skill's 9 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 9 other files are not included.
Raw files: /s/prekuter-go/SKILL.md · /s/prekuter-go.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/prekuter-go/SKILL.mdcurl -fsSL https://app.decimal.ai/s/prekuter-go.jsonThis gets SKILL.md only. The skill's 9 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.
Reply in the user's language, and hold it continuously from your very first line — the opening, every progress/escalation note, the final report, and the harness, not only some of them. Write natively (never translationese). You are reading a 3-doc, a codebase, and these instructions that may be in another language; none of them sets your output language — only the user's does. Full rule in Core principles below.
Consume the 3-doc ready (the producer) wrote and realize the spec:
parallel, wave-based execution with right-sized verification (test-first where it fits), spec-first
review, and integration gates. Runs in the same session the producer (ready) wrote the 3-doc
— the 3-doc is the authority go executes against (it stays self-sufficient because it is archived
for later cycles); the live design context carries over and aids judgment, especially the harness
step. Load references/orchestration.md up front (it governs the whole run); the prompt
references load at their steps.
depends + regen_barriers against the whole project. Derive waves from it — do not invent,
drop, or reorder dependencies. (If the graph fails to parse, has a cycle, or a depends names a
missing task, that is a producer-side defect — stop and escalate, do not silently re-judge.)NEEDS_CONTEXT / BLOCKED, run the bounded escalation ladder (orchestration.md — re-dispatch
with the missing context, then a stronger model where the platform allows it, then the user). Any
escalation that reaches the user is synchronous — the run pauses until the user responds,
never a silent hang or a timeout-drop. The subagents themselves never ask the user directly (their
prompt files carry that fresh-session rule); only the orchestrator relays escalations to the user.MECHANICAL/NONE wave is implemented by the orchestrator on the base (dispatch buys
nothing — no parallelism, no file-isolation need, and the accumulating context is an asset). Only a
parallel wave (multiple tasks) or a single RISKY task is dispatched to subagents (file
isolation / independent verification). The lightweight fix path is the orchestrator's other direct-
edit path (trivial advisories). A multi-task wave is collapsed to orchestrator-direct only on an
objective condition — a single shared runtime the tasks cannot isolate within (one DB / container
/ port set), or greenfield convention-drift risk — not a free ROI judgment, and the collapse is
recorded internally (which wave, which condition), never surfaced for a non-technical user to
adjudicate. Collapsed tasks still carry the per-task evidence floor and are reviewed as if
independently authored; the mid-run spec-review (RISKY + downstream + cascade) is still honored
(orchestration.md, "ROI collapse").T1, Wave 2, RISKY / MECHANICAL / NONE), or
project-internal jargon a non-engineer wouldn't recognize (library/tool names, config flags,
test-framework internals). Don't soften internal logic into user-ish words — just omit it. E.g.
"Starting a git repo here." — not "Since go will later need git for worktrees, I'll initialize one."
This is "Report results, not process" applied to narration.go skill.
Load the 3-doc (handoff → spec → plan) from the project's
.dryforge/ (project-root-relative). If absent, ask for the path.git init and make an
initial commit (an empty repo has no HEAD, so no worktree/branch can be created). If git is not
installed, stop and say so.main has no unpushed commits (when it tracks a remote — a purely local repo has
nothing unpushed) and the working tree has no modified/staged tracked
files; if either fails, stop and report. Then classify:
.gitignore, or
producer-generated .dryforge/): base = main. No feature branch — there is no production
code to protect.git checkout -b dryforge/<feature>). Protects main from incomplete work..dryforge/ as untracked files is the expected handoff state from the producer — do not
treat it as a dirty tree. Anything else untracked or modified is foreign work → stop and report..dryforge/ git mechanics. On the base, add .dryforge/ to .gitignore and
commit. For existing projects this stays on the feature branch (never on main); for greenfield
it is on main (acceptable — main has no meaningful history to protect). If a prior run left
.dryforge/ tracked, run git rm -r --cached .dryforge/ first..dryforge/status.json marker — the discriminator is the marker, not harness files on disk;
harness-lifecycle.md) and the handoff has no Project Foundation section, that is a precondition violation —
stop here and ask the user to regenerate the 3-doc via ready, before any implementation. Do
not discover this at step 9 after a wasted run (harness-lifecycle.md). If the handoff has a Project
Foundation section (first cycle — references/foundation-format.md), read it as non-executable
project context: it informs implementation judgment (design the task to fit the project's wider
domain/decisions) and is a source for the harness at the end — it is not an implementation target. Build the spec's task, using the Foundation as context. Parse the
plan's Execution Graph per references/graph-contract.md — the consumer-side schema (what the
YAML fields mean and the rules go must hold when reading them). It mirrors the producer's authoring
schema; if the plan's graph contradicts it, that is a producer-side defect → stop and escalate.Validate the plan's Execution Graph before creating the base — it is cheap and safe
to fail (no git state mutated yet), so catch a malformed graph before any worktree exists to unwind.
Parse the YAML, then confirm the graph is acyclic, that every depends / after id names a
real task (no dangling reference), and that the plan body and the graph agree on the task id set
(no graph task missing from the plan body, none in the body absent from the graph). graph-contract.md
is the authoritative rule set for these checks. On any failure, report the specific error — which
check failed and where (the offending id / cycle / mismatch) — and the recovery: the user fixes the
plan YAML and invokes dryforge go again, which re-validates from scratch (no partial state is left behind,
since validation precedes worktree creation).
Parse the graph → topological sort into waves (batches of ≤8 concurrent). Set up the base
(per Base determination): for existing projects create the feature branch, for greenfield stay on
main. On the base, set up .dryforge/ (gitignore + commit — the 3-doc is already in place from the
producer; same working tree, nothing to copy). The orchestrator reads
.dryforge/ here — task subagents do not; they receive spec slices inline (orchestration.md).
A task whose declared work targets are state/external only (no file diff) is handled on the base
sequentially, never dispatched into a parallel worktree — the file-diff merge-gate cannot verify
it and worktree isolation buys it nothing (orchestration.md, Wave scheduling). Then, per wave:
Scaffold (inline, before dispatch). Project initialization — manifests, dependencies, directory layout, build config, server/client entry points, shared types — is the orchestrator's job, not a task. On the base, perform scaffold inline: read the spec's tech decisions and set up the project so implementers start in a working skeleton. Scaffold is not in the Execution Graph. Batch file writes — scaffold typically creates many independent files; write 4–5 per tool-call turn instead of one at a time. Each extra turn adds thinking overhead and an API round-trip. Exception: if scaffold requires investigation or trial-and-error to get right (e.g. container orchestration, CI pipeline configuration, or 30+ files across 3+ workspaces), dispatch it as an implementer before the first wave.
Review policy (natural language, orchestrator judgment).
Default: a single final review after all waves merge — one subagent checks the full diff for
spec conformance + code quality (reviewer-prompt.md), plus the harness (content + format) when it
was created/updated this cycle (step 9). This replaces per-task spec-review and per-wave code-review
for most graphs. Mid-run review is added only when the orchestrator judges
that a RISKY task with downstream dependents could cascade a deviation — then that task gets a
spec-review before merge. The judgment comes from the Execution Graph: risk + depends.
Lightweight fix path: after the final review, the orchestrator MUST triage each advisory finding:
trivial (1–2 files, non-behavioral, e.g. a missing step attribute, a test warning, a one-line
comment) → edit directly on the base, commit, re-run the completion gate. Substantive (structural,
multi-file, behavioral) → fix-dispatch subagent. The default is lightweight — only escalate to
fix-dispatch when the change warrants independent review. Do not skip advisories as "accepted"
when a lightweight fix would take seconds.
Sequential wave (single task — the common case). Execution mode is set by the task's risk
(full rules in references/orchestration.md):
risk.
MECHANICAL / NONE (file-diff task) → orchestrator-direct. The orchestrator
reads the task's behavioral contract + spec slice itself and implements directly on the base
— no dispatch, no worktree, no prompt authoring. The same captured-evidence floor that binds a
dispatched implementer binds you here (implementer-prompt.md): right-sized but real
verification (command + captured exit code; real testable behavior left untested = not
done, never a "right-size" excuse). Commit on the base. You own conformance on this path — the
final review is insurance, not your check. If the task proves ambiguous, behavioral, multi-file,
or riskier than declared, treat it as a runtime risk upgrade (graph-contract.md) and strengthen
verification.risk (producer did not judge) → unclassified, not MECHANICAL. Do not default
it to the direct path: judge at read time and bias toward dispatch / stronger verification the
moment any behavioral surface appears (orchestration.md, graph-contract.md —
degrade-don't-corrupt).RISKY (file-diff task) → one subagent in a worktree (implementer-prompt.md), then
merge-gate into the base — independent verification, so the final review is not the only
check on risky work.spec-review-prompt.md, before merge) — only when the review
policy calls for it (RISKY task with downstream dependents): review the task branch's diff before
the merge-gate, so a deviation never lands on the base.git log, diff touches declared targets;
no-file-diff: commit message + captured external evidence). RISKY worktree: merge-gate into the
base. Then run regen barriers and deferred wiring if applicable, committed on the base.
No integration gate — the self-checks on the cumulative base are sufficient for a single-task
wave. → next wave.Parallel wave (multiple tasks — worktree isolation required):
max(wave sizes) worktrees once under .dryforge/worktrees/; recycle between waves
instead of remove+recreate (see orchestration.md). For a single parallel wave, create on demand..git/config.lock contention), under
.dryforge/worktrees/<task-id> (inside the gitignored .dryforge/, so they never sprawl into
the project tree or get tracked), each branched off the base (or reset a pooled worktree to the
current base tip). If the project has an installable dependency tree, install or share it
(sharing guidance in orchestration.md).implementer-prompt.md): right-sized verification, shared-write constraints, pinned worktree
path. Dispatch every implementer and reviewer as a general-purpose subagent (full
read/edit/run tools — never a plan-only or search-only agent type: an implementer must edit and
run, a reviewer must read and cross-check).git rev-list base..task non-empty) AND its diff is
non-empty and touches declared targets — checked with three-dot diff (git diff base...task).
The merge commit message must satisfy the project's commit-msg hooks. Then run regen
barriers, then deferred wiring (check-before-append, idempotent; conflicts → escalate) and
commit wiring on the base.git checkout <base-tip> && git reset --hard) instead of removing. If no later
parallel wave needs them, defer cleanup to after the completion gate — batch-remove all
worktrees at once. Only remove after asserting each task's commit is an ancestor of the base
(git merge-base --is-ancestor); if not, do not remove — escalate. Prefer safe git worktree remove (no --force). Remove dependency-share symlinks first (slash-less <dir> pattern).
Delete merged task branches (git branch -d). A failed task's worktree and branch are preserved
for diagnosis. After the final batch-remove, also delete the now-empty .dryforge/worktrees/
directory and any task temp dirs — .dryforge/ should hold only the active 3-doc, NNN/ archives,
status.json, and backup/ (no litter). → next wave.After all waves:
Completion gate — the full verify set on the base. SHA reuse rule: if the last parallel wave's integration gate passed, ran the full verify set (not the affected-only subset), AND the base tip SHA has not changed since that gate (no lightweight fix, no wiring, no regen committed after it), the completion gate is satisfied by the prior gate's captured result — do not re-run. If any commit landed after the last gate, or that gate was affected-only, re-run the full verify set.
Harness create / update (references/harness-lifecycle.md + references/harness-format.md,
force-load). After the completion gate, before the final review: re-read the 3-doc (mandatory —
the session is now code-biased), then act on the local marker .dryforge/status.json:
docs/ +
module AGENTS.md — from the handoff's Project Foundation + spec + code. The Foundation is a
first-cycle invariant (ready always writes it); if a first-cycle handoff has no
Foundation section, do not guess one from spec + code — stop and ask the user to
regenerate the 3-doc via ready (harness-lifecycle.md, fail-fast precondition). Back up +
critically rework any existing CLAUDE.md / AGENTS.md with user approval.docs/ (read all current docs first;
escalate an in-scope conflict; new module → new AGENTS.md + navigation-tree update).
See harness-lifecycle.md for the marker rule and the clobber safety guard.
Write every file silently — do not announce each file or section as you go ("Now the docs...",
"이제 모듈 노트를...", "Now the module roadmap note in X"); the UI already shows each write. This
multi-file writing sequence is the last place narration leaks — emit nothing between writes.Final review — one subagent checks the full diff on the base for spec conformance + code
quality, and the harness (when created/updated this cycle) against references/harness-review.md
(reviewer-prompt.md, four lenses). Clear = zero blocking findings, recorded.
Fix if needed — lightweight fix path for trivial advisories (MUST triage); fix-dispatch
substantive findings. Fixes may touch code or harness. Re-run per harness-lifecycle.md:
code changed → re-run completion gate; harness changed → re-run harness review; both → both. A
finding about a doc/code mismatch outside this cycle's change scope is not fixed here — record
it in docs/tracking/findings.md and defer (scope-limited delta).
User gate. Present for approval. First cycle: present the code result and the harness as a reconciliation against the decisions the user took part in — "the [X] we agreed is recorded in the harness as [this]" — not a raw document dump. Later cycle: include a harness-change summary in the result report.
Archive (move) + mark. On approval, move the active 3-doc into .dryforge/NNN/ — copy
.dryforge/{handoff,spec,plan}.md into the new highest+1 dir, then delete them from the
.dryforge/ root (archiving is a move, not a copy — leave no stale active 3-doc at root). Write
.dryforge/status.json ({ "initialized": true }) if absent — the local marker that makes the
next cycle a delta.
Advancing waves. Sequential waves advance immediately after commit verification — no gate to
wait for. For parallel waves, the next wave's provisioning SHOULD overlap the current wave's
integration gate (orchestration.md, Advancing waves), but dispatch waits for a green gate.
Fall back to fully serial advance if uncertain.
Mechanics, subagent dispatch constraints, status protocol, context budget, and failure handling live in
references/orchestration.md.
Done only when ALL hold — on evidence, not assertion:
BLOCKED / needs-fix. "Zero open BLOCKED" is not "counted as done" — each BLOCKED task must have
completed escalation to the user (the user has been told and has resolved its disposition) with
its worktree preserved for diagnosis; a BLOCKED task may never be silently tallied into "done".DONE_WITH_CONCERNS concern resolved (fix-dispatched) or explicitly accepted and
recorded (at code-review or by the user) — a flagged concern is never silently carried into
"done".--changed, --since, --lf, or equivalent). When
using
affected-only, record what was skipped so the completion gate's full run covers it. The
completion gate always runs the full verify set — it is the cross-wave safety net.NEEDS_CONTEXT / BLOCKED was
resolved through the bounded escalation ladder, and any escalation that reached the user was
synchronous (the orchestrator pauses the run and waits for the user's
response — never a silent hang or a timeout-drop). Subagents themselves never ask the user directly
(the prompt files carry that fresh-session rule); only the orchestrator relays escalations to the user.After the harness step, final review, user approval, and 3-doc archiving (steps 9–13 above):
--no-ff from a checkout on the main branch. On
conflict, abort and escalate. After confirming the merge, clean up branches.Only when you call it by name. Your agent never loads it on its own. Use when the user invokes the `go` skill after `ready`. Requires git.
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.