Install any skill in seconds. Free to start, no credit card required.
Get Started Free →SOP for writing, loading, and evolving a project-level convention file (CONVENTIONS.md / CLAUDE.md / .cursor/rules / .clinerules / AGENTS.md) so that a coder-agent reliably respects your codebase's style choices every session. Tool-agnostic; covers the four load mechanics (read-only attachment, ancestor-walk auto-load, glob-scoped rules, agent backstory) and the conflict resolution between pinned conventions and the existing code.
SkillScore96/100
Test results 96
3/3 safety checks passed
65%96%of test cases passed +30 pts
Passed 22 of 23 test cases with the skill, and 15 of 23 without it.
8 fixed14 passed either way0 still failing1 broke
One test taskA developer wants to add local sandbox database URLs and personal terminal preferences for Claude Code without committing them to the team's shared repository. Which file should they use?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add agentsope-agentsop-conventions-pinning
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("agentsope-agentsop-conventions-pinning")
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 agentsope-agentsop-conventions-pinningThe 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/agentsope-agentsop-conventions-pinning/SKILL.md https://app.decimal.ai/s/agentsope-agentsop-conventions-pinning/SKILL.md.claude/skills/agentsope-agentsop-conventions-pinning/SKILL.mdThis gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add agentsope-agentsop-conventions-pinningimport 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add agentsope-agentsop-conventions-pinningfrom 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add agentsope-agentsop-conventions-pinningimport 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add agentsope-agentsop-conventions-pinningimport 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add agentsope-agentsop-conventions-pinningfrom 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add agentsope-agentsop-conventions-pinningfrom 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 2 other files are not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add agentsope-agentsop-conventions-pinningimport 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add agentsope-agentsop-conventions-pinningfrom 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 2 other files are not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add agentsope-agentsop-conventions-pinningfrom 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 2 other files are not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add agentsope-agentsop-conventions-pinningimport 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 2 other files are not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add agentsope-agentsop-conventions-pinningimport 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 2 other files are not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add agentsope-agentsop-conventions-pinningfrom 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("agentsope-agentsop-conventions-pinning")
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/agentsope-agentsop-conventions-pinning/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 2 other files are not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add agentsope-agentsop-conventions-pinningNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/agentsope-agentsop-conventions-pinning/SKILL.md https://app.decimal.ai/s/agentsope-agentsop-conventions-pinning/SKILL.md.agents/skills/agentsope-agentsop-conventions-pinning/SKILL.mdThis gets SKILL.md only. The skill's 2 other files are not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 2 other files are not included.
Raw files: /s/agentsope-agentsop-conventions-pinning/SKILL.md · /s/agentsope-agentsop-conventions-pinning.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/agentsope-agentsop-conventions-pinning/SKILL.mdcurl -fsSL https://app.decimal.ai/s/agentsope-agentsop-conventions-pinning.jsonThis gets SKILL.md only. The skill's 2 other files are not included.
You don't need a DecimalAI account.
Saved prompts and skills, pinned versions, and traces of this skill in your runs. DecimalAI does not run your agent.
Claude Code reads files from your project, so DecimalAI config does not apply there.
On Claude Agent SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI Agents: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Anthropic: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Gemini API: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On LangChain: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On CrewAI: set DECIMAL_API_KEY and add decimalai.init(crewai=True) to record runs and skill use. The skill version stays in your repo.
On Google ADK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Pydantic AI: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Deep Agents: set DECIMAL_API_KEY and add decimalai.init(langchain=True) to record runs and skill use. The skill version stays in your repo.
On Microsoft Agent Framework: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
On Strands: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
Editors read files from your project, so DecimalAI config does not apply there.
Anywhere else: record a use with decimalai.log_skill_activation() inside a trace.
One line: a conventions file is the system prompt of your codebase. Treat it like a system prompt, not like a README. Anti-patterns: writing prose, narrating history, marketing the project. Patterns: command-first, verifiable, "prefer X over Y", < 200 lines.
make lint before commit"), write a hook / precommit / CI check..eslintrc, pyproject.toml, .editorconfig, tsconfig.json. Point the agent at the config; don't duplicate.A conventions file earns its tokens only if it contains information that is not already in the repository. The research is unambiguous on this: "Developer-written context files performed better for exactly the reason you'd guess: they contained information that wasn't already in the repository — tooling preferences, workflow requirements, conventions that existed in developers' heads but not in any documentation." [developer.upsun.com/posts/ai/agents-md-less-is-more]
If everything you would write into CONVENTIONS.md is already discoverable from package.json, pyproject.toml, .eslintrc, the test directory, and obvious code patterns — don't write the file. The agent will pre-cache it itself.
+-------------------------------------+ +-------------------------------------+
| COMPILE-TIME (conventions file) | | RUNTIME (code review / lint / CI) |
| | | |
| - Loaded once per session | | - Runs on every change |
| - Shapes generation | | - Catches violations after-the-fact|
| - Cheap to update, free to ignore | | - Costly to set up, hard to ignore |
| - "Prefer X over Y" lives here | | - "X must always hold" lives here |
| - Style + intent + preferences | | - Invariants + safety + correctness|
+-------------------------------------+ +-------------------------------------+
^ ^
| Conventions guide; |
| review enforces. |
| Both are needed; they fail |
| in different ways. |
Conventions fail by silent drift: agent ignores the rule once, no one notices, code is merged. Review fails by late catch: violation is found post-PR, expensive to fix. The two complement, not substitute.
Every coder-tool has settled on one of four mechanics for getting persistent context into the agent. Knowing which mechanic your tool uses is the difference between "agent reads my rules" and "agent silently ignores them."
| Mechanic | Examples | How it works |
|---|---|---|
| Read-only attach (explicit) | Aider --read CONVENTIONS.md | You explicitly attach the file. Loaded read-only every session, cacheable. [aider.chat/docs/usage/conventions.html] |
| Ancestor-walk auto-load | Claude Code CLAUDE.md, ./.claude/CLAUDE.md, ~/.claude/CLAUDE.md | Tool walks from cwd up to root, concatenates every CLAUDE.md it finds, plus CLAUDE.local.md per directory. Subdirectory files load on-demand when files in that dir are read. [code.claude.com/docs/en/memory] |
| Glob-scoped rules dir | Cursor .cursor/rules/*.mdc, Claude Code .claude/rules/*.md with paths: frontmatter, Cline .clinerules/*.md with paths frontmatter | Multiple small files. Each can declare a paths: glob; rule loads only when the agent touches a matching file. [cursor.com/docs/rules], [docs.cline.bot/customization/cline-rules] |
| Agent backstory | CrewAI agent backstory= field, single-agent system-prompt suffix | Style/preferences embedded into the agent's persona at construction time. Per-agent, not per-project. [docs.crewai.com/en/concepts/agents] |
A project that uses multiple tools should pick one source of truth and have the other tools @-import or symlink to it. Claude Code 2.x docs explicitly recommend this: "If your repository already uses AGENTS.md for other coding agents, create a CLAUDE.md that imports it ... @AGENTS.md." [code.claude.com/docs/en/memory]
| ✅ Put in | ❌ Keep out |
|---|---|
| "Prefer httpx over requests." [aider.chat/docs/usage/conventions.html] | "We've been using Python since 2019 ..." (project narrative) |
| "Use 2-space indentation." | "Run npm install then npm test." (already in package.json) |
"API handlers live in src/api/handlers/." [code.claude.com/docs/en/memory] | "Format code properly." (unverifiable) |
"Add type hints everywhere; ruff ANN* rules are on." | "Be careful with database connections." (ambiguous) |
Anti-pattern: "Never use os.system; use subprocess.run." | "TODO: write better docs here." (file is not a TODO list) |
Workflow that's not in a script: "Before commit, run make fmt && make test." | The output of make help (the agent can make help itself) |
The litmus test: would this information be discoverable by a competent developer who spent 30 minutes browsing the repo? If yes — leave it out, the agent will discover it too. If no — pin it. [developer.upsun.com/posts/ai/agents-md-less-is-more]
Claude Code documentation: "Target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence." [code.claude.com/docs/en/memory]
Cursor docs: "Keep rules concise: under 500 lines. ... A 1,000-word always-apply rule is expensive, so trim aggressively or convert it to auto-attached with appropriate globs." [cursor.com/docs/rules]
Aider docs: "Above about 25k tokens of context, most models start to become distracted." [aider.chat/docs/troubleshooting/edit-errors.html] — and CONVENTIONS.md is one chunk competing for that budget against the actual code.
When the file passes ~200 lines, split it: glob-scoped rules (Cursor, Claude Code paths:), per-language file (python.md, react.md), or move detail into a skill that loads on demand.
You will eventually hit: CONVENTIONS.md says A, the existing code shows B. What wins?
Default precedence the major tools converge on:
managed/org policy > user (~/.claude/) > project (./) > local (gitignored)
(loaded in order; later overrides for conflicts)
existing code in repo ⟂ conventions file ← these don't have built-in precedence;
you must declare it explicitly
The agent does not know which one you want to win unless you tell it. Two patterns:
Claude Code docs warn about this directly: "If two rules contradict each other, Claude may pick one arbitrarily. Review your CLAUDE.md files ... periodically to remove outdated or conflicting instructions." [code.claude.com/docs/en/memory]
[Q1] Will this codebase be touched in ≥ 3 future sessions?
no -> skip; pin nothing.
yes -> continue.
[Q2] Are there style/library choices NOT already encoded in config files
(pyproject, eslintrc, editorconfig, tsconfig)?
no -> point the agent at the existing configs; skip a conventions file.
yes -> continue.
[Q3] Is the rule something the agent should DO (guidance) or something that
MUST hold (invariant)?
must hold -> write a hook/precommit/CI check instead.
guidance -> conventions file is the right tool. Continue.
Start with 5–15 bullets, max. Aider's documented example is exactly this minimal: two bullets ("prefer httpx over requests" + "use types everywhere"). [aider.chat/docs/usage/conventions.html]
Structure template (copy this):
# <Project> Conventions
## Language & versions
- Python 3.12+ (no 3.11 syntax workarounds).
- Node 20 LTS, TypeScript strict mode.
## Libraries — prefer / avoid
- HTTP client: prefer `httpx` over `requests`.
- Date math: prefer `pendulum` over stdlib `datetime` for tz-aware ops.
- Avoid: `os.system` (use `subprocess.run`), `eval`, raw f-strings in logging.
## Style
- Type hints everywhere (`ANN*` ruff rules are on).
- 2-space indent (TS), 4-space (Python).
- No inline comments unless explaining "why not how".
## Layout
- API handlers: `src/api/handlers/`
- Shared types: `src/types/`
- Tests mirror source: `tests/<module>/test_<file>.py`
## Workflow
- Before commit: `make fmt && make test`.
- Conventional commits: `feat:`, `fix:`, `chore:`, `refactor:`.
## When this file disagrees with existing code
- Treat existing code as drift; propose a refactor in a separate commit.
Save it at the canonical location for the primary tool:
| Tool | Location |
|---|---|
| Aider | CONVENTIONS.md at repo root (loaded with --read) |
| Claude Code | ./CLAUDE.md or ./.claude/CLAUDE.md |
| Cursor (modern) | .cursor/rules/main.mdc (one rule file) |
| Cursor (legacy) | .cursorrules at repo root (deprecated but still works) |
| Cline | .clinerules/coding.md |
| Multi-tool | AGENTS.md at repo root; have CLAUDE.md / .cursorrules / .clinerules import or symlink |
This is where most projects fail silently.
| Tool | Load command / config |
|---|---|
| Aider | aider --read CONVENTIONS.md per invocation, OR put read: CONVENTIONS.md into .aider.conf.yml. [aider.chat/docs/usage/conventions.html] |
| Claude Code | Automatic. CLAUDE.md in cwd and all ancestor dirs are loaded at session start. Verify with /memory — it lists every loaded file. [code.claude.com/docs/en/memory] |
| Cursor | .mdc files in .cursor/rules/ auto-attach. Use alwaysApply: true or globs: in frontmatter. [cursor.com/docs/rules] |
| Cline | All .md/.txt files in .clinerules/ are concatenated and loaded automatically. [docs.cline.bot/customization/cline-rules] |
| CrewAI | Paste relevant rules into each agent's backstory= string at construction time. [docs.crewai.com/en/concepts/agents] |
Verify the load worked, every time you change tools or environments:
/tokens shows the file in the context budget./memory lists it.If the file isn't shown — the agent isn't reading it. Don't proceed.
Pin one specific, verifiable rule (e.g. "use httpx not requests"). Then ask the agent to write a new HTTP call from scratch. If it uses requests, the load failed or the rule is too vague. Fix and retest.
This is the same test Aider documents: their example explicitly shows httpx + type hints get used with CONVENTIONS.md and requests + no types get used without. [aider.chat/docs/usage/conventions.html] If you cannot produce that A/B in your own setup, the load is broken.
Add a rule when (codified from Claude Code docs): [code.claude.com/docs/en/memory]
Delete a rule when:
Split a rule when it only applies to part of the codebase: use glob-scoped rules. Claude Code .claude/rules/api.md with paths: ["src/api/**/*.ts"]. Cursor: per-.mdc globs: field. This shrinks the always-on context budget. [code.claude.com/docs/en/memory], [cursor.com/docs/rules]
1. Run `/memory` (or equivalent) — list what's loaded.
2. For each rule:
- Has it been triggered? (grep recent PRs / chat for the keyword)
- Does the codebase still follow it? (grep code for violations)
- If both no → delete.
- If first no, second yes → the rule is enforced by gravity; consider deleting.
- If first yes, second no → drift; either fix code or kill rule.
3. Check size: > 200 lines → split into glob-scoped rules.
4. Check for contradictions across files (project + user + ancestor).
Eight reusable operations. Each is Trigger / Action / Output / Evidence. Detailed JSON form in intermediate/operation_candidates.json.
| # | Operation | Trigger | Action | Output |
|---|---|---|---|---|
| OP-1 | Decide-to-pin | User asks how to make agent respect style, OR same correction typed ≥ 2× | Run Phase 0 decision tree | pin / skip / use-hooks-instead |
| OP-2 | Write first cut | Decision = pin | Fill the 6-section template (Language / Libraries / Style / Layout / Workflow / Conflict-rule), 5–15 bullets total | CONVENTIONS.md (or tool-equivalent) at canonical path |
| OP-3 | Wire load mechanism | File written | Pick tool's load path: --read flag, ancestor-walk, glob paths:, or backstory string | File appears in agent's loaded-files list |
| OP-4 | Verify with A/B test | Load wired | Ask agent to perform a task that triggers a specific bullet (e.g. HTTP call); confirm rule was followed | Pass/fail; if fail go back to OP-3 |
| OP-5 | Add a rule | Same mistake twice OR review caught project-specific knowledge | Add bullet that is concrete, verifiable, and not already encoded in lint/config | Updated file, < 200 lines |
| OP-6 | Delete a stale rule | Codebase moved past it, OR rule is unenforceable, OR file > 200 lines and rule has lowest hit rate | Remove the bullet; if it now lives in lint/CI, note that in commit msg | Slimmer file |
| OP-7 | Split into glob-scoped rule | Rule applies only to subset (e.g. only src/api/); main file passing 200 lines | Move rule into per-glob file with paths: frontmatter (Claude Code rules / Cursor .mdc globs:) | New scoped file; main file shrinks |
| OP-8 | Cross-tool unification | Project uses multiple coder-tools (e.g. Claude Code + Cursor + Aider) | Make one file canonical (AGENTS.md at root is the cross-tool convention); have other tools @-import or symlink to it | One source of truth, multiple thin pointers |
--read CONVENTIONS.md but the agent still uses requests instead of httpx"Symptom: rule is loaded (Aider /tokens shows it; Claude Code /memory lists it), but generation ignores it.
Differential diagnosis (cheapest first):
/tokens to confirm.requests. Code-in-context is a stronger demonstration than a one-line rule. "If two rules contradict each other, Claude may pick one arbitrarily." [code.claude.com/docs/en/memory] Fix: add the conflict-resolution clause to CONVENTIONS.md ("if existing code uses requests, treat as drift and propose refactor"), or /drop the conflicting files.httpx.Client with timeout=10.0; do not import requests" is not.~/.claude/CLAUDE.md) says one thing, project says another. Claude Code loads them in a defined order (managed → user → project → local) [code.claude.com/docs/en/memory] — but if both have the same rule wording with different answers, the merge is ambiguous. Verify with /memory.Resolution rule: if cases 1–4 don't resolve it, the rule belongs in enforcement (lint, precommit), not guidance. Add a ruff rule to pyproject.toml that bans import requests. The conventions file is not a hammer.
httpx, half use requests. Fix in conventions or in code?"Trigger: codebase has visible inconsistency. Agent will mirror whichever file it reads first.
Decision rule:
| If ... | Then ... |
|---|---|
| The team has decided httpx is the future, no exceptions | (a) Add rule to CONVENTIONS.md; (b) write a single PR that migrates all requests callsites; (c) add a lint rule forbidding requests |
| There's a reason the old code uses requests (e.g. a sync-only library inside) | Document the exception in CONVENTIONS.md ("requests allowed in src/legacy/, banned elsewhere") and consider a glob-scoped rule |
| Half-and-half because no one decided | Make the decision, then case (a). The conventions file is the wrong place to record an unresolved choice |
The anti-pattern to avoid: writing "agents should use httpx going forward" without doing the migration. The agent will see 50% requests in the existing code, ignore your rule, and the drift continues. Conventions describe the codebase you have, not the one you wish you had. If the rule contradicts > ~30% of the existing code, fix the code first, pin the rule second.
Decision: one. Two files = two truths = silent disagreement.
Implementation (Claude Code 2.x's recommended pattern): [code.claude.com/docs/en/memory]
repo/
├── AGENTS.md # canonical, ~80 lines
├── CLAUDE.md # one line: "@AGENTS.md"
├── .cursor/rules/main.mdc # frontmatter alwaysApply: true; body: contents copied or symlinked
└── .clinerules/main.md # symlink → ../AGENTS.md (Cline reads .md transparently)
For Cursor (.mdc files require frontmatter, can't symlink raw), either:
.mdc from AGENTS.md in a pre-commit hook, ORSurprising finding from the research: Claude Code's /init reads existing .cursorrules and .windsurfrules and incorporates them into the generated CLAUDE.md. [code.claude.com/docs/en/memory] So if you already have a .cursorrules, Claude Code will not silently ignore it on first init — it pulls it in.
Diagnosis: violating both Aider's 25k-distraction threshold (in aggregate context) and Claude Code's 200-line per-file recommendation. [code.claude.com/docs/en/memory], [aider.chat/docs/troubleshooting/edit-errors.html] Cursor's docs are even more explicit: "if you're hitting context limits, look at your always-apply rules first." [cursor.com/docs/rules]
Resolution sequence (cheapest first):
.claude/rules/python.md with paths: ["**/*.py"]; Cursor .mdc with globs: field). Only the rules matching files-in-this-session load.Target after pruning: < 150 lines, every line a verifiable directive.
Decision: not yet. Pinning conventions before the conventions exist forces premature decisions and the agent will fight you on them.
Right sequence:
The exception: policy-level rules that aren't about code style but about constraints — "never call external APIs without explicit approval", "no secrets in git history", "all functions need docstrings". Those can be pinned from day 0 because they don't depend on emergent style.
The unintuitive bit: CONVENTIONS.md is context, not enforcement. Claude Code documents this explicitly: "CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself. Claude reads it and tries to follow it, but there's no guarantee of strict compliance, especially for vague or conflicting instructions." [code.claude.com/docs/en/memory]
Tiered response:
| Tier | Action |
|---|---|
| 1 | Rewrite the rule to be more specific. "Format properly" → "Use 2-space indent, double quotes, no trailing comma in JSON" |
| 2 | Move it earlier in the file (recency in context matters) and bold it |
| 3 | Add a counter-example: "Wrong: requests.get(url). Right: httpx.get(url, timeout=10)" |
| 4 | If the rule MUST hold, demote it to a hook / lint / CI gate. Conventions are guidance, not contracts |
package.json / pyproject.toml. The agent reads those. "Context files generated by /init commands are doing little more than pre-caching information the agent would discover on its own." [developer.upsun.com/posts/ai/agents-md-less-is-more] If it's already there, leave it out./memory. [code.claude.com/docs/en/memory].cursor/rules/ each with one bullet is a different kind of bloat. Group by topic; aim for 3–8 files if you split, not 30.--read CONVENTIONS.md to .aider.conf.yml means new shells silently lose it. Cursor: not setting alwaysApply: true means the rule sits inert. Always verify load with the tool's introspection (/tokens, /memory, sidebar).~/.claude/CLAUDE.md) helps for personal prefs but is not shared.CLAUDE.local.md (Claude Code, gitignored) or env files for personal paths.| Aider | Claude Code | Cursor | Cline | CrewAI | |
|---|---|---|---|---|---|
| Canonical filename | CONVENTIONS.md (any name; convention by community) | CLAUDE.md, CLAUDE.local.md | .cursor/rules/*.mdc (legacy: .cursorrules) | .clinerules/*.md (and memory-bank/) | Agent.backstory field (in code, not a file) |
| Location convention | Repo root | ./ or ./.claude/, plus ancestors auto-walked | .cursor/rules/ (nested dirs supported) | .clinerules/ directory | Agent constructor, not filesystem |
| Load mechanic | Explicit --read CONVENTIONS.md (or in .aider.conf.yml) [aider.chat/docs/usage/conventions.html] | Automatic ancestor-walk; subdirectory files load on-demand [code.claude.com/docs/en/memory] | Auto-attach by alwaysApply: true or globs: frontmatter [cursor.com/docs/rules] | All .md/.txt in .clinerules/ concatenated automatically [docs.cline.bot/customization/cline-rules] | Embedded into agent prompt at instantiation [docs.crewai.com/en/concepts/agents] |
| Multi-file support | Multiple --read flags; or list in YAML config | Native — .claude/rules/*.md with optional paths: frontmatter | Native — multiple .mdc files; nested .cursor/rules/ in subdirs | Native — all files in folder, numeric prefix for ordering | None — re-instantiate agents |
| Scope control | Global to the session | Ancestor-walk + path-scoped rules via paths: frontmatter | globs: frontmatter, nested dirs, alwaysApply toggle | YAML frontmatter with paths glob | Per-agent |
| Read/write boundary | Read-only (cannot be edited by agent) [aider.chat/docs/usage/conventions.html] | Loaded as user message, treated as context | Loaded as rule (system-prompt-ish) | Loaded into rules section of system prompt | Part of agent's persona |
| Personal vs team layer | Team commits CONVENTIONS.md; no per-user layer | CLAUDE.md (team) + CLAUDE.local.md (personal, gitignored) + ~/.claude/CLAUDE.md (user-global) + managed policy | .cursor/rules/ (team) + user rules in settings | .clinerules/ (workspace) + global rules; workspace wins on conflict [docs.cline.bot/customization/cline-rules] | Code-level; no built-in personal layer |
| Hard size budget | 25k-token total-context threshold (whole context, not just rules) [aider.chat/docs/troubleshooting/edit-errors.html] | < 200 lines per CLAUDE.md recommended; full file loaded regardless [code.claude.com/docs/en/memory] | < 500 lines per .mdc rule; always-apply rules trimmed aggressively [cursor.com/docs/rules] | Concatenated total; same context-pressure rules apply | Limited by LLM context; backstory is part of system prompt |
| Conflict precedence | None built-in; later --read wins by recency | managed > user > project > local; later files in walk override earlier | Always-apply > globs-matched > manually attached | workspace > global on conflict [docs.cline.bot/customization/cline-rules] | Per-agent only |
| Cross-tool import | --read AGENTS.md works | @AGENTS.md import syntax [code.claude.com/docs/en/memory] | Must duplicate (or generate from a build step) | Plain markdown, can symlink to AGENTS.md | Read external file in Python at construction time |
| Verifiable load check | /tokens (in-session) | /memory lists all loaded files | Sidebar shows active rules | Sidebar shows loaded rules | Inspect agent object in code |
.mdc files. The legacy .cursorrules (single file) is deprecated; you migrate piece by piece. [cursor.com/docs/rules].clinerules/ (style/preferences) with memory-bank/ (mutable working memory). Memory bank is read at the start of every task — "this is not optional" — and includes projectBrief.md, activeContext.md, progress.md. [docs.cline.bot/customization/cline-rules] This is a different mechanism than conventions; do not conflate them.backstory= argument), not on the filesystem. This means style is per-agent (not per-project) and cannot be edited by non-engineers. Trade-off: more programmatic control, less convenient for teams.| Need | Best fit |
|---|---|
| One small project, one tool, simple rules | Single-file CONVENTIONS.md (Aider) or CLAUDE.md (Claude Code) |
| Monorepo with per-language conventions | Glob-scoped: Claude Code .claude/rules/ with paths: or Cursor .mdc with globs: |
| Personal preferences across all projects | ~/.claude/CLAUDE.md (Claude Code) or ~/.claude/rules/ |
| Multiple coder-tools on one repo | AGENTS.md canonical, others import/symlink |
| Style is part of an agent's identity (multi-agent system) | CrewAI backstory= |
| Working memory that the agent updates as it goes | Cline memory-bank/ (none of the others has a clean equivalent) |
--read CONVENTIONS.md pattern)/read, /tokens, /clear@-imports, .claude/rules/ with paths: frontmatter, 200-line guideline, AGENTS.md interop, /init reading of .cursorrules.cursor/rules/ migration).mdc format, frontmatter, alwaysApply, globs.clinerules/ + memory-bank)paths frontmatter for conditional rulesrole + goal + backstory triplet, backstory as primary style lever.cursorrules template gallery/Users/5imp1ex/Desktop/Skill-Workplace/output/aider-sop-skill/SKILL.md §2.2, §3 Phase 1, §6 anti-pattern #7/Users/5imp1ex/Desktop/Skill-Workplace/output/crewai-sop-skill/SKILL.md §2.2 (backstory as style lever)/Users/5imp1ex/Desktop/Skill-Workplace/output/dify-sop-skill/SKILL.md (system-prompt patterns in visual workflows)Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.