Config-as-code, async-first, pluggable SDK for building protocol-rich single-agent systems.
English | 中文
OpenAgents gives you a small, explicit runtime kernel for single-agent execution. It is designed for developers who want real control over agent behavior — not a black-box framework that hides everything inside one monolithic execute() call.
Designed for:
- Teams that want a clear, auditable agent runtime instead of a magic framework
- Developers building coding agents, research agents, and workflow agents
- Products that need custom middle protocols, safety rules, and context logic
- Applications that want a stable kernel now and product infrastructure on top
Deliberately not:
- A multi-agent control plane (one
run= oneagent_id) - A job scheduler or queue system
- A durable product control plane
- A UI framework
Team orchestration, mailboxes, schedulers, approvals, and product UX belong above this layer.
Most agent frameworks collapse three very different concerns into one abstraction:
- Kernel protocol — what a run is (inputs, outputs, state)
- Runtime seams — how a run behaves (memory, tools, context assembly)
- Product middle protocols — what only your application understands (task envelopes, review contracts, permission models)
OpenAgents keeps them separate:
┌─────────────────────────────────────────────────┐
│ App / Product Protocols │
│ task envelopes · coding plans · approvals │
│ review contracts · artifact taxonomies │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ SDK Runtime Seams (8) │
│ memory · pattern · tool · tool_executor │
│ context_assembler · runtime · session │
│ events · skills │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ Kernel Protocols │
│ RunRequest · RunResult · RunContext │
│ ToolExecutionRequest · SessionArtifact │
└─────────────────────────────────────────────────┘
This separation gives you a small kernel with explicit behavior, stable extension seams instead of ad-hoc monkeypatching, and room to invent app-specific protocols without forking the SDK.
Core (zero optional deps):
pip install io-openagent-sdk
# or
uv add io-openagent-sdkOptional extras:
| Extra | Installs | Use when |
|---|---|---|
cli |
rich, questionary, watchdog, pyyaml |
Interactive CLI, hot reload, colour output |
openai |
openai, httpx |
OpenAI-compatible LLM providers |
litellm |
litellm |
Non-OpenAI backends via LiteLLM (Bedrock, Vertex, Gemini, Azure, …) |
mem0 |
mem0ai |
Persistent cross-session memory |
mcp |
mcp |
MCP tool bridge |
otel |
opentelemetry-api |
OpenTelemetry event bridge |
sqlite |
aiosqlite |
SQLite-backed session persistence |
tokenizers |
tiktoken |
Accurate token counting for OpenAI |
yaml |
pyyaml |
YAML config files |
all |
Everything above | Development / full-featured deployments |
uv add "io-openagent-sdk[cli]"
uv add "io-openagent-sdk[openai,mcp]"
uv add "io-openagent-sdk[all]"Requires Python ≥ 3.11.
{
"version": "1.0",
"agents": [
{
"id": "assistant",
"name": "demo-agent",
"memory": {"type": "window_buffer", "on_error": "continue"},
"pattern": {"type": "react"},
"llm": {"provider": "anthropic", "model": "claude-sonnet-4-6"},
"tools": [
{"id": "search", "type": "builtin_search"},
{"id": "files", "type": "read_file"}
]
}
]
}# Single-shot turn
openagents run agent.json --input "hello"
# Interactive multi-turn REPL
openagents chat agent.json
# Hot-reload on config change (dev mode)
openagents dev agent.jsonimport asyncio
from openagents import Runtime
async def main() -> None:
runtime = Runtime.from_config("agent.json")
result = await runtime.run(
agent_id="assistant",
session_id="demo",
input_text="What files are in the current directory?",
)
print(result.output)
asyncio.run(main())from openagents import run_agent, run_agent_detailed, run_agent_with_dict
# Simple sync wrapper
result = run_agent("agent.json", agent_id="assistant", session_id="s1", input_text="hello")
# Detailed result (usage, artifacts, stop reason)
result = run_agent_detailed("agent.json", agent_id="assistant", session_id="s1", input_text="hello")
print(result.usage.cost_usd, result.stop_reason)
# Inline config (no file needed)
result = run_agent_with_dict(
{
"version": "1.0",
"agents": [
{
"id": "assistant",
"name": "demo",
"memory": {"type": "buffer"},
"pattern": {"type": "react"},
"llm": {"provider": "mock"},
"tools": []
}
]
},
agent_id="assistant",
session_id="demo",
input_text="hello",
)from openagents import Runtime, RunRequest
async def stream_example() -> None:
runtime = Runtime.from_config("agent.json")
request = RunRequest(agent_id="assistant", session_id="s1", input_text="hello")
async for chunk in runtime.run_stream(request):
print(chunk.kind, chunk.data)Caller
→ Runtime facade (Runtime.run / run_stream)
→ Runtime plugin (DefaultRuntime)
→ Session manager + Event bus
→ Context assembler (what enters this run?)
→ Pattern.setup() → Memory.inject()
→ Pattern.execute() ↔ Tool calls (policy + executor)
→ Memory.writeback() → Context assembler.finalize()
→ RunResult
| Object | Role |
|---|---|
RunRequest |
Inputs to a single run (agent_id, session_id, input_text, context_hints, budget) |
RunResult[OutputT] |
Output of a run (output, usage, artifacts, stop_reason, error) |
RunContext[DepsT] |
Per-run state carrier available to tools and patterns |
RunUsage |
Token counts + cost_usd + cache stats |
RunBudget |
Limits: max_cost_usd, max_tokens, max_turns, max_validation_retries |
RunArtifact |
Named artifact emitted during a run (carries metadata) |
StopReason |
Typed termination state (end_turn, budget_exhausted, error, …) |
Every plugin is loaded by either:
{"type": "react"} // builtin or decorator-registered name
{"impl": "myapp.patterns.custom.MyPattern"} // Python dotted pathIf both are set, impl wins. Top-level runtime, session, and events each take exactly one selector; agent-level plugins require at least one.
| Name | Description |
|---|---|
buffer |
Full in-memory conversation history |
window_buffer |
Sliding window over recent turns |
markdown_memory |
File-backed long-term memory (MEMORY.md index) |
mem0 |
Persistent semantic memory via mem0ai ([mem0] extra) |
chain |
Compose multiple memory plugins in sequence |
| Name | Description |
|---|---|
react |
ReAct: think → act → observe loop |
plan_execute |
Plan first, then execute steps |
reflexion |
Self-reflection and iterative refinement |
| Name | Description |
|---|---|
truncating |
Simple head truncation to fit token budget |
head_tail |
Keep head + tail, drop middle |
sliding_window |
Rolling window over recent messages |
importance_weighted |
Score-based retention |
| Category | Tools |
|---|---|
| Search | builtin_search, tavily_search |
| Files | read_file, write_file, list_files, delete_file |
| Text | grep_files, ripgrep, json_parse, text_transform |
| HTTP | http_request, url_parse, url_build, query_param, host_lookup |
| System | shell_exec, execute_command, get_env, set_env |
| Time | current_time, date_parse, date_diff |
| Random | random_int, random_choice, random_string, uuid |
| Math | calc, percentage, min_max |
| Memory | remember_preference |
| MCP | mcp (bridge to any MCP server, [mcp] extra) |
| Seam | Builtin | Description |
|---|---|---|
runtime |
default |
DefaultRuntime orchestrator |
session |
in_memory |
In-process session storage |
events |
async |
Async event bus |
Install the cli extra for the full CLI experience:
uv add "io-openagent-sdk[cli]"| Command | Description |
|---|---|
openagents run <path> |
Execute a single-shot turn |
openagents chat <path> |
Interactive multi-turn REPL |
openagents dev <path> |
Hot-reload runtime on config change |
openagents validate <path> |
Validate an agent.json without running |
openagents schema |
Dump the full AppConfig JSON Schema |
openagents list-plugins |
List all registered plugins by seam |
openagents config show <path> |
Print the fully-resolved AppConfig |
openagents init <name> |
Scaffold a new project from a template |
openagents new plugin <seam> <name> |
Scaffold a plugin skeleton + test stub |
openagents replay <path> |
Re-render a persisted transcript |
openagents doctor |
Environment health check |
openagents version |
Print SDK / Python / extras / plugin counts |
openagents completion <shell> |
Emit a shell-completion script |
Exit codes: 0 success · 1 usage error · 2 validation error · 3 runtime error
Any seam can be extended by implementing the plugin interface and pointing to it via impl:
# myapp/patterns/my_pattern.py
from openagents.interfaces import PatternPlugin, RunContext
class MyPattern(PatternPlugin):
async def execute(self, context: RunContext) -> str:
# your reasoning loop here
return "done"{
"pattern": {"impl": "myapp.patterns.my_pattern.MyPattern"}
}Or use the decorator registry for named plugins:
from openagents.decorators import pattern
@pattern("my_react")
class MyReact(PatternPlugin):
...{"pattern": {"type": "my_react"}}See Plugin Development for the full guide.
The SDK provides carriers for product-specific state — no need to fork the kernel:
| Carrier | Use for |
|---|---|
RunRequest.context_hints |
Pass structured hints into context assembly |
RunRequest.metadata |
Caller metadata (task IDs, trace IDs, …) |
RunContext.state |
Mutable per-run app state shared across tools/pattern |
RunContext.scratch |
Ephemeral scratchpad within a run |
RunContext.assembly_metadata |
Signals from context assembler to pattern |
RunArtifact.metadata |
Structured metadata on emitted artifacts |
| Example | Description |
|---|---|
examples/quickstart/ |
Minimal builtin-only setup — first contact with the kernel |
examples/production_coding_agent/ |
Production coding agent: task packets, persistent memory, follow-up recovery, delivery artifacts |
examples/pptx_generator/ |
Interactive 7-stage PPT generator CLI (pptx-agent) with MCP + multi-pattern pipeline |
Full example guide: docs/examples.md
Developer docs live in the docs directory.
| Document | Description |
|---|---|
| Developer Guide | Architecture boundaries, runtime lifecycle, state carriers |
| Repository Layout | Directory structure, doc topology, test conventions |
| Seams & Extension Points | Decision tree: which seam for which problem |
| Configuration Reference | JSON schema, selector rules, builtin names |
| Plugin Development | Loader mechanics, plugin contracts, testing patterns |
| API Reference | Package exports, runtime methods, protocol objects |
| CLI Reference | Full CLI surface and exit codes |
| Examples Guide | What each example demonstrates |
| Migration 0.2 → 0.3 | Upgrade guide |
Recommended reading order for new users:
This project uses uv for dependency management.
# Clone and install all dev deps
git clone https://github.com/your-org/openagent-python-sdk
cd openagent-python-sdk
uv sync
# Run the full test suite
uv run pytest -q
# Run a single test
uv run pytest -q tests/unit/test_runtime_core.py::MyTest::test_case
# Coverage (floor: 92%)
uv run coverage run -m pytest && uv run coverage report
# Lint
uv run ruff check .
uv run ruff format --check .Rule: When adding, removing, or changing code under the openagents package, you must add/update/remove the corresponding tests in the same change. The test suite and source are co-evolved.
shell_exec— allowlist-aware subprocess tool with cwd/env/timeout controlstavily_search— REST-based Tavily search tool (readsTAVILY_API_KEY)markdown_memory— file-backed long-term memory (MEMORY.md index + per-section files)remember_preference— companion tool for agent-side preference captureopenagents.utils.env_doctor— reusable environment health check frameworkopenagents.cli.wizard— Rich + questionary wizard component for interactive CLIsexamples/pptx_generator/— production-grade 7-stage PPT generator (pptx-agent)
Full changelog: CHANGELOG.md | Migration guide: 0.2 → 0.3
Apache License 2.0 — see LICENSE.