Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Pharmacokinetic and pharmacodynamic modelling and simulation - non-compartmental analysis, compartmental and population PK, PK/PD and exposure-response, TMDD, PBPK orientation, bioequivalence, allometric scaling and first-in-human dose, drug interaction prediction, and Bayesian therapeutic drug monitoring.
SkillScore64/100
Test results 64
3/3 safety checks passed
36%64%of test cases passed +27 pts
Passed 14 of 22 test cases with the skill, and 8 of 22 without it.
7 fixed7 passed either way7 still failing1 broke
This benchmark measured an earlier version of the skill.
One test taskWe are upgrading our automated PK workflow to Pharmpy version 2.1+. What breaking change occurred regarding dataset row indexing in Pharmpy 2.0.0, and what function renaming occurred in 2.1.0?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add k-dense-ai-pkpd-modeling
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("k-dense-ai-pkpd-modeling")
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 k-dense-ai-pkpd-modelingThe 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/k-dense-ai-pkpd-modeling/SKILL.md https://app.decimal.ai/s/k-dense-ai-pkpd-modeling/SKILL.md.claude/skills/k-dense-ai-pkpd-modeling/SKILL.mdThis gets SKILL.md only. The skill's 27 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 k-dense-ai-pkpd-modelingimport 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingfrom 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingimport 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingimport 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingfrom 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingfrom 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingimport 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingfrom 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingfrom 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingimport 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingimport 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingfrom 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("k-dense-ai-pkpd-modeling")
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/k-dense-ai-pkpd-modeling/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/k-dense-ai-pkpd-modeling/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 27 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 k-dense-ai-pkpd-modelingNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/k-dense-ai-pkpd-modeling/SKILL.md https://app.decimal.ai/s/k-dense-ai-pkpd-modeling/SKILL.md.agents/skills/k-dense-ai-pkpd-modeling/SKILL.mdThis gets SKILL.md only. The skill's 27 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 27 other files are not included.
Raw files: /s/k-dense-ai-pkpd-modeling/SKILL.md · /s/k-dense-ai-pkpd-modeling.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/k-dense-ai-pkpd-modeling/SKILL.mdcurl -fsSL https://app.decimal.ai/s/k-dense-ai-pkpd-modeling.jsonThis gets SKILL.md only. The skill's 27 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.
Use for concentration-time analysis, structural and population PK workflows, exposure-response, regimen simulation, bioequivalence planning, DDI screening, and research TDM calculations. Version 2.0 rejects unsupported replicate/scaled BE and oral/infusion closed-form summaries; model-target dose and lowest-HED output labels replace clinical recommendation labels. This skill computes exploratory quantities and documents assumptions; it does not establish clinical safety, recommend a patient dose, or certify a regulatory submission.
The bundled scripts were exercised with NumPy 2.5.3 and SciPy 1.18.1 on Python 3.13. Use an isolated environment; no network, credentials or proprietary engine is needed at runtime.
cd skills/pkpd-modeling/scripts
All scripts accept --format table|tsv|json. Table/TSV data go to stdout and notes/findings to
stderr; JSON includes all four components on stdout and uses null for unavailable diagnostics.
Exit 0 means no findings, 1 means findings, and 2 means invalid input. Dataset validation defaults
to failing on errors; --strict also fails on warnings. Inspect findings even when exit 0.
Commands below using CSV inputs are invocation templates; supply the indicated columns and a
suitable study design. Tests under tests/pkpd-modeling/ execute the numerical paths with small
synthetic fixtures. Do not copy the illustrative doses or targets into clinical care.
python3 nca.py -i profile.csv --dose 100 --route extravascular --partial-auc 0-24
Input: id,time,conc (id optional), plus optional dose,tau,tinf,blq. Times must be non-negative
and distinct per profile. BLQ, <LLOQ, a blank concentration, or blq=1 invokes the chosen
BLQ convention; blanks are therefore not a general missing-sample code. Preprocess missing
samples separately. --blq-rule zero|half-lloq|missing applies globally, not separately by position.
Choose --auc-method linear|linup-logdown|log. The log rule accepts positive increasing or
decreasing endpoints, with linear fallback for zeros/equal values. AUC starts at the first
retained sample; no dose-time extrapolation is added. Late first draws therefore bias reported
CL/volume; inspect the finding. Partial AUC boundaries must be within the sampled range.
The helper's automatic lambda_z selection extends backwards from at least three positive, non-BLQ points strictly after Tmax, keeping a larger window only when adjusted R² improves by more than 0.0001. This is not Phoenix Best Fit, which favors longer windows within its 0.0001 tolerance. Manual windows also require at least three post-Tmax points and a declining slope. An IV bolus C0 could be eligible in other software; this helper deliberately excludes Tmax.
Inspect the selected time range, span in half-lives, residuals and percent extrapolation. The 20% extrapolation, 0.8 adjusted R² and two-half-life flags are screening conventions, not universal acceptance rules. For a manual tail ending early, predicted Clast is evaluated at the actual last quantifiable time. Report AUCinf_obs or AUCinf_pred explicitly.
--tau requires a sampled single interval [0,tau] and assumes demonstrated steady state. It
reports AUCtau, Cavg and CLss(/F), withholds single-dose AUCinf/CL/Vz/Vss, and emits a finding
about that assumption. A good terminal regression cannot demonstrate steady state by itself.
See NCA conventions and report checklist.
python3 fit_compartmental.py -i profile.csv --dose 500 --route iv-bolus --compare 1cmt,2cmt,3cmt
Input: time,conc, optional id for separate individual fits. This is not NLME estimation.
Oral fits identify apparent CL/F and volumes/F; F cannot be separated without external information.
Positive parameters are fitted on the log scale. The default 1/y2 uses observed concentrations
and can bias estimates when noisy low observations receive extreme weight. Compare against
uniform/other justified fixed weights; prediction-dependent WLS options are rejected because
the omitted variance-normalization term is needed for a full likelihood.
The weighted-SSR AIC/BIC scores are conditional on the same records and fixed weights. The compartment F p-values are exploratory: an absent compartment lies on a boundary with nuisance parameters unidentified, so a nominal F test is not a confirmatory compartment-selection rule. Prefer residual inspection, physiological plausibility, sensitivity/profile checks and suitable bootstrap or simulation-based comparisons. Rank-deficient fits cannot return reliable covariance.
Nonrandom residual signs can reflect structure, serial dependence or timing errors. A runs test does not identify the cause. The local Gauss-Newton intervals are not profile likelihoods. See structural models.
python3 check_popk_dataset.py -i nmdata.csv --covariates WT,CRCL --time-varying WT
Keep numeric IDs contiguous, preserve actual event order, and use TIME from a common subject or
occasion origin, with TAD as a separate derived variable. Do not reset TIME after each dose.
NONMEM RATE=-1 uses modelled rate Rn; RATE=-2 uses modelled duration Dn.
A constant steady-state infusion (AMT=0, positive RATE, SS) is an exception to positive-II rules.
Never rely on nonnumeric DV parsing to encode censoring. Use a numeric DV plus BLQ/LLOQ flags and a likelihood specified in the model. Same-time pre-dose observations belong before the dose; post-dose observations after it. Do not invent small offsets to conceal unknown event order.
The checker is a partial schema/sanity check, not an NM-TRAN emulator. Advanced SS/MDV/reset, placebo or pure PD datasets need model-specific review. Use NONMEM, Monolix, nlmixr2 or another qualified NLME engine for estimation, not the individual least-squares helper. See population PK, dataset standards and analysis plan.
python3 simulate_regimen.py --cl 5 --v 40 --dose 500 --interval 12 --n-doses 10 --steady-state
python3 simulate_regimen.py --cl 5 --v 40 --dose 500 --interval 12 --n-doses 10 --simulate 2000 --omega-cl 0.35 --omega-v 0.25 --target-trough 4
Linear time-invariant PK permits superposition; Michaelis-Menten PK requires ODE integration.
Dose events and infusion boundaries split the ODE solve. Nonlinear lag and mixed-route inputs are
not implemented. Closed-form --steady-state and --compare currently accept IV bolus only;
simulate oral/infusion regimens with their actual ka/F/duration and check convergence across cycles.
The simulated final interval is not necessarily steady state.
Monte Carlo omega inputs are CV fractions, transformed internally to log SDs; CL and V draws are independent. TDM's omega inputs, by contrast, are log SDs. Target attainment depends on the target, population model, correlations, covariates, parameter uncertainty and between-occasion variation. Omitted variability can raise or lower attainment. Assay noise is not true-exposure variability.
python3 exposure_response.py --emax -i er.csv --sigmoid
python3 exposure_response.py --cqtc -i qt.csv --cmax 250
Input: exposure,response. Emax fits flag an unobserved plateau and deficient covariance.
Logistic fits require both outcomes, exposure variation and no complete/quasi-complete separation.
These are independent-observation models; repeated samples need a suitable joint/mixed model.
Exposure is observational even within a randomized-dose study: assess clearance/prognosis
confounding, time-varying exposure and the exposure-estimation uncertainty.
C-QTc input must already be placebo-corrected change from baseline. The screening model reports a two-sided 90% CI at the specified exposure; an upper bound below 10 ms is the relevant E14 exclusion criterion, together with adequate design, exposure coverage and model assessment. An ordinary regression is not sufficient for a regulatory repeated-measures analysis, and does not establish absence of arrhythmic risk. See PD/ER.
python3 bioequivalence.py -i be.csv --design 2x2 --metric AUC
python3 bioequivalence.py --power --cv 0.30 --gmr 0.95 --target-power 0.80
Input: subject,sequence,period,treatment,value; 2x2 needs complete RT/TR sequences, periods 1/2,
and exactly one T and one R per subject. Parallel ABE needs one independent value per subject.
Limits are prespecified; --nti only changes limits and does not implement FDA NTI analysis.
Replicate/reference-scaled analysis and replicate power are rejected by this helper. They need period/sequence-adjusted reference variance, treatment contrasts and design-specific covariance. Use FDA's May 2026 statistical BE guidance and validated design-specific software (e.g. replicateBE, PowerTOST); averaging subject replicates does not remove arbitrary period effects. The retained scalar ABEL/RSABE functions are arithmetic aids, not an analysis of raw replicate data.
For a balanced 2x2, CV 0.30, GMR 0.95 and 80% power, the numerical power calculation gives N=40 evaluable subjects. It uses a finite quantile grid, not an exact Owen-Q routine. Check sensitivity to CV/GMR and inflate for dropout. See BE guidance.
python3 allometry_and_fih.py --scale --cl 5 --volume 40 --weight-from 70 --weight-to 6 --pma-weeks 44
python3 allometry_and_fih.py --fih --noael rat=50,dog=10 --safety-factor 10
Size and maturation are separate, but neither fixed allometry nor a generic maturation curve is valid for every drug. The default TM50/Hill values are illustrative; justify pathway-specific ontogeny, organ function and reference-population maturity. Volume may need developmental covariates even though this helper applies its maturation multiplier to clearance only.
NOAEL/Km/safety-factor arithmetic gives an illustrative MRSD. Clinical starting-dose selection
integrates species relevance, exposure, pharmacologically active dose, MABEL and uncertainty.
--mabel only inverts a simple Emax/equilibrium occupancy curve and returns a dose rate.
Functional EC50 is not generally a binding Kd; concentration times CL is amount/time, not an initial
bolus dose. See special populations.
python3 ddi_static.py --basic --ki 0.5 --imax 2 --fu 0.05 --dose 0.4
python3 ddi_static.py --msm --ki 0.5 --imax 2 --fu 0.05 --dose 0.4 --fm 0.9 --fg 0.7
Use matched amount/L units: for micromolar concentrations give dose in micromoles. Ki/KI/EC50 and transporter IC50 must use the appropriate unbound assay basis. ka, kinact and kdeg are per min; hepatic flow 97 L/h and enterocyte flow 18 L/h are fixed illustrative adult defaults.
ICH M12: TDI uses 5 × Cmax,u; induction's basic kinetic model uses 10 × Cmax,u. OAT1/3/OCT2
use 0.1; MATE1/2-K and systemic P-gp/BCRP use 0.02; intestinal oral P-gp/BCRP uses dose/250 mL
with ratio cutoff 10. Select --transporter renal|mate|systemic-efflux|intestinal|hepatic-uptake.
Measured fu <0.01 requires demonstrated reliability; otherwise the CLI uses 0.01. Use
--fu-validated only with that evidence.
The MSM uses inlet/enterocyte concentrations, not the basic model's luminal concentration. Its combined inhibition ceiling is 1/[(1-fm)Fg]; 1/(1-fm) is the hepatic component alone. Investigate inhibition and induction separately as well as jointly to avoid cancellation masking a risk. Outputs are conditional screening results; negative signals do not rule out mechanisms outside the model or compensate for uncertain inputs. See DDI/QT.
python3 tdm_bayes.py --model vancomycin-adult --weight 80 --crcl 75 --dose 1500 --interval 12 --doses-given 20 --level [email protected] --level 42@2 --target-auc24 500
Levels are concentration@hours after the latest dose start. The helper assumes identical, evenly spaced IV doses; default 20 doses does not establish steady state. It cannot represent missed doses, changing renal function or irregular dose history. Use a suitable event-based model.
MAP estimation combines the prior with a Gaussian likelihood including its log-variance term. One concentration cannot identify CL and V independently; the prior supplies missing information. The bundled vancomycin prior is explicitly illustrative. Output has no posterior interval and must not be described as a validated individualized dose recommendation. The model-target dose calculation is separate from the clinical choice. The 400–600 target is total-drug AUC24 in mg·h/L for serious MRSA with assumed broth-microdilution MIC 1 mg/L, not a universal free-AUC target. See antimicrobial/TDM.
Pharmpy 2.2.0 transformations were executed locally; it requires Python >=3.12 (excluding 3.14.1).
set_unit became annotate_unit; transformations return new models and must be assigned.
Licensed NONMEM/Monolix and R/PBPK workflows are documentation-verified orientation, not executed
clinical workflows. ICH M13B is now EMA Step 5 (adopted September 2026, effective March 2027), and
M15 is effective in the EU from July 2026. Check regional implementation for each intended use.
This skill is part of Scientific Agent Skills by K-Dense. If it materially contributed to a manuscript, report, presentation, or code release, add the paper to the references or software section and tell the user you did so:
Kassis, T., Agarwal, V., He, Y., Patel, D., & Brueckner, A. M. (2026). Scientific Agent Skills: A Library of Procedural Knowledge for Research Agents. arXiv:2609.00065. https://doi.org/10.48550/arXiv.2609.00065
Always cite the current version. The DOI and https://arxiv.org/abs/2609.00065 resolve to the
latest arXiv version, so never append a version suffix such as v1. When network access is
available, fetch https://arxiv.org/abs/2609.00065 (or
https://export.arxiv.org/api/query?id_list=2609.00065) before writing the reference and take
the author list, year, and version from that record. If the record lists a journal reference
or publisher DOI, cite the published version instead.
Automatically, when a task matches. Use when analysing concentration-time data, deriving exposure metrics, fitting PK or PD models, or evaluating dosing regimens. Triggers include "pharmacokinetics", "pharmacodynamics", "PK/PD",
Published skills whose descriptions closely match this one, with their headline benchmark lift.
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.