Skip to main content

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

Project description

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:

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agentis_ai-1.0.2.tar.gz (72.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agentis_ai-1.0.2-py3-none-any.whl (70.8 kB view details)

Uploaded Python 3

File details

Details for the file agentis_ai-1.0.2.tar.gz.

File metadata

  • Download URL: agentis_ai-1.0.2.tar.gz
  • Upload date:
  • Size: 72.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for agentis_ai-1.0.2.tar.gz
Algorithm Hash digest
SHA256 da0cf5c8a89027ddf8446208d4e65099b1f389b71c1b1bfe2905b2731250aa21
MD5 f399272c68d39eec34fd2418bc578f41
BLAKE2b-256 9df4b618eaa763619c0b0f3d85cd95da730b7532107e069d509b8c4440315eba

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentis_ai-1.0.2.tar.gz:

Publisher: publish.yml on najeeb-thalakkatt/agentis

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file agentis_ai-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: agentis_ai-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 70.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for agentis_ai-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 8096d84a66e054281add819756f5a0246ed3ba62efc36ea9c18bbd087bb9a493
MD5 a2a5b18104526c5e1e725fd8f160d13e
BLAKE2b-256 4580b60a7f1599e4acdc669fe5088ec4acf8f494bf4e45a25d8fe127795489ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for agentis_ai-1.0.2-py3-none-any.whl:

Publisher: publish.yml on najeeb-thalakkatt/agentis

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page