Simple Agent aims to be a simple, transparent, general-purpose agent TUI.
- Real-time observers: attach independent observer agents (e.g. naming, code quality) that monitor changes and provide immediate feedback
- Transparency: observe every tool call and agent decision with ease
- Tab-based multi-agent TUI: view and manage multiple agents side by side
- Session continuation: pause and resume sessions with
--continue - Markdown-driven subagents: build modular agents from simple markdown files
- CLI-first design: built for command-line use, with optional non-interactive mode
- API integration: works with OpenAI, Anthropic, and Google Gemini APIs
uv tool install .
agent "your message here"
agent --agent <agent-type> # defines the starting agent
agent --continue # continue previous session
agent --system-prompt # print rendered system prompt
agent --non-interactive # suppress interactive prompts
agent --help # show all optionsDuring a session, type these in the input prompt:
/clear— clear conversation history/model <name>— switch to a different model/agent <name>— switch to a different agent@<filename>— attach a file to your message
The Textual UI can be served in a browser using textual-serve (via serve_web.py).
# Build and run
docker compose up -d --build
# Example .env entries
SIMPLE_AGENT_PUBLIC_URL=http://<host>:8000
ANTHROPIC_API_KEY=...
OPENAI_API_KEY=...
GEMINI_API_KEY=...Then open http://<host>:8000 in your browser.
Create a .simple-agent.toml file either in your home directory or in the directory where you run the agent. Values from the current directory override those from ~.
[model]
default = "claude" # Which model configuration to use by default
[models.claude]
model = "claude-sonnet-4-5-20250929"
adapter = "claude"
api_key = "${ANTHROPIC_API_KEY}" # Or use a literal API keyThe [model] section specifies which model to use by default. Define one or more models under [models.*] sections. API keys can reference environment variables using ${VAR_NAME} syntax.
On startup the agent loads .env files — first ~/.env, then .env in the current
directory, which takes precedence. Real environment variables always win over values
from a .env file, and the loaded values are available to ${VAR_NAME} placeholders
in .simple-agent.toml as well as to commands the agent runs.
# .env
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...You can define multiple model configurations and switch between them:
[model]
default = "claude"
[models.claude]
model = "claude-sonnet-4-5-20250929"
adapter = "claude"
api_key = "${ANTHROPIC_API_KEY}"
[models.openai]
model = "gpt-4o"
adapter = "openai"
api_key = "${OPENAI_API_KEY}"
# base_url = "https://openrouter.ai/api/v1" # Optional: for OpenRouter, etc.
[models.gemini]
model = "gemini-3.7-flash"
adapter = "gemini"
api_key = "${GOOGLE_API_KEY}"OpenAI adapter: You can point the client at a compatible provider by overriding base_url, e.g. set it to https://openrouter.ai/api/v1 for OpenRouter.
Gemini adapter: Talks to the Gemini Interactions API (POST /v1beta/interactions). Configure with a Google AI API key and a current model name (e.g., gemini-3.7-flash, gemini-3.1-pro-preview, gemini-3.5-flash-lite).
Agent definition files (*.agent.md) are discovered from the built-in simple_agent package and from .simple-agent/agents in your project directory.
To point the agent at a different directory, add this to .simple-agent.toml:
[agents]
path = "${APP_DIR}/custom_agents"
Example custom agent definition (save as marketing.agent.md in your configured agents directory):
---
name: Marketing
tools:
- bash
- cat
- edit_file
model: gemini
---
You are a marketing-focused assistant who writes short, punchy summaries.
{{DYNAMIC_TOOLS_PLACEHOLDER}}
{{AGENTS.MD}}To change which agent starts first, set it via the [agents] section:
[agents]
start = "orchestrator"Observers are specialized agents (*.observer.md) that watch an agent's diffs and intent in real-time, providing targeted suggestions (e.g. naming conventions, consistency, architectural rules) without directly modifying code.
You can attach observers to any agent in its frontmatter:
---
name: Coding
tools: bash, cat, ls, create_file, replace_file_content
observers: [naming]
---Observer definition files are discovered from the same directories as agent definitions (built-in package and configured custom agent directory).
# Run tests
./test.sh # Run all tests (stops on first failure)
./test.sh test_foo.py # Run a specific test file
./test.sh test_foo # Run tests matching a pattern
./test.sh -v # Verbose mode with full tracebacks
./test.sh -h # Show help
# Approve received files
./approve.sh
# Generate coverage locally and refresh the badges
./coverage.sh # generate code coverage report
./coverage.sh foo.py # show coverage of a specific file
./coverage.sh --badge # update the coverage badgeThe bridge allows agents to interact with simple-agent end to end via the file system. It captures the TUI state into a Markdown file and reads your input from a text file. This is useful for building custom integrations or observing the agent without a terminal.
See the Bridge Documentation for details.
The say.py script requires a Piper TTS voice model to function. Download the required model:
# Download the voice model (61MB)
curl -L -o en_US-lessac-medium.onnx "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/lessac/medium/en_US-lessac-medium.onnx"
curl -L -o en_US-lessac-medium.onnx.json "https://huggingface.co/rhasspy/piper-voices/resolve/v1.0.0/en/en_US/lessac/medium/en_US-lessac-medium.onnx.json"Or use the provided script:
./download_voice_model.shThen use:
./say.py "Hello world"
# or
./say.sh "Hello world"