Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build Python agents with Agentica SDK - @agentic decorator, spawn(), persistence, MCP integration
.claude/skills/agentica-sdk/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 160% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 49% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 64% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 49% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 59% | 0% |
Build AI agents in Python using the Agentica framework. Agents can implement functions, maintain state, use tools, and coordinate with each other.
Use this skill when:
pythonfrom agentica import agentic @agentic() async def add(a: int, b: int) -> int: """Returns the sum of a and b""" ... result = await add(1, 2) # Agent computes: 3
pythonfrom agentica import spawn agent = await spawn(premise="You are a truth-teller.") result: bool = await agent.call(bool, "The Earth is flat") # Returns: False
python# String (default) result = await agent.call("What is 2+2?") # Typed output result: int = await agent.call(int, "What is 2+2?") result: dict[str, int] = await agent.call(dict[str, int], "Count items") # Side-effects only await agent.call(None, "Send message to John")
python# Premise: adds to default system prompt agent = await spawn(premise="You are a math expert.") # System: full control (replaces default) agent = await spawn(system="You are a JSON-only responder.")
pythonfrom agentica import agentic, spawn # In decorator @agentic(scope={'web_search': web_search_fn}) async def researcher(query: str) -> str: """Research a topic.""" ... # In spawn agent = await spawn( premise="Data analyzer", scope={"analyze": custom_analyzer} ) # Per-call scope result = await agent.call( dict[str, int], "Analyze the dataset", dataset=data, # Available as 'dataset' analyzer=custom_fn # Available as 'analyzer' )
pythonfrom slack_sdk import WebClient slack = WebClient(token=SLACK_TOKEN) # Extract specific methods @agentic(scope={ 'list_users': slack.users_list, 'send_message': slack.chat_postMessage }) async def team_notifier(message: str) -> None: """Send team notifications.""" ...
pythonagent = await spawn(premise="Helpful assistant")
__init__)pythonfrom agentica.agent import Agent class CustomAgent: def __init__(self): # Synchronous - use Agent() not spawn() self._brain = Agent( premise="Specialized assistant", scope={"tool": some_tool} ) async def run(self, task: str) -> str: return await self._brain(str, task)
python# In spawn agent = await spawn( premise="Fast responses", model="openai:gpt-5" # Default: openai:gpt-4.1 ) # In decorator @agentic(model="anthropic:claude-sonnet-4.5") async def analyze(text: str) -> dict: """Analyze text.""" ...
Available models:
openai:gpt-3.5-turbo, openai:gpt-4o, openai:gpt-4.1, openai:gpt-5anthropic:claude-sonnet-4, anthropic:claude-opus-4.1anthropic:claude-sonnet-4.5, anthropic:claude-opus-4.5google/gemini-2.5-flash)python@agentic(persist=True) async def chatbot(message: str) -> str: """Remembers conversation history.""" ... await chatbot("My name is Alice") await chatbot("What's my name?") # Knows: Alice
For spawn() agents, state is automatic across calls to the same instance.
pythonfrom agentica import spawn, MaxTokens # Simple limit agent = await spawn( premise="Brief responses", max_tokens=500 ) # Fine-grained control agent = await spawn( premise="Controlled output", max_tokens=MaxTokens( per_invocation=5000, # Total across all rounds per_round=1000, # Per inference round rounds=5 # Max inference rounds ) )
pythonfrom agentica import spawn, last_usage, total_usage agent = await spawn(premise="You are helpful.") await agent.call(str, "Hello!") # Agent method usage = agent.last_usage() print(f"Last: {usage.input_tokens} in, {usage.output_tokens} out") usage = agent.total_usage() print(f"Total: {usage.total_tokens} processed") # For @agentic functions @agentic() async def my_fn(x: str) -> str: ... await my_fn("test") print(last_usage(my_fn)) print(total_usage(my_fn))
pythonfrom agentica import spawn from agentica.logging.loggers import StreamLogger import asyncio agent = await spawn(premise="You are helpful.") stream = StreamLogger() with stream: result = asyncio.create_task( agent.call(bool, "Is Paris the capital of France?") ) # Consume stream FIRST for live output async for chunk in stream: print(chunk.content, end="", flush=True) # chunk.role is 'user', 'agent', or 'system' # Then await result final = await result
pythonfrom agentica import spawn, agentic # Via config file agent = await spawn( premise="Tool-using agent", mcp="path/to/mcp_config.json" ) @agentic(mcp="path/to/mcp_config.json") async def tool_user(query: str) -> str: """Uses MCP tools.""" ...
mcp_config.json format:
json{ "mcpServers": { "tavily-remote-mcp": { "command": "npx -y mcp-remote https://mcp.tavily.com/mcp/?tavilyApiKey=<key>", "env": {} } } }
./logs/agent-<id>.logpythonfrom agentica.logging.loggers import FileLogger, PrintLogger from agentica.logging.agent_logger import NoLogging # File only with FileLogger(): agent = await spawn(premise="Debug agent") await agent.call(int, "Calculate") # Silent with NoLogging(): agent = await spawn(premise="Silent agent")
python# Listeners are in agent_listener submodule (NOT exported from agentica.logging) from agentica.logging.agent_listener import ( PrintOnlyListener, # Console output only FileOnlyListener, # File logging only StandardListener, # Both console + file (default) NoopListener, # Silent - no logging ) agent = await spawn( premise="Custom logging", listener=PrintOnlyListener ) # Silent agent agent = await spawn( premise="Silent agent", listener=NoopListener )
pythonfrom agentica.logging.agent_listener import ( set_default_agent_listener, get_default_agent_listener, PrintOnlyListener, ) set_default_agent_listener(PrintOnlyListener) set_default_agent_listener(None) # Disable all
pythonfrom agentica.errors import ( AgenticaError, # Base for all SDK errors RateLimitError, # Rate limiting InferenceError, # HTTP errors from inference MaxTokensError, # Token limit exceeded MaxRoundsError, # Max inference rounds exceeded ContentFilteringError, # Content filtered APIConnectionError, # Network issues APITimeoutError, # Request timeout InsufficientCreditsError,# Out of credits OverloadedError, # Server overloaded ServerError, # Generic server error ) try: result = await agent.call(str, "Do something") except RateLimitError: await asyncio.sleep(60) result = await agent.call(str, "Do something") except MaxTokensError: # Reduce scope or increase limits pass except ContentFilteringError: # Content was filtered pass except InferenceError as e: logger.error(f"Inference failed: {e}") except AgenticaError as e: logger.error(f"SDK error: {e}")
pythonclass DataValidationError(Exception): """Invalid input data.""" pass @agentic(DataValidationError) # Pass exception type async def analyze(data: str) -> dict: """ Analyze data. Raises: DataValidationError: If data is malformed """ ... try: result = await analyze(raw_data) except DataValidationError as e: logger.warning(f"Invalid: {e}")
pythonfrom agentica.agent import Agent class ResearchAgent: def __init__(self, web_search_fn): self._brain = Agent( premise="Research assistant.", scope={"web_search": web_search_fn} ) async def research(self, topic: str) -> str: return await self._brain(str, f"Research: {topic}") async def summarize(self, text: str) -> str: return await self._brain(str, f"Summarize: {text}")
pythonclass LeadResearcher: def __init__(self): self._brain = Agent( premise="Coordinate research across subagents.", scope={"SubAgent": ResearchAgent} ) async def __call__(self, query: str) -> str: return await self._brain(str, query) lead = LeadResearcher() report = await lead("Research AI agent frameworks 2025")
pythonfrom agentica import initialize_tracing # Initialize tracing (returns TracerProvider) tracer = initialize_tracing( service_name="my-agent-app", environment="development", # Optional tempo_endpoint="http://localhost:4317", # Optional: Grafana Tempo organization_id="my-org", # Optional log_level="INFO", # DEBUG, INFO, WARNING, ERROR instrument_httpx=False, # Optional: trace HTTP calls )
pythonfrom agentica import enable_sdk_logging # Enable internal SDK logs (for debugging the SDK itself) disable_fn = enable_sdk_logging(log_tags="1") # ... run agents ... disable_fn() # Disable when done
python# Main imports from agentica from agentica import ( # Core Agent, # Synchronous agent class agentic, # @agentic decorator spawn, # Async agent creation # Configuration ModelStrings, # Model string type hints AgenticFunction, # Agentic function type # Token tracking last_usage, # Get last call's token usage total_usage, # Get cumulative token usage # Tracing/Logging initialize_tracing, # OpenTelemetry setup enable_sdk_logging, # SDK debug logs # Version __version__, # "0.3.1" )
Before using Agentica:
@agentic() MUST be asyncspawn() returns awaitable - use await spawn(...)agent.call() is awaitable - use await agent.call(...)call() is return type, second is prompt stringpersist=True for conversation memory in @agenticAgent() (not spawn()) in synchronous __init__agentica.logging.agent_listener (NOT agentica.logging)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 7,745 | 5,433 | -30% | 1 | 1 | 0% | 1,539 | 3,999 | +160% | 0 | 0 | — |
case-02 | fail→pass | 16,053 | 9,690 | -40% | 1 | 1 | 0% | 3,343 | 4,965 | +49% | 0 | 0 | — |
case-03 | fail→pass | 15,393 | 8,899 | -42% | 1 | 1 | 0% | 2,885 | 4,729 | +64% | 0 | 0 | — |
case-08 | pass→pass | 16,524 | 2,048 | -88% | 1 | 1 | 0% | 2,575 | 3,428 | +33% | 0 | 0 | — |
case-04 | fail→pass | 13,481 | 5,865 | -56% | 1 | 1 | 0% | 2,938 | 4,377 | +49% | 0 | 0 | — |
case-05 | fail→pass | 14,020 | 3,979 | -72% | 1 | 1 | 0% | 2,459 | 3,916 | +59% | 0 | 0 | — |
case-06 | fail→pass | 13,815 | 4,103 | -70% | 1 | 1 | 0% | 2,652 | 3,766 | +42% | 0 | 0 | — |
case-07 | fail→pass | 15,095 | 2,379 | -84% | 1 | 1 | 0% | 2,452 | 3,544 | +45% | 0 | 0 | — |
case-09 | fail→pass | 9,425 | 2,111 | -78% | 1 | 1 | 0% | 1,790 | 3,571 | +99% | 0 | 0 | — |
case-10 | fail→pass | 21,001 | 2,436 | -88% | 1 | 1 | 0% | 3,431 | 3,627 | +6% | 0 | 0 | — |
case-11 | fail→pass | 17,888 | 2,686 | -85% | 1 | 1 | 0% | 3,772 | 3,730 | -1% | 0 | 0 | — |
case-12 | fail→pass | 11,369 | 2,487 | -78% | 1 | 1 | 0% | 2,034 | 3,647 | +79% | 0 | 0 | — |
case-13 | fail→pass | 15,947 | 4,620 | -71% | 1 | 1 | 0% | 3,343 | 4,156 | +24% | 0 | 0 | — |
case-14 | fail→pass | 16,289 | 9,047 | -44% | 1 | 1 | 0% | 1,451 | 3,569 | +146% | 0 | 0 | — |
case-15 | fail→pass | 11,817 | 3,335 | -72% | 1 | 1 | 0% | 2,163 | 3,792 | +75% | 0 | 0 | — |
case-16 | fail→pass | 7,743 | 1,905 | -75% | 1 | 1 | 0% | 1,658 | 3,547 | +114% | 0 | 0 | — |
case-17 | fail→pass | 12,423 | 3,079 | -75% | 1 | 1 | 0% | 2,340 | 3,635 | +55% | 0 | 0 | — |
case-18 | fail→pass | 14,060 | 5,039 | -64% | 1 | 1 | 0% | 2,560 | 4,178 | +63% | 0 | 0 | — |
case-19 | fail→pass | 15,344 | 9,847 | -36% | 1 | 1 | 0% | 2,917 | 5,262 | +80% | 0 | 0 | — |
case-20 | pass→pass | 4,154 | 2,522 | -39% | 1 | 1 | 0% | 572 | 3,664 | +541% | 0 | 0 | — |
case-21 | pass→pass | 2,850 | 4,095 | +44% | 1 | 1 | 0% | 456 | 3,881 | +751% | 0 | 0 | — |
case-22 | pass→pass | 3,941 | 2,960 | -25% | 1 | 1 | 0% | 729 | 3,735 | +412% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +82 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/28/2026 | +70% |
Other measured skills in the registry, with their headline benchmark lift.