mantismantis

Claude Code, for open source.
Any model, any provider.

A Claude-Code-style agent in your terminal, and Anthropic's claude-agent-sdk surface as a library — on any model you can serve, open or closed. The migration is one import.

agent.py
-from claude_agent_sdk import query, ClaudeAgentOptions, tool
+from

That's the whole diff. Code written for Anthropic's SDK runs as-is — mantis keeps the surface you know and swaps what's underneath.

The mantis terminal ships in the same install — a Claude-Code-style coding agent driving the open model you choose.

One kwarg between

OllamavLLMllama.cppTGITogetherFireworksGroqOpenRouterCerebrasOpenAIGeminiModal
two ways in · one pip install

A terminal to code in, and a library to build with.

01

The mantis terminal

Point it at any directory. It reads, writes, edits, greps, and runs shell commands — Claude Code's feel, driving your local Ollama, your vLLM box, or a hosted endpoint. The input stays pinned to the bottom; replies render as Markdown; file edits come back as real, line-numbered diffs.

mantis — ~/code/todo-api
            ▄▀▄▀
           ▄█▀
        ▄██▀▀█▀
    ▄█ ▄███▀▀
 ▄▄██▀▀██▀▀▀▀▀
 ▀▀ █  █▀ ▀▄
 ▄▄▀  ▄▀   ▀▄
build me a fastapi todo app
⚒ Edit app/main.py +12 -0
1+ from fastapi import FastAPI
2+ app = FastAPI()
3+ todos: list[str] = []
Done — run it with uvicorn app.main:app --reload.
✻ Undulating…(3s · esc to interrupt)
02

The Python library

The same engine, as an SDK. A tool-calling loop is a few lines away — and the exact same script runs against Together, Fireworks, vLLM, or Groq by changing one string.

quickstart.py
import asyncio
from mantis_agent import query, MantisAgentOptions, tool, AssistantMessage

@tool
async def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"{city}: 67°F"

async def main():
    async for msg in query(
        prompt="What's the weather in SF?",
        options=MantisAgentOptions(
            model="qwen2.5:1.5b",   # routes to local Ollama automatically
            tools=[get_weather],
            max_turns=5,
        ),
    ):
        if isinstance(msg, AssistantMessage):
            for block in msg.content:
                if hasattr(block, "text"):
                    print(block.text)

asyncio.run(main())
# same script, three backends — change one line
options = MantisAgentOptions(model="qwen2.5:7b")                       # → local Ollama
options = MantisAgentOptions(model="Qwen/Qwen2.5-72B-Instruct-Turbo")  # → Together
options = MantisAgentOptions(model="llama-3.3-70b-versatile",
                            backend="https://api.groq.com/openai/v1")  # → Groq
the whole surface

Everything that makes Claude Code feel finished — on models you choose.

any backend

Name the model and go

A local Ollama, your own GPU server, a hosted provider — even closed models like GPT and Gemini. mantis works out where the model lives and speaks its dialect. Moving is a one-line change, not a rewrite.

tools

Write a function. It becomes a tool.

Decorate any Python function and every model can call it — even the ones that never learned function calling. mantis finds a way, and you never think about it.

mcp

Plug into the MCP ecosystem

Connect the same MCP servers Claude Code uses — filesystems, browsers, databases — or expose your own tools as one. Your open model gets the whole ecosystem.

sessions

Pick up where you left off

Every conversation is saved as it happens. Close the laptop, come back tomorrow, resume — or fork a session and try a different approach. Long chats compact themselves.

sub-agents

Build teams, not monoliths

Hand an agent smaller agents as tools — a researcher, a reviewer, a fixer — and set rules for what each one may touch. Approve, deny, or rewrite any call before it runs.

budget

Spend with a ceiling

Cap any run in dollars or turns. Every response tells you what it cost, and the run stops cleanly before it overspends — no surprise bills from a runaway loop.

universal tool use

Every model gets tool use.

Not every open model knows how to call functions. mantis meets each one where it is — you write the tool once, and it picks the right way in for whatever model is in front of it.

ANative

Models that speak function calling — Qwen, Llama 3, gpt-oss — get called directly. The fast path.

BPrompted

Older models never learned the schema, so mantis teaches it in the prompt and parses the reply. Tool use for models that “can't do tools.”

CConstrained

Where the server can enforce a grammar, the model physically cannot produce a malformed call. The strict path.

ranked · picked by where they run

Pick the highest-ranked model that fits your hardware.

ModelRunsmodel=Notable
Kimi K2.6cloudmoonshotai/Kimi-K2.6-Instruct#1 open-weights GPQA
Qwen3 235B-A22Bcloud · 64 GB+Qwen/Qwen3-235B-A22B-Instruct-TurboApache 2.0, broad leader
GLM-5cloudzai-org/GLM-5Best open Arena Elo
MiniMax M2.5cloudminimaxai/MiniMax-M2.580.2% SWE-bench
DeepSeek-V3.2cloud · 80 GB+deepseek-ai/DeepSeek-V3.2Top general-purpose OSS
gpt-oss-120bcloud · 80 GBgpt-oss:120bOpenAI open, ~o4-mini class
Qwen2.5-Coder 7B8 GB localqwen2.5-coder:7bStrongest small coder
qwen2.5:1.5b4 GB localqwen2.5:1.5bCPU default, tool-capable

Full ranked catalog — 20 hosted + 10 CPU-friendly tiers — in Models & backends.

observability, shipped

See what every run did — and what it cost.

Every run produces a full trace: each turn, each model call, each tool call, with tokens and dollars totalled at the top. Keep it in memory while you develop, or ship the same trace to Datadog, Honeycomb, or any OpenTelemetry pipeline with one line. And traces record which fields a tool was given — never their values — so nothing sensitive leaves the house.

tracing.py
from mantis_agent import Agent, InMemoryTracer

tracer = InMemoryTracer()
agent  = Agent(model="qwen2.5:7b", tools=[...], tracer=tracer)
await agent.run(...)

tracer.summary()            # turns / tokens / cost_usd on the root span
tracer.write_jsonl("t.jsonl")

# ship the same spans to Datadog / Honeycomb / Tempo — zero extra code
from mantis_agent import OTelTracer
agent = Agent(model="qwen2.5:7b", tracer=OTelTracer(service_name="my-agent"))
does it actually work?

On a fresh machine, no GPU. Works on the first try.

pip install mantis-agent-sdk
mantis-agent setup-local     # pulls a CPU-friendly model, smoke-tests
python my_agent.py           # two tools, a 5-turn task — first try

Change one word — model= — and the same script runs against Together, Fireworks, vLLM, llama.cpp, or Groq.

why “mantis”

A new model drops every week. Your code doesn't move a line.

qwen3:32b
llama4:scout
deepseek-r1:70b
gpt-oss:120b
gemini-2.0-flash
Kimi-K2.6
waiting…

The ecosystem keeps shipping; the loop keeps hunting. Same agent, same tools, same sessions — whatever lands next. pip install mantis-agent-sdk