Skip to content

Parasaran-Python/eidolon

Repository files navigation

Eidolon

An extensible AI agent framework with event-sourced architecture. Supports multiple LLM providers (OpenAI, Anthropic, Google, local via Ollama), MCP server integration, custom Python tools, parallel sub-agents, persistent memory, and both terminal and web interfaces.

Why Eidolon?

In Greek mythology, an eidolon is an ideal form -- a spirit that acts on your behalf. That's the idea here.

The AI agent landscape is fragmented. LangChain is a dependency maze. CrewAI is opinionated about multi-agent patterns you may not want. AutoGen assumes you're building chatrooms. Most frameworks lock you into one provider, one way of doing things, one interface. And almost none of them speak MCP.

Eidolon was built on a few beliefs:

Your agent framework shouldn't be smarter than you. No hidden chains, no magic graphs, no 47-layer abstractions between your prompt and the LLM. The agent loop is a while True that calls the model, executes tools, and loops. You can read it in five minutes. When something breaks, the stack trace makes sense.

Provider lock-in is a trap. Today you want Claude for reasoning. Tomorrow you want Gemini for its context window. Next week you're running Llama locally for privacy. Eidolon's provider protocol is a Python Protocol -- structural typing, no inheritance. Write a class with complete(), stream_complete(), and count_tokens(), and it works. Swap providers by changing one line in a YAML file.

Tools should be functions, not frameworks. Decorate a Python function with @tool. Its type hints become JSON Schema. Its docstring becomes the description. That's it. No tool classes, no schema builders, no registration ceremony. If you can write a function, you can write a tool.

MCP is the future of tool interoperability. Instead of building a GitHub integration, a Playwright integration, and a database integration from scratch, Eidolon connects to MCP servers. Drop a .mcp.json in your project and the agent gains access to every tool those servers provide. The same MCP servers you use with Claude Code or Cursor work with Eidolon unchanged.

Events are the natural language of agents. An agent thinks, calls tools, receives results, and responds. That's a stream of events. By making events first-class -- typed, published, subscribable -- everything else falls out naturally. The WebSocket handler? Subscribe to the bus. The terminal UI? Subscribe to the bus. Audit logging? Subscribe to the bus. A new interface you haven't thought of yet? Subscribe to the bus.

You should own your agent. Eidolon runs on your machine, with your models, with your data. It works with a $0 Ollama setup or a $100/month API key. The code is MIT-licensed, 100% open source, and has zero telemetry.

Features

  • Multi-provider -- OpenAI, Anthropic (Claude), Google (Gemini), and local models via Ollama. Swap providers with one config change.
  • Event-sourced kernel -- Every action produces typed events flowing through an async bus. Built-in audit trail and replay.
  • MCP integration -- Connect to any MCP server (stdio, SSE, HTTP, WebSocket). Auto-discovers tools from .mcp.json.
  • Tool system -- Define tools as decorated Python functions. Type hints become JSON Schema automatically.
  • Sub-agents -- Spawn parallel child agents with filtered tool access and supervision policies.
  • Persistent memory -- SQLite-backed conversation history with session management.
  • Terminal UI -- Rich Textual TUI with streaming, tool call panels, and syntax highlighting.
  • Web UI -- React + TypeScript three-panel interface with real-time WebSocket streaming.
  • FastAPI backend -- REST API + WebSocket for building custom integrations.

Quick Start

Install

git clone https://github.com/Parasaran-Python/eidolon.git
cd eidolon
python -m venv .venv
source .venv/bin/activate
pip install -e ".[all,dev]"

Configure

Create eidolon.yaml (or copy the included one):

agent:
  provider: anthropic          # or openai, google, ollama
  model: claude-sonnet-4-20250514
  system_prompt: "You are a helpful assistant."

providers:
  anthropic:
    api_key: ${ANTHROPIC_API_KEY}
  # openai:
  #   api_key: ${OPENAI_API_KEY}
  # ollama:
  #   base_url: http://localhost:11434
  #   model: gemma3:4b

Run

# One-shot
eidolon run "What is the capital of France?"

# Interactive TUI
eidolon chat

# Web UI
eidolon serve        # API on http://localhost:8000
cd web && npm install && npm run dev   # UI on http://localhost:5173

Architecture

                         EVENT BUS
                    (async, topic-based)
                     /       |        \
                    v        v         v
              AGENT LOOP  TOOL       MCP
              (think/act) EXECUTOR   MANAGER
                    |        |         |
              PROVIDER    @tool     MCP Servers
              REGISTRY    funcs    (stdio/SSE/HTTP)
              /  |  |  \
         OpenAI  Anthropic  Google  Ollama

