Install
$ agentstack add mcp-sagebynature-sage-agent ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Sage Agent
Yes, I shamelessly named it after me ;)
Inspired by the recent sprawl of OpenClaw, PicoBot, ZeroClaw, and whatever else popped up last Tuesday — I decided to write my own. Written from the ground up in Python.
Sage doesn't aspire to be the next Claude Code. Instead, it's intentionally designed to be a clean slate out of the box, so that you can make it more intelligent. No opinions. No bloat. Just a solid foundation you can build on top of.
Built-in evaluation and CI/headless execution are included. See [.docs/eval.md](.docs/eval.md) and [.docs/ci-headless.md](.docs/ci-headless.md).
Key Features
Agents
The core unit. Define an agent in a Markdown file with YAML frontmatter — name, model, system prompt — and you're running. No boilerplate classes, no framework ceremony. Just config and go.
---
name: assistant
model: gpt-4o
---
You are a helpful AI assistant.
Subagents & Delegation
Agents can have subagents. When they do, they automatically get a delegate tool — the LLM decides when and how to hand off work. It's orchestration without the orchestration code.
The delegate tool accepts two optional parameters beyond the target agent and task:
session_id— resume a previous conversation with the subagent. Conversation history is persisted across calls and restored automatically. The result is prefixed with[Session: ]when a session ID is supplied.category— route the delegation to a model defined in thecategoriesblock ofconfig.toml(e.g."quick"→gpt-4o-mini,"deep"→ Claude Sonnet). The subagent's model is swapped at runtime without changing its config file.
Tools via @tool Decorator
Write a Python function. Decorate it with @tool. Sage auto-generates the JSON schema from your type hints. That's it. No manual schema wrangling.
@tool
def word_count(text: str) -> str:
"""Count the number of words in the given text."""
return str(len(text.split()))
Built-in tools included — or load them all at once with sage.tools.builtins:
| Category | Tools | |----------|-------| | Core | shell, file_read, file_write, file_edit, http_request | | Memory | memory_store, memory_recall | | Web | web_fetch, web_search | | Git | git_status, git_diff, git_log, git_commit, git_undo, git_branch |
Per-agent tool restrictions are supported via frontmatter. blocked_tools hides specific tools from the LLM; allowed_tools is an explicit allowlist (all others are hidden). Blocklist takes precedence over allowlist.
---
blocked_tools: [shell, http_request]
allowed_tools: [file_read, file_write, memory_store]
---
Skills
Reusable capabilities defined as Markdown files. Drop them in a skills/ directory and all agents share them automatically. Sage resolves the global skill pool via a waterfall (skills_dir in config.toml → ./skills/ → ~/.agents/skills/ → ~/.claude/skills/). Each agent can optionally limit its skills to a named subset via an allowlist in config.toml. Flat files or directory-per-skill — both work.
Orchestration
Four flavors:
- Pipeline (
>>) — chain agents sequentially. Output of one feeds the next. - Parallel — run multiple agents concurrently via
Orchestrator.run_parallel(). - Race — first agent to complete wins via
Orchestrator.run_race(). - Autonomous delegation — an orchestrator agent with subagents decides who does what, on its own.
100+ LLM Providers
Powered by litellm. OpenAI, Azure, Anthropic, Ollama, and basically everything else. One model string, any provider.
| Provider | Model String | |----------|-------------| | OpenAI | gpt-4o, gpt-4o-mini | | Azure | azure/gpt-4o | | Anthropic | anthropic/claude-sonnet-4-20250514 | | Ollama | ollama/llama3 |
MCP Support
Connect to MCP servers (stdio or SSE) or expose your tools as an MCP server. Both directions work.
Semantic Memory
SQLite-backed with litellm embeddings. Zero-config persistent recall across sessions. Compaction built in so context doesn't bloat forever.
Permissions
Control what tools can do via a single permission: block in YAML frontmatter. Each permission category (read, edit, shell, web, memory) maps to a set of built-in tools. Set a category to allow, deny, or ask, or use pattern matching for fine-grained shell control. When set to deny, tools are invisible to the LLM. Interactive prompts in the TUI when policy is ask.
Hook System
A lifecycle event bus for intercepting and extending agent behavior without modifying core code. Register async handlers against named HookEvent values — 31 events across seven categories: run lifecycle (ON_RUN_STARTED, ON_RUN_COMPLETED, ON_RUN_FAILED, ON_RUN_CANCELLED), LLM calls (PRE_LLM_CALL, POST_LLM_CALL, ON_LLM_STREAM_DELTA, ON_LLM_ERROR, ON_LLM_RETRY), tools (PRE_TOOL_EXECUTE, POST_TOOL_EXECUTE, ON_TOOL_FAILED), delegation (ON_DELEGATION, ON_DELEGATION_COMPLETE, ON_DELEGATION_FAILED), memory, compaction, permissions, sessions, coordination, and planning. Built-in hooks cover credential scrubbing, query-based model routing, bail-out retry (follow-through), automatic memory injection, notepad injection, and plan analysis. Hooks that raise never crash the agent — errors are logged and swallowed.
from sage.hooks.registry import HookRegistry
from sage.hooks.base import HookEvent
hr = HookRegistry()
async def log_calls(event, data):
print(f"{event}: {data.get('model')}")
hr.register(HookEvent.PRE_LLM_CALL, log_calls)
agent = Agent(name="a", model="gpt-4o", hook_registry=hr)
Every hook emission is also recorded as a canonical EventEnvelope by the telemetry layer (sage/telemetry.py). Each event carries correlation IDs (run_id, session_id, originating_session_id), timing, token usage, and a sanitized payload. The TUI's event timeline and inspector consume these envelopes via JSON-RPC for real-time visibility into agent behavior. See [ADR-012](.docs/adrs/012-event-telemetry-and-observability.md).
Coordination
Agent-to-agent messaging and lifecycle primitives for multi-agent systems:
- MessageBus — in-memory per-agent inboxes with TTL expiry, idempotency, overflow protection, and broadcast delivery
- CancellationScope — propagate cancel signals across async tasks; child scopes inherit parent cancellation
- SessionManager — create, track, and destroy concurrent agent sessions with typed metadata
- BackgroundTaskManager — launch subagent runs as non-blocking asyncio tasks. The orchestrator gets a
delegate_backgroundtool and receives completion notifications injected into the next turn's message stream. Supports polling (background_status) and cancellation (background_cancel).
# Orchestrator gets these tools automatically when subagents are present:
# delegate_background(agent_name, task) → task_id
# background_status(task_id) → status + result
# background_cancel(task_id) → bool
Context Management
Token-aware context window management. Automatic compaction when approaching the model's limit — tries LLM summarization first, then emergency drop, then deterministic trim as a guaranteed last resort. Configurable reserve tokens and optional pruning of large tool outputs.
TUI
A full interactive terminal UI built with Ink v6 and React 19. Communicates with the Python backend via JSON-RPC over stdio. Block-based conversation display with live streaming, collapsible tool calls, markdown rendering, permission prompts, delegation hierarchy visualization, and an event timeline with inspector for real-time observability.
Prerequisites: Node.js 22+, pnpm 10+
# Install dependencies
make tui-install
# Build
make tui-build
# Install globally on PATH
make tui-install-global
# Development mode (hot reload)
make tui-dev
See [tui/README.md](tui/README.md) for slash commands, keyboard shortcuts, and architecture details.
Planning Pipeline
A structured plan-then-execute loop for long-horizon tasks. Enable it via planning: in frontmatter.
plan_create— agents call this tool to create a named plan with an ordered list of task descriptions. State persists to disk under.sage/plans/.plan_status/plan_update/plan_complete— query and mutate plan state across turns and sessions.notepad_write/notepad_read— persistent markdown working memory scoped to a plan. Notes are stored under.sage/notepads//and injected automatically before each LLM call via the built-in notepad hook.- Plan analysis — optional
ON_PLAN_CREATEDhook that makes an LLM call to identify ambiguities, missing dependencies, ordering issues, and risks in a newly created plan. Enable viaplanning.analysis.enabled: true. - Review loop —
review_loop(plan, reviewer, reviser)iterates through review-revise cycles using thePlanReviewerprotocol. The shippedLLMPlanReviewerevaluates specificity, success criteria, and dependencies. Configurable viaplanning.review. ConductorMixin— mixin for orchestrator agents that drives plan execution: reads the plan, delegates each pending task to anexecutorsubagent, and persists results after each step.
---
name: planner
model: gpt-4o
planning:
analysis:
enabled: true
review:
enabled: true
max_iterations: 3
---
You are a planning agent. Use plan_create to structure work, then execute step by step.
Prompt System
Model-specific overlays — lightweight transformations applied to the assembled system prompt after all content (body, identity, skills) has been joined. Each overlay targets a model family and appends model-tuned instructions.
Built-in overlays:
GeminiOverlay— appends a tool-call enforcement reminder forgemini/*modelsGPTOverlay— appends a "format reasoning in clear steps" hint forgpt-*models
Register custom overlays via overlay_registry.register(my_overlay) from sage.prompts.
Dynamic delegation table — orchestrator agents can include {{DELEGATION_TABLE}} in their system prompt body. Sage replaces this placeholder at runtime with a markdown table of all available subagents, derived from each agent's prompt_metadata frontmatter field.
---
name: orchestrator
model: gpt-4o
subagents: [researcher, summarizer]
---
You are the orchestrator.
{{DELEGATION_TABLE}}
Use the delegate tool to assign work.
# researcher/AGENTS.md
---
name: researcher
model: gpt-4o
description: "Finds primary sources and synthesizes citations"
prompt_metadata:
cost: moderate
use_when: ["deep research", "fact checking", "citations needed"]
avoid_when: ["simple questions", "quick lookups"]
triggers: ["research", "find sources", "citations"]
---
Protocol-Based Architecture
ProviderProtocol, MemoryProtocol, EmbeddingProtocol — swap out any layer. Don't like the SQLite memory backend? Write your own. Don't want litellm? Implement the protocol. Everything is async-first.
Quick Start
pip install sage-agent
# or
uv tool install sage-agent
export OPENAI_API_KEY=sk-...
sage agent run AGENTS.md --input "What is the capital of France?"
Code API
import asyncio
from sage import Agent
agent = Agent(
name="assistant",
model="gpt-4o",
body="You are a helpful assistant.",
)
result = asyncio.run(agent.run("What is 2 + 2?"))
print(result)
Or load from config:
agent = Agent.from_config("AGENTS.md")
result = asyncio.run(agent.run("Hello"))
Pipelines
pipeline = researcher >> summarizer
result = asyncio.run(pipeline.run("Explain quantum computing"))
Parallel Execution
from sage import Orchestrator
results = asyncio.run(Orchestrator.run_parallel(agents, "Analyze this topic"))
Race Execution
winner = asyncio.run(Orchestrator.run_race(agents, "Solve this problem"))
Autonomous Orchestration
---
name: orchestrator
model: gpt-4o
subagents:
- research_agent
- summarize_agent
---
You are an orchestrator. Use the delegate tool to assign tasks to your subagents.
sage agent run orchestrator/AGENTS.md --input "Research and summarize quantum computing"
CLI
sage agent run AGENTS.md --input "Hello" [--stream] # Run an agent
sage agent validate AGENTS.md # Validate config
sage agent list [directory] # List agent configs
sage agent orchestrate AGENTS.md --input "text" # Run subagents in parallel
sage tool list AGENTS.md # List available tools
sage init [--name my-agent] [--model gpt-4o] # Scaffold a new project
sage tui --agent-config AGENTS.md # Launch interactive TUI
sage exec AGENTS.md -i "Hello" [-o text|jsonl|quiet] [--timeout N] [--yes] # Run headless (CI/scripting)
sage eval run suite.yaml [--min-pass-rate 0.9] [--runs N] # Run evaluation suite
sage eval validate suite.yaml # Validate suite file
sage eval history [--suite NAME] [--last N] # Show run history
sage eval compare # Compare two runs
sage eval list [directory] # Find suite files
Configuration Reference
Agent Config (Markdown Frontmatter)
---
name: my-agent
model: gpt-4o
description: "A helpful assistant" # Display only, NOT sent to model
max_turns: 10
max_depth: 3 # Max delegation depth (default: 3)
git:
auto_snapshot: true # Auto-snapshot before edits (default: true)
# Tool access: permission categories drive tool registration
# Categories: read, edit, shell, web, memory, task, git
# Values: "allow" | "deny" | "ask" | {pattern: action, ...}
permission:
read: allow
edit: allow
shell:
"*": ask
"git log*": allow
"git diff*": allow
web: allow
# Custom tool modules (in addition to permission-derived built-ins)
extensions:
- myapp.tools # Your own tools (module path)
memory:
backend: sqlite # "sqlite" (default) or "file"
path: memory.db
embedding: text-embedding-3-large
compaction_threshold: 50
auto_load: false # Auto-inject recalled memories pre-LLM-call
auto_load_top_k: 5 # How many memories to inject
subagents:
- research_agent # Directory containing AGENTS.md
- config: helper.md # Reference another .md file
- name: inline-helper # Or define inline
model: gpt-4o-mini
mcp_servers:
filesystem:
transport: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
remote:
transport: sse
url: http://localhost:8080/sse
context:
compaction_threshold: 0.75 # Compact at 75% of context window
reserve_tokens: 4096
prune_tool_outputs: true
tool_output_max_chars: 5000
model_params:
temperature: 0.7
max_tokens: 2048
# Hook-driven features (all optional)
credential_scrubbing:
enabled: true
patterns: ["sk-.*", "Bearer .*"]
allowlist: ["sk-test"]
query_classification:
rules:
- pattern: "python|code"
model: gpt-4o
priority: 1
follow_through:
enabled: true
patterns: ["I cannot", "I'm unable", "I don't have access"]
research:
enabled: true
max_sources: 3
timeout: 10.0
session:
enabled: true
# Per-agent tool restrictions
blocked_tools: [shell, http_request] # always hidden from the LLM
# allowed_tools: [file_read, memory_store] # allowlist (all others hidden)
# Planning pipeline (Phase 3)
planning:
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [sagebynature](https://github.com/sagebynature)
- **Source:** [sagebynature/sage-agent](https://github.com/sagebynature/sage-agent)
- **License:** MIT
- **Homepage:** https://pypi.org/project/sage-agent
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.