Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use this skill whenever a session will touch a scientific-computing codebase (numerical methods, PDE solvers, inverse problems, OED, UQ, scientific ML, or any code that produces numbers) in Python, Julia, C++, or other languages. Make sure to load this EVEN IF THE USER DOES NOT MENTION IT. Codifies eleven disciplines for AI-assisted scientific software development: numerical correctness (MMS, convergence-rate tests, conservation invariants, "paper tests" guard); testing strategies for numerical
SkillScore86/100
Test results 86
3/3 safety checks passed
45%86%of test cases passed +41 pts
Passed 19 of 22 test cases with the skill, and 10 of 22 without it.
9 fixed10 passed either way3 still failing0 broke
This benchmark measured an earlier version of the skill.
A newer attempt on gemini-3.8-flash on 10/23/2026 did not produce a publishable comparison (graded differently). The snapshot above is the previously measured run.
One test taskWe are redesigning the API exposure for our array-based spatial mesh module in `mesh/api.py`. I want to load reference 03 (`references/03-api-design-for-researchers.md`) to follow its specific guide. How should I proceed?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add a-attia-research-software-engineering
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("a-attia-research-software-engineering")
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 a-attia-research-software-engineeringThe 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/a-attia-research-software-engineering/SKILL.md https://app.decimal.ai/s/a-attia-research-software-engineering/SKILL.md.claude/skills/a-attia-research-software-engineering/SKILL.mdThis gets SKILL.md only. The skill's 4 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 a-attia-research-software-engineeringimport 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringfrom 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringimport 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringimport 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringfrom 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringfrom 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringimport 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringfrom 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringfrom 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringimport 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringimport 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringfrom 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("a-attia-research-software-engineering")
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/a-attia-research-software-engineering/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/a-attia-research-software-engineering/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 4 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 a-attia-research-software-engineeringNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/a-attia-research-software-engineering/SKILL.md https://app.decimal.ai/s/a-attia-research-software-engineering/SKILL.md.agents/skills/a-attia-research-software-engineering/SKILL.mdThis gets SKILL.md only. The skill's 4 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 4 other files are not included.
Raw files: /s/a-attia-research-software-engineering/SKILL.md · /s/a-attia-research-software-engineering.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/a-attia-research-software-engineering/SKILL.mdcurl -fsSL https://app.decimal.ai/s/a-attia-research-software-engineering.jsonThis gets SKILL.md only. The skill's 4 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.
This skill follows the three-level progressive disclosure pattern
also used by agent-resource-discipline and codified by Anthropic's
skill-creator:
SKILL.md,
~340 lines. Contains the universal principles + a workflow table
showing which reference to load for which task.references/*.md
files -- one per discipline. Loaded only when a session actually
exercises that discipline.agent-resource-discipline's planned hooks.Always load this SKILL.md when the trigger fires. Load specific references only when the current sub-task requires them.
Load this skill at the start of any session that will involve any of:
If the session is a paper-writing session that does NOT touch code,
load research-paper-writing instead. If the session is mixed (paper +
code), load both.
A scientific-computing program that returns a plausible-looking wrong number is much worse than one that crashes. The agent MUST treat numerical correctness as the highest-priority concern, ahead of performance, ahead of API ergonomics, ahead of style. Specifically:
references/02-testing-for-numerical-code.md.experiments/<run-id>/metadata.json.This principle is non-negotiable. If style / performance / API elegance ever conflicts with it, correctness wins.
Beyond the correctness imperative, these universal principles fire
for every action the agent takes in a scientific-computing codebase.
Restated from the Scientific Python Development Guide
(https://learn.scientific-python.org/development/principles/design/,
BSD-3) with sci-computing-specific framing:
Keep I/O separate. I/O functions only do I/O and return standard types (NumPy arrays, dataclasses); the scientific logic operates on those standard types and never touches files / sockets / GUIs directly.
Duck typing where helpful. Avoid isinstance checks; functions
should accept the broadest input types they can handle.
Consider: can this just be a function? Cite Perlis: "It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures." Most scientific code is functions over arrays; resist the urge to wrap everything in classes.
Avoid changing state. Replace mutable workflow classes with multiple immutable classes (or pure functions chained explicitly) representing each step.
Static typing makes code more readable. Add type hints by default; they document intent at zero runtime cost.
Keyword-only optional arguments. Use the * separator in
function signatures to force long-tail options to be named at
call sites; this prevents positional-argument bugs when defaults
change.
Two-layer "friendly + cranky" architecture. Library code raises errors unless it knows how the user wants to handle them; a thin convenience layer above can be more permissive. Don't mix the two.
Write useful error messages. A scientific error message should name the offending value, the constraint it violated, and the function it occurred in -- not just "ValueError".
A tool's first negative result is a claim about the tool. Before believing that a new viewer, rasteriser, linter, or checker has found a defect, run it on an input already known to be good. A tool failing on both is the fault. One command separates "my artifact is broken" from "this tool cannot read this format", and skipping it cost three rounds of fixes to a diagram that was correct from the first build.
The corollary, for a check that reports a threshold: calibrate it against a rendered artifact known to be good rather than against the configuration value it appears to correspond to. A stylesheet says what space is reserved; only the render says what occupies it.
An identical measurement across unrelated inputs is the tell that the quantity being measured is not the one intended.
Survey the library before extending it. Before writing code
that a dependency might already provide, enumerate that
dependency's public surface in the relevant area -- ls src/*plot*.hpp, the module index, dir(), the class list in the
API docs -- and state which classes or functions were considered
and rejected. Reading one header is not a survey: a positive
result stops the search, so the first plausible class found gets
mistaken for the whole API.
Two tells that this step was skipped. You are reimplementing a domain-standard quantity -- emittance, Twiss parameters, a histogram, a quadrature rule, a norm -- which mature domain libraries exist largely to provide. Or you are working around a limit inferred from a single file rather than one the library documents.
The cost is not only duplicated effort. A reimplementation does not know the domain conventions the library encodes, so it silently computes something adjacent to what was wanted. In the case that produced this rule, a hand-rolled rms emittance disagreed with the library's by a factor of 2.4 because the library mirrors the distribution about the symmetry axis in cylindrical geometry and the reimplementation used half of it. The wrong number was plausible and had nothing to contradict it.
A failed import is not a completed survey. From a second instance (2026-09). A Gaussian laser-field model was written from scratch because the library that already contained it would not import on the author's platform, and the import error was read as "unavailable" rather than as "look harder". An import error is a fact about the build, not about the contents, and the contents stay readable: a wheel is a zip, and listing its public surface takes seconds.
pip download <pkg>==<version> -d /tmp/x --no-deps
unzip -l /tmp/x/*.whl # module layout
unzip -p /tmp/x/*.whl '*/physics.py' | grep '^def ' # public surface
In that case the duplicated function was identical in formula and convention, and making the library importable turned out to cost sixteen lines across two small patches. Survey first, then decide whether the platform problem is worth solving, not the other way round.
The Bridgeford et al. 2025 paper "Ten Simple Rules for AI-Assisted
Coding in Science" (arXiv 2510.22254, CC-BY 4.0, companion Jupyter
Book at https://poldracklab.org/10sr_ai_assisted_coding) is the
peer-reviewed reference for the AI-assisted era specifically targeting
scientists. The full rules are in
references/11-ai-assisted-coding-rules.md; the four rules that
apply unconditionally are:
git reset --hard is cheaper than trying to
steer a confused context back to correctness.When the session enters a specific phase or addresses a specific concern, load the matching reference. Do NOT load all references at once.
| Phase / concern | Reference to load |
|---|---|
| Numerical correctness, MMS, convergence | references/01-numerical-correctness.md |
| Test design for numerical code | references/02-testing-for-numerical-code.md |
| Working with AI on scientific code | references/11-ai-assisted-coding-rules.md |
| Shell-script orchestration + cross-language data interop | references/12-shell-and-cross-language-interop.md |
The following references are designed but not yet shipped. The universal principles + AI-assisted-coding rules above cover the underlying discipline; specialised content arrives in PR2 + PR4 per the audit's sequencing. Do NOT try to load these references yet -- the files do not exist.
| Phase / concern | Planned reference (not loadable yet) | Ship target |
|---|---|---|
| API design / refactoring decisions | references/03-api-design-for-researchers.md | PR2 |
| Lockfiles / Zenodo / FAIR / CITATION.cff | references/05-reproducibility-infrastructure.md | PR2 |
| Code-paper coupling / submission tags | references/08-code-paper-coupling.md | PR2 |
| Performance / GPU / MPI | references/04-performance-and-scaling.md | PR4 |
| pyproject / pre-commit / nox / actions | references/06-ci-cd-for-research-code.md | PR4 |
| Lifecycle / extraction / abandonment | references/07-project-lifecycle.md | PR4 |
| Launching a long numerical run | references/09-launch-checklist-numerical.md | PR4 |
| Debugging numerical failures | references/10-debug-protocol-numerical.md | PR4 |
In the meantime, when one of the planned phases comes up, fall back
on: (a) the universal principles + AI-assisted-coding rules in this
SKILL.md; (b) the cited upstream references (Scientific Python
Development Guide, JOSS criteria, etc.); (c) the
research-software-engineering skill's
references/01-numerical-correctness.md and
references/02-testing-for-numerical-code.md, which cover correctness +
testing in depth.
The full discipline lives in the references; the cross-cutting rules applied across all references are:
experiments/<run-id>/ + a
lockfile. Don't oversell DVC / wandb / mlflow until the project
actually needs them.scientific-python/cookie (or NLeSC/python-template,
CU-DBMI/template-uv-python-research-software). Don't reinvent
pyproject.toml + pre-commit + GitHub Actions configs we'd just
have to maintain forever.notes/impl_<component>.md with the source of the choice (paper
citation, prior implementation, empirical sweep).This skill composes with:
agent-resource-discipline -- always load when the session is
heavy (PDF / multi-file / web fetch / cross-session). Software
sessions almost always qualify.human-facing-doc-authoring -- load when authoring or revising
the project's README.md, PLAN.md, notes/impl_*.md, or any
human-facing doc.literature-survey -- load when papers cited as algorithm
sources need bib + survey-note workflow (the _collection_log.md
pattern transfers cleanly to "papers we cited in code comments").research-paper-writing -- load when the code supports a paper
and the paper draft is also being touched.The four skills are designed to compose; loading 2-3 simultaneously is normal for software sessions.
Detailed prior-art lineage lives at the bottom of
references/11-ai-assisted-coding-rules.md. The shortest summary:
the audit that informed this skill found a clear gap (no agent-skill
exists for sci-computing software methodology) but a rich corpus of
human-facing best-practice guides and project templates to cite +
borrow from. Templates: scientific-python/cookie (BSD-3) +
NLeSC/python-template (Apache-2.0) +
CU-DBMI/template-uv-python-research-software (BSD-3). Best-practice
corpus: Scientific Python Development Guide (BSD-3) + sp-repo-review,
pyOpenSci package guide, Wilson et al. 2017 (CC-BY), JOSS review
criteria, BSSw.io, The Turing Way (CC-BY 4.0 + MIT), Bridgeford et al.
2025 (CC-BY 4.0). Closest neighbour skills (different scope):
fcakyon/phd-skills (MIT, ML-flavored) and
K-Dense-AI/scientific-agent-skills (MIT, per-package wrappers).
When the user invokes this skill, the agent should:
agent-resource-discipline's
surfacing rule); never silently fix.notes/agent_feedback.md if any of the
trigger conditions in
agent-resource-discipline/references/persistent-memory.md fired
during the session.*Created 2026-05-13 by A. Attia. Informed by a prior-art audit
covering ~30 sources across agent-skills (anthropics/skills,
fcakyon/phd-skills, K-Dense-AI/scientific-agent-skills,
addyosmani/agent-skills, 47Wu/cc_skills,
sscivier/prompt-protocols), project templates
(scientific-python/cookie, NLeSC/python-template,
UCL-ARC/python-tooling, CU-DBMI/template-uv-python-research-software,
pyOpenSci/python-package-guide, cookiecutter-data-science),
best-practice corpora (Scientific Python Development Guide,
Wilson et al. 2014/2017, Bridgeford et al. 2025, JOSS review criteria,
The Turing Way, BSSw.io), and reproducibility tooling (DVC,
mlflow / wandb, Snakemake / Nextflow, Zenodo, Software Heritage,
JuliaBesties/BestieTemplate.jl). The audit identified a clear gap:
no agent-skill targeted scientific-computing software methodology;
this skill is the first cut at filling that gap. Currently ships
SKILL.md + 3 references (01-numerical-correctness,
02-testing-for-numerical-code, 11-ai-assisted-coding-rules); the
companion templates/software-skeleton/ (with bootstrap.sh
delegating to scientific-python/cookie | NLeSC/python-template |
CU-DBMI/template-uv-python-research-software | JuliaBesties/BestieTemplate.jl
12-shell-and-cross-language-interop.md consolidating 6 rules
(YAML/JSON quoting on bash/Python boundary; setdefault for
security-defaulted keys; error-message recovery hints must
themselves be tested; test stimulus must exercise the assertion
site; shell-script unit-test mechanics; exit-summary scope-keyed
hints). Reference 12 moved from the "Planned references" table to
the live workflow table. The framework's "research-software-
engineering" skill now ships 4 references (01, 02, 11, 12); 8
remain planned (03-10). Revised 2026-09-16: added universal principle
9, "Survey the library before extending it" (now principle 10), from
real-project feedback. Revised 2026-10-14: front-loaded the
frontmatter description so its first ~480 characters (Cursor's
truncation budget) carry the load triggers and scope; corrected the
planned count from 7 to 8 (reference 12 was never on the planned list);
added universal principle 9, "A tool's first negative result is a
claim about the tool", and the "failed import is not a completed
survey" extension to principle 10, both from a project-local
improvement made in 2026-09.*Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.