Every action produces a typed Pydantic event. The TUI, Web UI, and API are all event subscribers -- adding a new interface means subscribing to the bus.

Event Flow

UserMessage -> CompletionRequested -> CompletionStarted -> StreamChunk (x N)
  -> CompletionFinished -> ToolCallRequested -> ToolCallStarted
  -> ToolCallCompleted -> (loop back to CompletionRequested)
  -> TurnCompleted

Tools

Define tools as decorated Python functions:

from eidolon.tools import tool

@tool
async def web_search(query: str, max_results: int = 10) -> list[dict]:
    """Search the web for information.

    Args:
        query: The search query
        max_results: Maximum results to return
    """
    # Your implementation
    return results

Type hints become JSON Schema automatically via Pydantic. Sync functions run in a thread pool. Optional sandbox=True runs in a subprocess.

MCP Servers

Eidolon discovers MCP servers from two sources:

  1. eidolon.yaml -- explicit configuration
  2. .mcp.json -- auto-discovered (Claude Desktop / Cursor format)
{
  "playwright": {
    "command": "npx",
    "args": ["@playwright/mcp@latest"]
  }
}

MCP tools are merged into the agent's tool registry transparently -- the agent loop doesn't distinguish between local and MCP tools.

Providers

Provider SDK Tool Calling Key Features
OpenAI openai Yes GPT-4o, o-series. tiktoken token counting.
Anthropic anthropic Yes Claude series. Extended thinking, prompt caching.
Google google-genai Yes Gemini series. 1M context window.
Ollama openai (compat) Model-dependent Local models. Auto-detects tool support per model family.

Install only what you need:

pip install eidolon[openai]      # OpenAI only
pip install eidolon[anthropic]   # Anthropic only
pip install eidolon[google]      # Google only
pip install eidolon[all]         # Everything

Sub-Agents

Spawn parallel child agents with independent context:

from eidolon.agents import SubAgentSpawner, SubAgentTask

spawner = SubAgentSpawner(bus=bus, provider=provider, ...)
results = await spawner.spawn([
    SubAgentTask(prompt="Research X", tool_names=["web_search"]),
    SubAgentTask(prompt="Analyze Y", tool_names=["read_file"]),
])
# Both run in parallel via asyncio.TaskGroup

CLI Commands

Command Description
eidolon chat Interactive TUI (or REPL fallback)
eidolon serve Start FastAPI server
eidolon run "<prompt>" One-shot mode
eidolon tools list List available tools
eidolon config Show resolved configuration
eidolon mcp status MCP server connection status

Web UI

Three-panel layout: session sidebar, chat area with tool call cards, and an event inspector.

cd web
npm install
npm run dev    # http://localhost:5173

Requires the API server running (eidolon serve). The Vite dev server proxies /api and /ws to localhost:8000.

Docker

cd docker
docker compose up -d

Services: Ollama (model server), Eidolon (Python backend), Web (nginx frontend).

Configuration

eidolon.yaml is loaded from: ./eidolon.yaml -> ~/.eidolon/config.yaml. Supports ${ENV_VAR} expansion.

agent:
  name: my-assistant
  provider: anthropic
  model: claude-sonnet-4-20250514
  system_prompt: "You are a helpful assistant."
  temperature: 0.7
  max_tokens: 4096

providers:
  anthropic:
    api_key: ${ANTHROPIC_API_KEY}
  ollama:
    base_url: http://localhost:11434

tools:
  directories: [./tools]

mcp_servers: []
  # - name: github
  #   transport: stdio
  #   command: ["npx", "-y", "@modelcontextprotocol/server-github"]

memory:
  backend: sqlite
  path: ~/.eidolon/memory.db

server:
  host: 0.0.0.0
  port: 8000
  cors_origins: ["http://localhost:5173"]

Project Structure

src/eidolon/
  core/         # Agent loop, event bus, event types, core types
  providers/    # LLMProvider protocol + OpenAI, Anthropic, Google, Ollama
  tools/        # @tool decorator, registry, executor
  mcp/          # MCP client, manager, bridge, lifecycle
  memory/       # SQLite persistence, event store, context window
  agents/       # Sub-agent spawner, supervisor
  api/          # FastAPI routes, WebSocket streaming
  tui/          # Textual terminal UI
  config/       # Pydantic settings, YAML loading
  plugins/      # Entry-point plugin discovery
  cli/          # Click CLI entry point
web/            # React + TypeScript frontend
docker/         # Docker Compose, Dockerfiles
tests/          # 482 tests (unit, integration, e2e)

Development

pip install -e ".[all,dev]"
pytest tests/ -v              # Run all tests
ruff check src/               # Lint
mypy src/                     # Type check

License

MIT

About

An extensible AI agent framework with event-sourced architecture

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors