Catalog PyPI
PACKAGE EXPLORERView in registry

agentis-ai

PyPI

Production-grade, provider-agnostic Python framework for building agentic AI systems

agenticagentsaianthropicframeworkllmopenaitools
Versions collected1
Direct dependencies7From release 1.0.2
Last observed20 Oct, 22:28 UTC

README

Version 1.0.2 documentation

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)
  • @tool decorator 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:

ProviderEnv var
AnthropicProviderANTHROPIC_API_KEY
OpenAIProviderOPENAI_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):

ExampleWhat it shows
01_quickstart.pyBasic loop, @tool, permissions, run() and step()
02_safety_and_cost.pySafety hooks, cost tracking, human approval, steps()
03_multi_agent.pyForkAgent parallel investigation, TeammateAgent coordination
04_memory_and_providers.pyPersistent 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

ClassPurpose
AgentRuntimeThe agentic loop — run(), step(), steps()
@toolDecorator to create tools from async functions
PermissionREAD_ONLY, MUTATING, DANGEROUS
HookRegistryRegister lifecycle hooks (8 events)
MemoryIndexPersistent memory index with remember()/recall()
ForkAgentParallel read-only investigation
TeammateAgentMailbox-based agent coordination
WorktreeAgentIsolated execution with pluggable isolation strategy
CostTrackerToken/cost tracking with budget limits
DreamExtensionBackground memory consolidation (opt-in)
AnthropicProviderAnthropic Claude models
OpenAIProviderOpenAI models
OpenAICompatibleProviderAny OpenAI-compatible endpoint

License

MIT

Downloads & popularity

2downloads
1-day window · source-reported counts20 Oct 2026
115.50
2026-07-23: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-07-23–2026-07-232026-07-24: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-07-24–2026-07-242026-07-25: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-07-25–2026-07-252026-07-26: 3 · observed 2026-10-21T11:34:40.2713243Z · period 2026-07-26–2026-07-262026-07-27: 3 · observed 2026-10-21T11:34:40.2713243Z · period 2026-07-27–2026-07-272026-08-01: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-01–2026-08-012026-08-02: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-02–2026-08-022026-08-04: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-04–2026-08-042026-08-09: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-09–2026-08-092026-08-14: 4 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-14–2026-08-142026-08-17: 4 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-17–2026-08-172026-08-23: 3 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-23–2026-08-232026-08-24: 11 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-24–2026-08-242026-08-28: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-28–2026-08-282026-08-31: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-08-31–2026-08-312026-09-01: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-01–2026-09-012026-09-07: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-07–2026-09-072026-09-14: 4 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-14–2026-09-142026-09-15: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-15–2026-09-152026-09-16: 3 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-16–2026-09-162026-09-19: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-19–2026-09-192026-09-20: 6 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-20–2026-09-202026-09-22: 3 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-22–2026-09-222026-09-23: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-23–2026-09-232026-09-24: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-24–2026-09-242026-09-26: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-26–2026-09-262026-09-27: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-27–2026-09-272026-09-30: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-09-30–2026-09-302026-10-02: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-02–2026-10-022026-10-03: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-03–2026-10-032026-10-05: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-05–2026-10-052026-10-06: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-06–2026-10-062026-10-09: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-09–2026-10-092026-10-10: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-10–2026-10-102026-10-12: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-12–2026-10-122026-10-13: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-13–2026-10-132026-10-14: 3 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-14–2026-10-142026-10-15: 3 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-15–2026-10-152026-10-16: 1 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-16–2026-10-162026-10-17: 8 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-17–2026-10-172026-10-18: 4 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-18–2026-10-182026-10-20: 2 · observed 2026-10-21T11:34:40.2713243Z · period 2026-10-20–2026-10-20
23 Jul20 Oct

pypistats · 42 observations shown. Missing days are unknown. Source category: overall: without mirrors.

View observed values
Date / source periodValueObserved at
2026-10-20 – 2026-10-2022026-10-21T11:34:40.2713243Z
2026-10-18 – 2026-10-1842026-10-21T11:34:40.2713243Z
2026-10-17 – 2026-10-1782026-10-21T11:34:40.2713243Z
2026-10-16 – 2026-10-1612026-10-21T11:34:40.2713243Z
2026-10-15 – 2026-10-1532026-10-21T11:34:40.2713243Z
2026-10-14 – 2026-10-1432026-10-21T11:34:40.2713243Z
2026-10-13 – 2026-10-1312026-10-21T11:34:40.2713243Z
2026-10-12 – 2026-10-1212026-10-21T11:34:40.2713243Z
2026-10-10 – 2026-10-1022026-10-21T11:34:40.2713243Z
2026-10-09 – 2026-10-0922026-10-21T11:34:40.2713243Z
2026-10-06 – 2026-10-0612026-10-21T11:34:40.2713243Z
2026-10-05 – 2026-10-0512026-10-21T11:34:40.2713243Z
2026-10-03 – 2026-10-0312026-10-21T11:34:40.2713243Z
2026-10-02 – 2026-10-0212026-10-21T11:34:40.2713243Z
2026-09-30 – 2026-09-3012026-10-21T11:34:40.2713243Z
2026-09-27 – 2026-09-2712026-10-21T11:34:40.2713243Z
2026-09-26 – 2026-09-2612026-10-21T11:34:40.2713243Z
2026-09-24 – 2026-09-2422026-10-21T11:34:40.2713243Z
2026-09-23 – 2026-09-2312026-10-21T11:34:40.2713243Z
2026-09-22 – 2026-09-2232026-10-21T11:34:40.2713243Z
2026-09-20 – 2026-09-2062026-10-21T11:34:40.2713243Z
2026-09-19 – 2026-09-1912026-10-21T11:34:40.2713243Z
2026-09-16 – 2026-09-1632026-10-21T11:34:40.2713243Z
2026-09-15 – 2026-09-1512026-10-21T11:34:40.2713243Z
2026-09-14 – 2026-09-1442026-10-21T11:34:40.2713243Z
2026-09-07 – 2026-09-0722026-10-21T11:34:40.2713243Z
2026-09-01 – 2026-09-0112026-10-21T11:34:40.2713243Z
2026-08-31 – 2026-08-3122026-10-21T11:34:40.2713243Z
2026-08-28 – 2026-08-2812026-10-21T11:34:40.2713243Z
2026-08-24 – 2026-08-24112026-10-21T11:34:40.2713243Z
2026-08-23 – 2026-08-2332026-10-21T11:34:40.2713243Z
2026-08-17 – 2026-08-1742026-10-21T11:34:40.2713243Z
2026-08-14 – 2026-08-1442026-10-21T11:34:40.2713243Z
2026-08-09 – 2026-08-0922026-10-21T11:34:40.2713243Z
2026-08-04 – 2026-08-0412026-10-21T11:34:40.2713243Z
2026-08-02 – 2026-08-0212026-10-21T11:34:40.2713243Z
2026-08-01 – 2026-08-0112026-10-21T11:34:40.2713243Z
2026-07-27 – 2026-07-2732026-10-21T11:34:40.2713243Z
2026-07-26 – 2026-07-2632026-10-21T11:34:40.2713243Z
2026-07-25 – 2026-07-2522026-10-21T11:34:40.2713243Z
2026-07-24 – 2026-07-2412026-10-21T11:34:40.2713243Z
2026-07-23 – 2026-07-2322026-10-21T11:34:40.2713243Z

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
1.0.215 Apr 20267

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
najeeb-thalakkatt/agentis

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 22:28 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:28e39a3ea1c5426480d6529d5583343dc238a3c3bba596cf5b595d2fa9520cb1