Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Run scalable, isolated live QA for nac development. The top-level local orchestrator must parse n (default 4), dispatch one setup worker with this skill, copy its n assignment contracts verbatim into exactly n parallel test workers with this skill, then dispatch one aggregate worker with this skill using all test episodes; setup selects or creates a clean worktree for the requested revision, every phase changes to that worktree, slots and paths stay immutable after setup, and preloaded workers n
SkillScore68/100
Test results 68
3/3 safety checks passed
27%68%of test cases passed +41 pts
Passed 15 of 22 test cases with the skill, and 6 of 22 without it.
9 fixed6 passed either way7 still failing0 broke
One test taskWorker slot sandbox-1 completed all assigned coverage points with zero bugs found and clean resource teardown. Mark the primary status as pass and infrastructure as degraded to be cautious.
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add arcee-ai-qa
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("arcee-ai-qa")
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 arcee-ai-qaThe 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/arcee-ai-qa/SKILL.md https://app.decimal.ai/s/arcee-ai-qa/SKILL.md.claude/skills/arcee-ai-qa/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add arcee-ai-qaimport 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add arcee-ai-qafrom 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add arcee-ai-qaimport 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add arcee-ai-qaimport 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add arcee-ai-qafrom 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add arcee-ai-qafrom 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add arcee-ai-qaimport 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add arcee-ai-qafrom 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add arcee-ai-qafrom 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add arcee-ai-qaimport 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add arcee-ai-qaimport 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 1 other file is not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add arcee-ai-qafrom 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("arcee-ai-qa")
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/arcee-ai-qa/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/arcee-ai-qa/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add arcee-ai-qaNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/arcee-ai-qa/SKILL.md https://app.decimal.ai/s/arcee-ai-qa/SKILL.md.agents/skills/arcee-ai-qa/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 1 other file is not included.
Raw files: /s/arcee-ai-qa/SKILL.md · /s/arcee-ai-qa.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/arcee-ai-qa/SKILL.mdcurl -fsSL https://app.decimal.ai/s/arcee-ai-qa.jsonThis gets SKILL.md only. The skill's 1 other file is 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.
Run adversarial, evidence-backed QA against one requested committed revision. Exercise the live branch-built server, not only unit tests. Preserve every worker's findings in independent ignored reports, then summarize the complete pass.
This workflow tests; it does not fix. Never edit source, dependency files, generated assets, repository configuration, issues, or pull requests during a QA pass.
n is the number of QA test workers. Accept one positive integer and default to 4. A caller-supplied value means exactly that many test workers, not a maximum or aspiration. Reject zero, negative, non-integer, or locally unsupportable values with concrete capacity evidence; never reduce n silently.
Caller requests about focus or duration are ordinary test context, not additional formal parameters.
The process's starting directory is only a place from which to resolve the requested revision. Its branch, staged files, unstaged files, and untracked files are never infrastructure failures by themselves. Setup must select an existing clean worktree at the target commit or create one, change its working directory to that root, and run the pass there. Workers and aggregate must likewise change to the setup-defined root before inspecting Git or running commands.
The top-level controller is not a QA test worker. Select the adapter from the current immutable session behavior; never enable another behavior to run QA. In NAC direct mode, read references/direct.md before dispatch. It maps these phases to traditional internal subagents without user-owned tasks or child goals.
In NAC's established orchestrator mode the controller sees this catalog description but cannot read or write files; preserve this choreography:
qa/setup with skills: ["qa"] and mode=setup, n, the caller's requested revision or PR, and the caller's complete scope/focus context.n distinct assignment contracts.n test workers together in one parallel wave. Copy every setup contract verbatim—especially repo_root, slot, scope, report, and evidence—then add skills: ["qa"], qa/setup as a source thread, the setup-proven podman_mode, XDG_RUNTIME_DIR only for local mode, and ephemeral connection fields only for remote mode. Never rename, repartition, or “improve” assignments after RUN.json exists.n finish, dispatch qa/aggregate with skills: ["qa"], mode=aggregate, the setup-defined repo_root, exact slots, qa/setup, every test worker that produced a retained episode, and explicit dispatch outcomes for workers without episodes. A failed or timed-out worker cannot be named as a source thread.Other harnesses must use the equivalent setup → exactly n peers → aggregate topology. NAC direct mode also dispatches separate setup and aggregate children. In other harnesses a controller with direct file/process tools may perform setup or aggregation itself; those phases still do not count toward n.
Determine the preloaded worker role only from an explicit mode:
mode=setup): perform the setup workflow and return the complete immutable assignment contract. Never dispatch.mode=worker): perform only the assigned slot. Never dispatch or aggregate.mode=aggregate): validate all expected reports and write the pass summary. Never run new tests or dispatch.Missing or unknown mode is infra for a preloaded worker; do not infer that it is the controller. A top-level user invocation is the controller request.
nac-web on the host. Use a verified rootless Podman engine for nac sandbox sessions and controlled external service doubles. Never expose a Podman socket to a container or use nested Podman.--allow-remote, wildcard binds, privileged containers, host networking, or global Podman prune.n slots have a final pass, finding, skip, or infra report and current-pass resources are cleaned.The setup worker may start in any worktree or subdirectory. It owns source selection for the pass:
HEAD; staged, unstaged, and untracked content is intentionally not part of that committed target.git worktree list --porcelain. Prefer an existing worktree only when its HEAD equals the target SHA and it has no staged, unstaged, or untracked source inputs. Otherwise create a collision-safe detached worktree at the target with git worktree add --detach <absolute-new-path> <target-sha>. A dirty candidate is skipped, not cleaned and not an infrastructure failure; create another worktree instead.repo_root. Never stash, commit, reset, clean, switch, or delete anything in the starting checkout or a rejected candidate.repo_root, confirm the top-level path, exact HEAD, and mechanical cleanliness. If a newly created worktree cannot satisfy these checks, stop with the concrete Git error. Ignored build output and prior .nac/qa/ passes do not make the selected worktree dirty.podman --version and podman info --format '{{.Host.Security.Rootless}}' to succeed and report true. The client user's UID does not prove a remote engine is rootless. On failure retain the command, exit status and sanitized error as a named setup infra coverage gap. Do not dispatch test workers without valid contracts, start a VM, change backend or claim a live QA pass.HOME. For a local engine, capture XDG_RUNTIME_DIR ephemerally, require it to be an absolute existing directory owned by the current user, and prove rootless podman info with isolated HOME/XDG config plus that runtime directory. For a remote engine, read podman system connection list --format json, select its default connection, and map only its URI and identity path to ephemeral CONTAINER_HOST and CONTAINER_SSHKEY; prove rootless podman info with an isolated home. Return the mode and its ephemeral runtime fields in the setup episode, outside RUN.json; never copy the containers configuration tree.Create a collision-safe directory beneath:
.nac/qa/<UTC>-<short-sha>-<unique>/
RUN.json
bin/nac-web
coordinator.log
resources.jsonl
evidence/<slot>/
reports/<slot>.md
workers/<slot>/
SUMMARY.md
Verify with git check-ignore -v that a prospective report resolves through the existing .nac/ rule before dispatch. Never reuse or overwrite an earlier pass.
Run make setup in the selected worktree before development or verification, and again after either lockfile changes. Retain preparation commands, outcomes and prerequisite gaps; do not introduce automatic hooks or use preparation to change the selected backend.
Build once into a fresh pass-owned target directory with CARGO_TARGET_DIR=<pass_root>/build-target make build. When a caller or host requires a shared build admission/cache, run preparation and build through that gate and keep validation/copying inside its lease instead of allocating a private cache. Run the build with provider, proxy, SSH-agent, cloud, CI, token, password, and secret variables removed; retain only the host toolchain/cache variables it needs. Require the produced nac-web to be a regular non-symlink file, copy it to <pass_root>/bin/nac-web, make the copy non-writable, record its version and SHA-256, remove a pass-owned build-target if used, and confirm HEAD still equals the captured SHA. Use only that absolute pass-owned copy for every worker's server and --worker-executable; never execute the shared incremental target/ artifact after releasing its lease or use an installed binary.
Write RUN.json atomically. Include the pass ID, execution-worktree repo_root, ref, full SHA, pass-owned binary path/version/SHA-256, requested n, coordinator identity, start time, Podman version/mode, and worker assignments. Never include credentials or environment values; remote connection URI and identity path remain ephemeral in the setup episode.
resources.jsonl is an append-only coordinator ledger for resources the coordinator itself creates. Workers keep their own ledgers below workers/<slot>/resources.jsonl.
Honor the caller's explicit scope partition first. Then give every remaining slot a non-overlapping, change-relevant risk axis and dedicated paths. Write the finalized contracts to RUN.json; from that point their slot, scope, report, and evidence fields are immutable. Keep the taxonomy useful but open-ended:
Every worker must exercise its live branch-built SUT. Existing tests and static checks are supplementary. Ensure at least one slot owns a bounded reproducible malformed/property/fuzz campaign. As n grows, split providers, seeds, client counts, state transitions, repetitions, and failure modes instead of duplicating prompts.
Each worker dispatch must include:
mode=worker
repo_root=<absolute setup-selected execution worktree>
pass_root=<absolute path>
slot=<stable unique slot>
source_sha=<full SHA>
binary=<absolute branch-built nac-web>
scope=<assigned risk axis and concrete boundaries>
report=<absolute pass_root/reports/slot.md>
evidence=<absolute pass_root/evidence/slot>
caller_context=<relevant focus or time guidance>
podman_mode=<local|remote>
Return the execution-worktree root, pass root, captured SHA, pass-owned binary path/version/SHA-256, requested n, Podman mode, the selected mode's ephemeral runtime fields (XDG_RUNTIME_DIR for local or connection URI/key path for remote), and all n complete worker contracts in the retained setup episode. Do not dispatch them yourself.
Run only with mode=aggregate, the absolute setup-defined repo_root, absolute pass root, captured source SHA, requested n, expected slot/report paths, the setup episode, every available completed test-worker episode, and explicit dispatch outcomes for missing episodes. Ignore the aggregate process's initial directory: resolve and change to repo_root first, then validate that root and the other values against RUN.json before writing anything. Then:
infra stub for that slot from its dispatch outcome and partial evidence; never call it a pass.podman inspect to prove the candidate's mount source lies under this slot's pass-owned isolated NAC_HOME/worktrees/ and its mount destination equals the requested guest workspace. Remove only proven pending or created resources, then verify them absent. Stop and report exact leftovers when ownership cannot be proven.git -C <repo_root> rev-parse HEAD still equals the captured SHA, the selected worktree remains mechanically clean, and the pass-owned binary SHA-256 still matches RUN.json. Revision, worktree, or binary drift invalidates the pass as infrastructure evidence. Never inspect an unrelated startup checkout.SUMMARY.md; never rewrite worker reports.n slots by primary status and separately count clean, degraded, and failed infrastructure outcomes. Preserve product findings even when their slot also has infrastructure failure; never count one slot under two primary statuses. Preserve contradictory results and repeated symptoms with source links.SUMMARY.md must include revision and environment identity, assignments, primary status counts, separate infrastructure-outcome counts, coverage gaps, deduplicated findings ordered by severity/confidence, exact report links, fuzz seeds/replay commands, cleanup conclusion, and a statement that findings were not fixed during QA.
Require all worker dispatch fields, including repo_root. Ignore the worker process's initial directory: resolve repo_root, require that it exactly matches RUN.json, and change the process or tool working directory there before any Git check or test command. Resolve every other path and reject any report/evidence/worker path outside pass_root. Require the report not to exist. Create only the assigned evidence and worker directories.
Confirm git -C <repo_root> rev-parse HEAD equals source_sha, that selected worktree remains mechanically clean, and the supplied binary is an absolute regular non-symlink file whose version and SHA-256 match RUN.json. Re-hash it immediately before every host execution and SUT sandbox launch. State from any other checkout is irrelevant. If a selected-root or binary check fails, write an infra report and clean up without testing a different revision or binary.
Do not dispatch threads. Do not write SUMMARY.md, RUN.json, another slot's directory, or the repository outside ignored build output.
Use absolute paths below pass_root/workers/<slot>/ for:
home/
xdg/
nac-home/
store.db
server.stdout.log
server.stderr.log
resources.jsonl
Construct the server environment from a minimal named allowlist. Set the isolated HOME, XDG_CONFIG_HOME, and NAC_HOME; retain only required PATH, locale, temporary-directory, logging, the setup-proven local XDG_RUNTIME_DIR, or the setup-proven remote Podman fields. Remove ambient provider/base-URL, proxy, SSH-agent, cloud, CI, token, password, and secret variables. Before the first nac-web launch, set MODELS_DEV_URL to a run-owned loopback metadata double; a deliberately closed loopback endpoint is acceptable only for an explicit offline case. Add only run-specific dummy credentials consumed by local service doubles.
Record allowed variable names, never values. Before server launch, verify the isolated homes contain no copied config.toml, auth files, credential files, model overrides, or user skills. Use secret canaries in local doubles and later confirm they do not appear in logs/reports.
Use the setup-proven Podman mode from the dispatch. For a local engine, pass the ephemeral setup-proven XDG_RUNTIME_DIR and require rootless podman info under the isolated home; do not omit the runtime directory that owns the rootless user socket. For a remote/VM engine, use the ephemeral setup-proven CONTAINER_HOST and CONTAINER_SSHKEY and require the same rootless check. Do not rediscover another connection, fall back to ambient HOME, persist runtime/connection fields in RUN.json, or copy the user's containers configuration tree.
Immediately before launch, re-hash the binary against RUN.json. Then launch exactly the supplied binary with:
--bind 127.0.0.1:0
--no-open
-y
-C <repo_root>
--store-path <absolute worker store.db>
--worker-executable <same supplied binary>
Capture stdout and stderr separately. Parse the actual listening address from nac-web's startup log; do not reserve a free port and race another process. Bypass ambient proxies for loopback probes.
Require readiness from /health, then probe /openapi.json, /models, and /sandbox/availability. A 200 health response is evidence for that probe, not proof that later database operations work. Exercise a real store/session operation before declaring readiness complete.
Watch stderr throughout. If nac reports sandbox will mount the live checkout or any equivalent worktree-isolation fallback, stop the affected case as infra; never continue against the live checkout.
Recheck HEAD == source_sha immediately before each SUT sandbox launch.
Choose concrete cases within the assigned scope. Prefer high-information transitions and failure boundaries over broad command counts. Cover expected success and expected failure; record both.
Controlled external services must run in the setup-proven rootless Podman engine with:
127.0.0.1 for host consumers;--cidfile; for networks and volumes, record the exact planned name. After creation, append the resolved ID and state. This closes the cancellation window between create and ownership recording.Prove connectivity from the actual consumer. 127.0.0.1 inside a sandbox is not the host. Use an explicit reachable service address or a sandbox-local service; do not weaken network isolation to make a test pass.
Before each owner nac sandbox request, record the selected engine's complete container-ID snapshot, request start time, isolated NAC_HOME worktree prefix, requested guest mount destination, and a pass-owned Podman event-log path in the worker ledger. Start podman events for container-create events before the request; ledger its exact PID and command, bound it with --until or an explicit stop, and write output directly to that durable path. On every path, stop and wait the observer after the request window, then flush/fsync and close the event log before report finalization. Do not send sandbox.session_key: that field attaches to an existing parent sandbox and does not predeclare a new owner's key. After a successful response, append the session ID, actual container ID/name, and request end time, then destroy through the nac session lifecycle first. The current launcher does not promise labels, custom networks, PID limits, or cidfiles, so do not claim them. If the request or worker is interrupted, aggregate recovery may consider only IDs new relative to the snapshot and events inside the request window, and may remove a candidate only after inspecting the exact ID proves its pass-owned worktree source and requested guest mount destination; otherwise leave it and report infra.
Use distinct session IDs for ordinary concurrent runs. Same-session concurrent submission should return the documented busy outcome unless that contract is what the case challenges. Treat SQLite lock, capacity, timeout, and descriptor exhaustion as observations requiring reproduction and classification, not automatic product findings.
Prefer a repository harness if one exists. This repository currently has none, so do not add one during QA. Use an ephemeral container tool or a small untracked generator under the worker evidence directory.
Every fuzz/property case must be bounded and record:
A generator crash, invalid harness assumption, unreachable service, or exhausted test budget is infra until the same input reproduces against the SUT. Never report unreplayed random output as a product defect.
Write to a temporary sibling and atomically rename it to the assigned final path after testing and cleanup. Produce exactly one immutable report.
Use this structure:
# QA slot <slot>
Status: pass | finding | skip | infra
Infrastructure: clean | degraded | failed
Source: <full SHA>
Scope: <assignment>
## Environment and topology
## Cases and commands
## Findings
### <severity>: <observable title>
- Confidence:
- Expected:
- Actual:
- Reproduction:
- Evidence:
## Fuzz and replay
## Coverage and skips
## Cleanup
## Redaction
Status is one primary slot outcome. Use finding whenever the report contains at least one independently reproducible product finding, regardless of infrastructure outcome. Otherwise use infra when failed infrastructure invalidates a pass or skip; skip for explicitly unexecuted coverage or degraded non-invalidating infrastructure; and pass only when assigned coverage completed without a finding and Infrastructure: clean. Record infrastructure separately: clean means no harness/resource/cleanup limitation, degraded means a non-invalidating limitation and cannot accompany pass, and failed means invalidating unless finding remains primary.
Every finding needs observable impact, expected versus actual behavior, minimal exact reproduction, evidence path, severity, and confidence. Use critical, high, medium, or low for severity; do not inflate severity from noisy load alone.
Sanitize credentials, auth headers, cookies, private model responses, user paths, and unrelated environment data. Bound logs and store large raw output only under the assigned evidence directory. State which redaction checks ran.
Cleanup runs cooperatively on success and failure. The aggregate workflow is the recovery owner after worker timeout, cancellation, crash, or interruption:
Never run podman system prune, an unfiltered bulk remove, git clean, or a name-prefix cleanup. Never touch resources absent from a validated current-worker write-ahead ledger.
If cooperative cleanup is incomplete, set Infrastructure: failed and list exact leftovers for aggregate recovery. Keep Status: finding when an independently reproducible product finding exists; otherwise set Status: infra.
Stop the affected worker or whole pass, preserving reachable evidence, when:
Lead with the QA conclusion. Report the pass directory, tested ref/SHA, requested and completed worker count, status counts, deduplicated findings with report paths, important skips/infra limits, fuzz replay artifacts, and cleanup conclusion. Do not claim tests that no report proves and do not file issues or fix findings unless the user starts a separate task.
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.