A modular AI agent CLI inspired by the full reference harness.
Project description
Somnia (OpenAgent)
Somnia 是一个模块化的 AI Agent CLI 工具。名字来源于拉丁语"梦"(somnia),寓意用 AI 编织梦想。
内部模块仍使用
openagent作为 Python 包名,somnia是发布到 PyPI / npm 的产品名。
Prerequisites
| 方式 | 需要的环境 |
|---|---|
pip install |
Python 3.11+(自带 pip) |
npx somnia |
Node.js 16+ + Python 3.11+ |
| 一键脚本 | curl / PowerShell(脚本会检测并引导安装 Python) |
| Docker | Docker(什么都不用装) |
💡 如果你还没有 Python,去 python.org 下载安装, 或用包管理器:
brew install python@3.12/winget install Python.Python.3.12
Installation
方式一:pip install(推荐)
pip install somnia
安装后直接使用:
somnia # 交互式 REPL
somnia chat "hi" # 单次对话
somnia doctor # 检查环境
方式二:一键安装脚本(自动检测 Python)
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/your-org/openagent/main/scripts/install.sh | bash
Windows PowerShell:
irm https://raw.githubusercontent.com/your-org/openagent/main/scripts/install.ps1 | iex
脚本会自动检测 Python 3.11+,没有的话会提示你如何安装。
方式三:npx(需要 Node.js + Python)
npx somnia # 直接运行,首次会自动 pip install
npm install -g somnia # 或全局安装
方式四:Docker(零依赖,什么都不用装)
docker build -t somnia .
docker run -it somnia # 交互式
docker run -it somnia chat "hello" # 单次对话
从源码安装(开发者)
git clone https://github.com/your-org/openagent.git
cd openagent
pip install -e .
Included in this MVP
- Interactive CLI with chat, run, tasks, compact, and doctor flows
- Single-agent loop with tool dispatch
- Filesystem and shell tools with workspace boundaries
- Session-scoped
TodoWrite - Persistent task graph
- Isolated subagent execution
- Skill loading from
skills/**/SKILL.md - Context micro-compact and transcript-backed auto-compact
- Background shell jobs with notifications
- Message bus, inbox, teammate runtime, shutdown requests, and plan approvals
- Anthropic provider and OpenAI-compatible provider adapters
- MCP client integration over
stdioand HTTP - Persistent sessions, transcripts, inbox, team state, and jobs under
.openagent/
Coordination Flow
subagent is a disposable isolated worker, task_* is the persistent task system, and team tools manage long-lived teammates. They can be used independently, but the common collaboration flow looks like this:
sequenceDiagram
autonumber
actor User
participant Lead as Lead Agent
participant Todo as Session TodoWrite
participant Sub as subagent tool
participant Child as Isolated Subagent
participant Tasks as TaskStore(task_*)
participant Team as TeammateRuntimeManager
participant Bus as MessageBus
participant Mate as Teammate
User->>Lead: Ask for a larger coding task
Lead->>Todo: TodoWrite(short checklist for this session)
Todo-->>Lead: Session-scoped progress
alt Lead wants a one-off isolated subtask
Lead->>Sub: subagent(prompt, agent_type)
Sub->>Child: run_subagent() with fresh messages
Child-->>Sub: concise summary only
Sub-->>Lead: tool_result(summary)
end
alt Lead wants persistent tracked work
Lead->>Tasks: task_create(subject, description)
Tasks-->>Lead: task id and pending state
end
alt Lead wants long-lived parallel help
Lead->>Team: spawn_teammate(name, role, prompt)
Team->>Mate: start worker loop
Mate->>Bus: read_inbox()
opt Teammate receives direct instruction
Lead->>Bus: send_message(to=teammate)
Bus-->>Mate: inbox message
end
opt Teammate picks up persistent work
Mate->>Tasks: list_claimable()/claim_task()
Tasks-->>Mate: claimed task
end
Mate-->>Bus: send_message(to=lead, progress/plan/result)
Bus-->>Lead: inbox message
end
Note over Lead,Todo: TodoWrite is only for the current session.
Note over Tasks,Team: task_* persists across turns and can be claimed by teammates.
Note over Sub,Child: subagent does not own persistent tasks and does not become a teammate.
Subagent vs Teammate
Both subagent and teammates run with their own message history instead of sharing the lead session directly, but they are not equivalent workers.
| Aspect | subagent |
Teammate (spawn_teammate) |
|---|---|---|
| Lifetime | Disposable, one call only | Long-lived worker loop |
| Message context | Fresh isolated messages per invocation |
Persistent worker-local messages across work and idle cycles |
| Entry point | subagent(prompt, agent_type) |
spawn_teammate(name, role, prompt) |
| Returns to lead | One summary string as tool result | Ongoing inbox messages, plan requests, and progress updates |
| Base role | One-off isolated helper | Persistent collaborator |
| Shell tool | Yes | Yes |
| File read | Yes | Yes |
| File write/edit | Only when agent_type != "Explore" |
Yes |
TodoWrite |
No | No |
Persistent task_* tools |
No | Yes |
| Inbox / messaging tools | No | Yes |
| Can auto-claim persistent tasks | No | Yes |
| Can spawn more teammates | No | No |
| Can recursively spawn subagents | No | No |
Current tool boundaries in this repo:
subagentgetsbash,read_file,load_skill, and optionallywrite_file/edit_filefor non-Exploreruns.- Teammates get
bash, filesystem tools,task_create,task_get,task_update,task_list,claim_task, plus worker-local collaboration tools such assend_message,idle, andsubmit_plan. - The lead agent has the broader coordination surface:
subagent,task_*, team tools,TodoWrite, approvals, and other top-level runtime tools.
Practical rule:
- Use
subagentwhen you want a clean one-off investigation or implementation pass and only need a summary back. - Use a teammate when you want a persistent collaborator that can own tracked work, send updates, and resume later.
Agent Team
Agent Team is the long-lived collaboration layer in OpenAgent. Unlike subagent, which is a disposable isolated helper, a teammate is a named worker managed by TeammateRuntimeManager and coordinated through the message bus and persistent task system.
What a Teammate Is
- A teammate is created with
spawn_teammate(name, role, prompt). - Each teammate runs in its own worker thread with its own message history.
- Teammates do not share the lead session transcript directly.
- Teammates are intended for ongoing collaboration, not one-off isolated delegation.
Lifecycle
The usual status flow is:
startingworkingidle- back to
workingwhen resumed by inbox messages or claimable tasks shutdownwhen the worker exits
Teammates stop running in these cases:
- The lead sends a
shutdown_request. - The teammate stays idle longer than
teammate_idle_timeout_secondswithout new inbox work or claimable tasks. - The worker loop crashes with a runtime error.
- The OpenAgent process restarts. On the next boot, previously active teammates are repaired to
shutdownwith reasonruntime_restarted.
What Persists
Teammates are workspace-scoped rather than session-scoped.
- Team member metadata is persisted under
.openagent/team/team.json. - Inbox messages are persisted under
.openagent/inbox/*.jsonl. - Persistent tasks used by teammates live under
.openagent/tasks/. - Shutdown and plan-approval workflow state lives under
.openagent/requests/.
Persisted teammate metadata includes:
namerolestatusactivitylast_transition_atlast_activity_atshutdown_reasoncurrent_task_idlast_error
What does not persist:
- The worker thread itself
- The full teammate
messageshistory - In-memory reasoning state inside the worker loop
This means a teammate identity and status survive as project data, but an active worker must be spawned again after shutdown or process restart.
Tool Surface
Teammates have a narrower tool surface than the lead and a different one than subagent.
- Teammates can use shell and filesystem tools.
- Teammates can use persistent
task_*tools andclaim_task. - Teammates can use worker-local collaboration tools such as
send_message,idle, andsubmit_plan. - Teammates cannot call
TodoWrite. - Teammates cannot spawn more teammates.
- Teammates cannot spawn
subagent.
When to Use Agent Team
Use teammates when you need:
- A named worker that can keep collaborating over time
- Progress updates through inbox messages
- Ownership of persistent tracked work
- Automatic pickup of claimable tasks while idle
Do not use teammates when you only need:
- A single isolated research pass
- A one-off implementation summary
- A clean temporary context with no persistent ownership
That is the case where subagent is the better fit.
Layout
OpenAgent/
pyproject.toml
README.md
openagent.toml.example
openagent/
cli/
collaboration/
config/
mcp/
providers/
runtime/
skills/
storage/
tools/
Quick Start
- Install the package in editable mode:
python -m pip install -e ./OpenAgent
- Copy the config file:
mkdir -p .openagent
cp OpenAgent/openagent.toml.example .openagent/openagent.toml
- Run a doctor check:
python -m openagent doctor
- Start interactive chat:
python -m openagent
You can also resume a previous session through the picker:
python -m openagent -r
You can override the provider or model for a single run without editing config files:
python -m openagent --provider anthropic --model glm-5
python -m openagent --provider openai --model gpt-4.1
python -m openagent run --provider openai --model gpt-4.1 "Summarize this repo"
If you install the console entrypoint, the same commands work as:
openagent
openagent -r
Configuration
OpenAgent reads configuration from:
- Global config at
~/.openagent/openagent.toml - Workspace config at
.openagent/openagent.toml
For ad-hoc switching, command-line --provider and --model overrides take precedence for the current invocation only.
Both config files are optional. OpenAgent deep-merges them at runtime, and workspace settings override global settings when the same key is defined.
openagent.toml
Supported top-level sections:
[agent][providers][providers.<name>][runtime][[mcp_servers]]or[mcp_servers.<name>]
Example:
[agent]
name = "OpenAgent"
# Optional: fully override the built-in base system prompt.
# system_prompt = """
# You are a careful coding agent.
# """
[providers]
default = "anthropic"
[providers.anthropic]
models = ["claude-sonnet-4-5", "claude-3-5-haiku-latest"]
default_model = "claude-sonnet-4-5"
api_key = "replace-me"
# base_url = "https://api.anthropic.com"
# max_tokens = 8000
# timeout_seconds = 120
[providers.openai]
models = ["gpt-4.1", "gpt-4.1-mini"]
default_model = "gpt-4.1"
api_key = "replace-me"
# base_url = "https://api.openai.com/v1"
# organization = "org_xxx"
# max_tokens = 8000
# timeout_seconds = 120
[model_traits."claude-sonnet-4-5"]
cwt = 200000
[model_traits."claude-3-5-haiku-latest"]
cwt = 200000
[model_traits."gpt-4.1"]
cwt = 1047576
[model_traits."gpt-4.1-mini"]
cwt = 1047576
# Provider-specific override when needed.
#[model_traits.openrouter."gpt-4.1"]
#cwt = 262144
[runtime]
token_threshold = 100000
command_timeout_seconds = 120
background_poll_interval_seconds = 2
teammate_idle_timeout_seconds = 60
teammate_poll_interval_seconds = 5
max_tool_output_chars = 50000
max_subagent_rounds = 30
max_agent_rounds = 50
[[mcp_servers]]
name = "filesystem"
transport = "stdio"
command = "python"
args = ["server.py"]
cwd = "D:/tools/mcp-filesystem"
enabled = false
timeout_seconds = 30
protocol_version = "2025-11-25"
[mcp_servers.unityMCP]
transport = "http"
url = "http://127.0.0.1:8081/mcp"
http_headers = { "X-API-Key" = "replace-me", "Accept" = "text/event-stream" }
startup_timeout_sec = 20
enabled = false
OpenAgent now uses provider-aware token counting for context tracking:
- Anthropic profiles prefer the native
messages.count_tokensAPI. - OpenAI-compatible profiles prefer
tiktoken. - The REPL status area shows current context usage as
used / totalplus percentage. - Configure model-wide defaults under
model_traits."<model-id>". - If the same model id needs a provider-specific override, use
model_traits.<provider>."<model-id>". - Today the only model trait is
cwt, which meanscontext_window_tokens.
Selecting a Model
There are now three ways to choose the active model:
- Configure multiple models under
[providers.<name>]inopenagent.toml. - Use
/modelinside the REPL to interactively switch provider and model. - Pass
--providerand--modelon the command line for a one-off override.
Examples:
openagent --provider anthropic --model glm-5
openagent chat --provider anthropic --model claude-sonnet-4-5
openagent run --provider openai --model gpt-4.1 "Explain the failing tests"
openagent doctor --provider openai --model gpt-4.1
Inside the REPL, run:
/model
OpenAgent will first show a provider picker, then a model picker limited to the models configured under that provider.
Agent Prompt Configuration
If you set only agent.name, OpenAgent uses the built-in default base prompt and injects the configured name into it.
[agent]
name = "MyAgent"
If you set agent.system_prompt, that string replaces the built-in base prompt.
[agent]
name = "CodeReviewer"
system_prompt = """
You are a code review specialist.
Prioritize correctness, regressions, and missing tests.
"""
At runtime, OpenAgent also appends role-specific guidance to the base prompt, including:
- current workspace path
- available skills
- tool usage guidance
- current execution environment
The execution environment block tells the model which OS it is running on and how to use the bash tool correctly:
- on Unix-like systems,
bashuses the system shell - on Windows,
bashruns PowerShell-compatible commands
That means Windows sessions should prefer commands such as:
Get-ChildItemGet-ContentSelect-StringSelect-Object
MCP Server Configuration
OpenAgent supports both styles below.
Array style:
[[mcp_servers]]
name = "filesystem"
transport = "stdio"
command = "python"
args = ["server.py"]
cwd = "D:/tools/mcp-filesystem"
enabled = true
Named table style:
[mcp_servers.unityMCP]
transport = "http"
url = "http://127.0.0.1:8081/mcp"
http_headers = { "X-API-Key" = "replace-me", "Accept" = "text/event-stream" }
startup_timeout_sec = 20
enabled = true
Supported MCP fields include:
transporturlcommandargscwdenvhttp_headersenabledtimeout_secondsorrequest_timeout_secstartup_timeout_secprotocol_version
REPL Commands
/compact/model/tasks/team/inbox/mcp/toollog/bg/help/exit
Notes
- Data is stored under
.openagent/in the workspace root. - MCP tools are exposed with the local name format
mcp__<server>__<tool>. - MCP config supports both
[[mcp_servers]]array style and[mcp_servers.<name>]table style. - The OpenAI adapter uses the chat completions API shape so provider differences stay isolated in
providers/.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file somnia-0.1.0.tar.gz.
File metadata
- Download URL: somnia-0.1.0.tar.gz
- Upload date:
- Size: 109.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23d3d2223cc76397262f3051313caf01dd2494a085450e3f5e374bbcbf3d91b5
|
|
| MD5 |
8a79e21882cc61c4bec3a3908450673b
|
|
| BLAKE2b-256 |
bad9693a3b228567be246266cfed811fa2fc374e53da3a333743ff65e97dbd78
|
File details
Details for the file somnia-0.1.0-py3-none-any.whl.
File metadata
- Download URL: somnia-0.1.0-py3-none-any.whl
- Upload date:
- Size: 98.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e021417e95749daa77579771f07b5ec1f6d41315a4ad02b3920fcb5d81b68b88
|
|
| MD5 |
83a1f01ba9d437cf3cecf47f0f4aeae7
|
|
| BLAKE2b-256 |
6de99f82c1ae55148b3e84d29be0cc2f5f9f3c90029e9db727b02dfad035599b
|