STAR Pattern Agent Framework for Python
Dana is a Python agentic runtime implementing the STAR pattern (See-Think-Act-Reflect) for building conversational AI agents. It provides multi-provider LLM support, extensible tool resources, timeline-based context management with automatic compression, and a set of CLI applications.
Structured reasoning loop for transparent, explainable agent behavior:
- See - Perceive user intent and context
- Think - Reason about response using available resources
- Act - Execute tools and retrieve information
- Reflect - Learn from outcomes and update memory
- OpenAI - gpt-4.1, gpt-4.1-mini, o3, o4-mini
- Anthropic - claude-sonnet, claude-opus, claude-haiku
- Google Gemini - gemini-2.5-flash, gemini-2.5-pro
- Azure OpenAI - Full compatibility
- Local Models - LLaMA Stack, Ollama
- Custom Endpoints - Anthropic-like protocol support
- BashResource - Execute shell commands
- FileIOResource - Read/write files
- FileEditResource - Edit files with diffs
- SearchResource - Web search integration
- TaskResource - Task management
- TodoResource - Todo list operations
- SkillResource - Claude Code skills (gated by
DANA_CLAUDE_SKILLS=1) - CodeExecutionResource - Sandboxed Python execution
- Web research pipeline - search, fetch, extract, synthesize resources
- Chronological conversation history
- Token-aware automatic compression
- LLM-based history summarization
- Serializable persistence per session
- Short-Term Memory - Per-session caching
- Long-Term Memory - Persistent markdown storage
- Memory types: lessons, episodes, facts, patterns
All six entrypoints answer --help and --version:
| Command | Purpose |
|---|---|
dana-agent |
Interactive conversational agent |
dana-agent-repl |
Interactive Python REPL with Dana imported |
dana-code |
Coding-focused agent with rich UI |
dana-memory |
Memory store inspection (--json for machine-readable output) |
dana-init |
Bootstrap config setup |
dana-acp |
Agent Client Protocol (ACP) server |
# Clone repository
git clone https://github.com/aitomatic/dana-runtime.git
cd dana-runtime
# Install dependencies
uv syncRequires Python >= 3.11.
Once the first release is published, Dana can be installed directly (the
PyPI distribution is dana-agent; the import package is dana):
pip install dana-agentNote: the first PyPI release is pending — the publish workflow is in place, but the upload requires the maintainer's one-time Trusted Publisher setup on PyPI. Until it lands, use the git-clone installation above, or install a locally built wheel:
pip install <path>/dist/dana_agent-*.whl.
Dana reads provider keys from environment variables (or a .env file at the
repo root, loaded automatically):
# Required (at least one provider)
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."Or bootstrap interactively:
dana-initimport asyncio
from dana.core.agent import STARAgent
async def main():
agent = STARAgent(model="gpt-4.1")
response = await agent.aquery(message="What time is it?")
print(response["response"])
asyncio.run(main())aquery returns a dict with keys such as response, reasoning,
tool_calls, and done. This sample requires an LLM API key.
For host applications (durable conversation, turn events, journalling), use
AgentSession instead of driving STARAgent directly. A 15-line working
example lives at docs/examples/host_hello.py:
session = await AgentSession.create()
[print(e.text) async for e in session.prompt([TextBlock(text="hello")]) if e.event_type.name == "ASSISTANT_CONTENT_FINAL"]Run it with uv run python docs/examples/host_hello.py (live LLM; set
DANA_MOCK_LLM=1 for a canned reply — the mock switch is a property of that
example script, not a library feature).
dana-agent # main conversational agent
dana-agent-repl # Python REPL with Dana imported
dana-code # coding agentDana ships defaults in dana/config.json, which is loaded automatically.
To override it, point DANA_CONFIG_PATH at a custom file — the env var takes
precedence over the packaged defaults:
export DANA_CONFIG_PATH="/path/to/your/config.json"Provider entries use this shape (models maps alias → model ID):
{
"llm": {
"providers": {
"openai": {
"name": "OpenAI",
"priority": 100,
"base_url": "https://api.openai.com/v1",
"api_key_env": "OPENAI_API_KEY",
"default_model": "gpt-4.1",
"models": {
"gpt-4.1": "gpt-4.1",
"gpt-4.1-mini": "gpt-4.1-mini",
"o3": "o3",
"o4-mini": "o4-mini"
}
}
}
}
}# Required (at least one provider)
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
# Optional
export DANA_CONFIG_PATH="/path/to/config.json" # Custom config locationDana uses a layered architecture with clear separation of concerns:
Applications (CLI)
↓
Agent Layer (STARAgent + Components)
↓
Core Systems (Resources, Timeline, Workflows)
↓
LLM Abstraction (Providers, Codecs)
↓
Data Persistence & Infrastructure
Key Components:
- STARAgent - Main orchestrator with streaming support
- AgentSession - Host-facing conversational session with durable journal
- Resource System - Tool execution framework with auto-registration
- Timeline - Conversation history with compression
- Runtime - Provider-agnostic LLM abstraction
- Workflow - Multi-step composition engine
For detailed architecture, see docs/system-architecture.md.
All examples below require an LLM API key unless noted.
from dana.core.agent import STARAgent
agent = STARAgent(model="gpt-4.1")
response = await agent.aquery(message="Summarize Python features")
print(response["response"])import asyncio
from dana.core.agent import STARAgent
async def main():
agent = STARAgent(model="gpt-4.1")
async for event in agent.aquery_stream(message="Write a poem"):
print(event.event_type.name, event.data)
asyncio.run(main())Emits THINKING, TEXT_DELTA, and DONE events. For a raw
text-only stream, hosts can use aquery_text_stream(message=..., cancel_event=...) after adding the user message to the timeline (see
docs/examples/host_hello.py for the preferred
session-level path).
from dana.core.resource import BaseResource
class MyResource(BaseResource):
"""Custom resource for your domain."""
async def my_tool(self, param: str) -> str:
return f"Processed: {param}"
# Auto-registers with the global registry on instantiation
my_resource = MyResource()
# Use in agent
agent = STARAgent(model="gpt-4.1")
response = await agent.aquery(message="Call my_tool with 'hello'")from dana.lib.agents.web_research import WebResearchAgent
research = WebResearchAgent()
result = await research.aquery(message="Research Python 3.12 features")
print(result["response"])from dana.core.workflow import BaseWorkflow
class ResearchWorkflow(BaseWorkflow):
"""Research a topic and report."""
async def execute(self, topic: str):
return {"topic": topic}
workflow = ResearchWorkflow(workflow_id="research")# Install dev dependencies
uv sync
# Run tests
make test
# Run unit tests only
make test-unit
# Run linting
make lint
# Format code
make format
# Auto-fix lint issues
make fixmake test # All tests (excludes live)
make test-unit # Unit tests only
make test-live # Live tests (requires API keys)
make test-cov # Coverage reportTools:
- Ruff - Linting & formatting (line-length 140)
- Pytest - Testing framework
Standards:
- Type hints required on all functions
- All tests must pass before commit
- Follow code-standards.md
- Project Overview & PDR - Vision, goals, requirements
- Codebase Summary - Module structure and organization
- Code Standards - Coding conventions and patterns
- System Architecture - Architecture diagrams and data flows
- Branching Strategy - Git branching model and release flow
- Project Roadmap - Development timeline and milestones
- Extending Dana - Adding agents, resources, workflows
agent = STARAgent(
model: str | None, # e.g. "gpt-4.1"
llm_provider: str | None, # e.g. "openai", "anthropic"
max_context_tokens: int = 4000, # Timeline context budget
enable_web_search: bool = False, # search() + fetch_url(), no API key
enable_code_execution: bool = False, # sandboxed Python execution
enable_skills: bool = True, # Claude Code skills (DANA_CLAUDE_SKILLS=1 gates the scan)
)
# Query agent (async; returns a dict)
response = await agent.aquery(message: str)
# Stream events (THINKING / TEXT_DELTA / DONE)
async for event in agent.aquery_stream(message: str): ...
# Ephemeral replacement for this agent instance (no repository write)
agent.override_system_prompt_template("You are a domain specialist.")
# Only codec runtimes can persist the replacement to their prompt repository
agent.override_system_prompt_template(
"You are a persistent domain specialist.",
persist=True,
)
# Conversation state
state = agent.get_state() # dict
summary = agent.get_timeline_summary() # strpersist=False is the default: the override is ephemeral, scoped to the agent
instance, and never written to the prompt repository. persist=True is supported
only by codec runtimes and writes to their configured prompt repository; base
runtimes raise NotImplementedError. The template fully replaces, rather than
extends, the default system prompt, so retain every required tool-usage and
output-format instruction in the replacement.
from dana.core.resource import BaseResource
class CustomResource(BaseResource):
async def my_tool(self, param: str) -> str:
"""Tool docstring becomes tool description."""
return result
# Auto-registers on instantiation
resource = CustomResource()- Fork repository
- Create feature branch (
git checkout -b feature/my-feature) - Make changes following code-standards.md
- Run tests (
make test) - Commit with clear message
- Push to fork
- Create pull request
MIT License — see LICENSE. Copyright (c) 2026 Dana Contributors.
@software{dana-runtime,
title={Dana: Domain-Aware Neurosymbolic Agents},
author={Aitomatic, Inc.},
year={2026},
url={https://github.com/aitomatic/dana-runtime}
}- Documentation: docs/ directory
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- 0.2.0 - CLI entrypoints (
dana-agent,dana-agent-repl,dana-code,dana-memory,dana-init,dana-acp) with--help/--version;AgentSessionhost API - 0.1.1 (2026-03-21) - Stable, production-ready
- 0.1.0 (2026-03-01) - Initial release
Dana is developed by Aitomatic, Inc. with contributions from the open-source community.
Quick Links: Docs | Examples | API Reference | Contributing | License