Agentis
The harness your model is missing. Production-grade, provider-agnostic Python framework for building agentic AI systems.
What Agentis Does
- Agentic loop with three APIs:
run()(autonomous),step()(single turn),steps()(async iterator) @tooldecorator with permission system: READ_ONLY (parallel), MUTATING (serial), DANGEROUS (approval required)- Safety hooks that the LLM cannot bypass: block destructive commands, path sandboxing, human approval gates
- Cost tracking with per-turn token accounting and budget limits
- Persistent memory across sessions: lightweight index in context, full data on disk
- Multi-agent: ForkAgent for parallel read-only investigation, TeammateAgent for mailbox-based coordination
- Context compaction: five-layer tiered eviction so long sessions don't overflow
- Provider-agnostic: Anthropic, OpenAI, any OpenAI-compatible endpoint. Swap in one line.
Install
pip install agentis-ai # Core (aiofiles only)
pip install agentis-ai[anthropic] # + Anthropic SDK
pip install agentis-ai[openai] # + OpenAI SDK
pip install agentis-ai[all] # Everything
Requires Python 3.11+.
Scaffold a new project
pip install agentis-ai[anthropic]
agentis new myagent
cd myagent
cp .env.example .env # paste your ANTHROPIC_API_KEY
pip install -e '.[anthropic]'
python main.py "what is 17 + 25?"
agentis doctor prints a diagnostic summary (SDKs installed, env vars set). Exit code 0 means you're ready.
Environment variables
Each provider declares an env var and exposes from_env() for explicit auto-construction:
| Provider | Env var |
|---|---|
AnthropicProvider |
ANTHROPIC_API_KEY |
OpenAIProvider |
OPENAI_API_KEY |
from agentis import AnthropicProvider
provider = AnthropicProvider.from_env() # raises ConfigError naming the var if missing
Auth, rate-limit, and network failures surface as AuthenticationError, RateLimitError, and ProviderNetworkError (all subclasses of ProviderError) — each with an actionable message, not a generic wrap.
Quickstart
import asyncio
from agentis import AgentRuntime, AnthropicProvider, tool, Permission
@tool()
async def lookup_weather(city: str) -> str:
"""Look up current weather for a city."""
return f"72F and sunny in {city}"
@tool(permission=Permission.MUTATING)
async def save_report(content: str) -> bool:
"""Save a weather report."""
print(f"Saved: {content}")
return True
async def main():
provider = AnthropicProvider.from_env() # reads ANTHROPIC_API_KEY
agent = AgentRuntime(
provider=provider,
tools=[lookup_weather, save_report],
system_prompt="You are a weather assistant.",
)
result = await agent.run("What's the weather in Portland? Save a report.")
print(result)
asyncio.run(main())
The agent will call lookup_weather (parallel-safe), then save_report (serialized behind a lock), then respond. All tool calls go through safety hooks. All results are structured — the LLM never parses raw output.
Architecture
+------------------+
| Your Code |
+--------+---------+
|
run() / step() / steps()
|
+-------------v--------------+
| AgentRuntime |
| |
| Session HookRegistry |
| MemoryIndex Compactor |
| ToolOrchestrator |
+-------------+---------------+
|
+-------------+-------------+
| | |
+-----v----+ +-----v----+ +------v-----+
| Anthropic | | OpenAI | | Compatible |
| Provider | | Provider | | (Ollama,..)|
+----------+ +----------+ +------------+
Features
Custom Tools
from agentis import tool, Permission
@tool()
async def search(query: str, max_results: int = 10) -> list[str]:
"""Search the knowledge base."""
... # READ_ONLY by default — runs in parallel
@tool(permission=Permission.MUTATING)
async def write_file(path: str, content: str) -> bool:
"""Write to a file."""
... # Serialized behind an asyncio.Lock
@tool(permission=Permission.DANGEROUS)
async def drop_table(name: str) -> str:
"""Drop a database table."""
... # Requires human approval via callback
Type hints become JSON Schema automatically. Exceptions become ToolResult(success=False) — tools never crash the agent.
Safety Hooks
from agentis import HookRegistry, LifecycleEvent
from agentis.hooks.builtins import block_destructive_commands, create_path_sandbox
hooks = HookRegistry()
# Block rm -rf, DROP DATABASE, fork bombs, etc.
hooks.register(LifecycleEvent.PRE_TOOL_USE, block_destructive_commands)
# Restrict file access to the project directory
hooks.register(
LifecycleEvent.PRE_TOOL_USE,
create_path_sandbox(["/home/user/project"]),
)
Hooks are code, not prompts. The LLM cannot talk its way past them. PRE_TOOL_USE is fail-closed: if a hook crashes, the operation is denied.
Cost Tracking
from agentis import CostTracker
tracker = CostTracker(budget_usd=5.00)
agent = AgentRuntime(
provider=provider,
extensions=[tracker],
...
)
await agent.run("Do the thing")
print(tracker.total_cost()) # $0.0234
print(tracker.is_over_budget()) # False
print(tracker.get_report()) # Full breakdown
Human Approval
from agentis import ApprovalRequest
async def ask_user(request: ApprovalRequest) -> bool:
answer = input(f"Allow {request.tool_name}({request.arguments})? [y/n] ")
return answer.lower() == "y"
agent = AgentRuntime(
provider=provider,
tools=[dangerous_tool],
approval_callback=ask_user,
)
DANGEROUS tools pause and ask. The callback receives rich context: tool name, arguments, reason, session ID, turn number.
Multi-Agent
ForkAgent — cheap parallel clones for read-only investigation:
from agentis import ForkAgent
results = await ForkAgent.parallel_investigate(
parent=agent,
tasks=["Check auth module", "Check database module", "Check API module"],
)
# 3 results, run concurrently. On providers with prompt caching: ~1x cost.
TeammateAgent — independent agents with mailbox coordination:
from agentis import TeammateAgent, InMemoryMailbox
mailbox = InMemoryMailbox()
researcher = TeammateAgent(name="researcher", runtime=runtime1, mailbox=mailbox)
writer = TeammateAgent(name="writer", runtime=runtime2, mailbox=mailbox)
await researcher.send("writer", {"findings": "JWT bug in auth.py:42"})
mail = await writer.check_mail() # [{"from": "researcher", "content": {...}}]
Memory
from agentis import MemoryIndex
memory = MemoryIndex(workspace=".agentis/memory")
# Store — only a pointer goes into LLM context
await memory.remember("Auth system", "Uses JWT with 15-min expiry", tags=["security"])
# Recall — full content fetched on demand
content = await memory.recall(topic_id)
# Search
results = await memory.search(tags=["security"])
# Persists across sessions
memory2 = MemoryIndex(workspace=".agentis/memory")
await memory2.load() # Picks up where you left off
The memory index is always in context (~150 chars per entry). Full content lives on disk and is fetched via the built-in recall tool.
Tool Packs
from agentis.packs.filesystem import TOOLS as fs_tools # file_read, file_write, file_edit, list_directory
from agentis.packs.coding import TOOLS as coding_tools # grep, glob
from agentis.packs.shell import TOOLS as shell_tools # bash (DANGEROUS)
from agentis.packs.web import TOOLS as web_tools # http_get, http_post
from agentis.packs.data import TOOLS as data_tools # query_json
agent = AgentRuntime(provider=provider, tools=fs_tools + coding_tools)
Provider Swap
# Anthropic Claude
from agentis import AnthropicProvider
provider = AnthropicProvider(model="claude-sonnet-4-20250514")
# OpenAI
from agentis import OpenAIProvider
provider = OpenAIProvider(model="gpt-4o")
# Any OpenAI-compatible endpoint (Ollama, vLLM, Together, Groq, LM Studio)
from agentis import OpenAICompatibleProvider
provider = OpenAICompatibleProvider(model="llama3", base_url="http://localhost:11434/v1")
Same agent code. Different provider. One line.
Examples
Run any example without API keys (they use a built-in MockProvider):
| Example | What it shows |
|---|---|
01_quickstart.py |
Basic loop, @tool, permissions, run() and step() |
02_safety_and_cost.py |
Safety hooks, cost tracking, human approval, steps() |
03_multi_agent.py |
ForkAgent parallel investigation, TeammateAgent coordination |
04_memory_and_providers.py |
Persistent memory, provider swap |
python examples/01_quickstart.py
python examples/02_safety_and_cost.py
python examples/03_multi_agent.py
python examples/04_memory_and_providers.py
API Quick Reference
| Class | Purpose |
|---|---|
AgentRuntime |
The agentic loop — run(), step(), steps() |
@tool |
Decorator to create tools from async functions |
Permission |
READ_ONLY, MUTATING, DANGEROUS |
HookRegistry |
Register lifecycle hooks (8 events) |
MemoryIndex |
Persistent memory index with remember()/recall() |
ForkAgent |
Parallel read-only investigation |
TeammateAgent |
Mailbox-based agent coordination |
WorktreeAgent |
Isolated execution with pluggable isolation strategy |
CostTracker |
Token/cost tracking with budget limits |
DreamExtension |
Background memory consolidation (opt-in) |
AnthropicProvider |
Anthropic Claude models |
OpenAIProvider |
OpenAI models |
OpenAICompatibleProvider |
Any OpenAI-compatible endpoint |
License
MIT
Release files for agentis-ai 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agentis_ai-1.0.2.tar.gz | 72.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agentis_ai-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 142.9 kB
Release files / agentis_ai-1.0.2.tar.gz
| Download URL | agentis_ai-1.0.2.tar.gz |
|---|---|
| Size | 72.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
da0cf5c8a89027ddf8446208d4e65099b1f389b71c1b1bfe2905b2731250aa21
|
|
BLAKE2b-256 checksum How to use checksums |
9df4b618eaa763619c0b0f3d85cd95da730b7532107e069d509b8c4440315eba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 15, 2026.
Transparency logRelease files / agentis_ai-1.0.2-py3-none-any.whl
| Download URL | agentis_ai-1.0.2-py3-none-any.whl |
|---|---|
| Size | 70.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8096d84a66e054281add819756f5a0246ed3ba62efc36ea9c18bbd087bb9a493
|
|
BLAKE2b-256 checksum How to use checksums |
4580b60a7f1599e4acdc669fe5088ec4acf8f494bf4e45a25d8fe127795489ca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 15, 2026.
Transparency log