# iolaus Personal agents for Daedalus — powered by [Pallas](https://git.helu.ca/r/pallas). Iolaus is a pure agent project: Python agent definitions + YAML configuration. The runtime (serving, registry, health checks, multimodal support) lives in Pallas. ## Architecture ``` Daedalus Backend — FastAPI │ MCP over StreamableHTTP ▼ Pallas MCP Bridge (pallas.server:main) │ reads agents.yaml for topology │ reads fastagent.config.yaml for LLM + model capabilities │ ├── Registry → /.well-known/mcp/server.json (agent discovery) ├── Shawn → kairos, neo4j_cypher, argos, research, time ├── Watson → argos, neo4j_cypher, time ├── Cristiano → nike, neo4j_cypher, time ├── Nate → periplus, argos, neo4j_cypher, time ├── David → orpheus, argos, neo4j_cypher, research, time ├── Research → argos, neo4j_cypher ├── Tech Research → context7, github, argos └── Mikael → argos, time (news briefings; reads `news:` config) ``` ## Project Structure ``` . ├── agents.yaml # Deployment topology — agents, ports, host, namespace ├── fastagent.config.yaml # LLM provider, MCP servers, model capabilities (committed) ├── fastagent.secrets.yaml # API keys and tokens (gitignored — never commit) ├── agents/ # Agent definitions (FastAgent @fast.agent decorators) │ ├── shawn.py │ ├── watson.py │ ├── cristiano.py │ ├── nate.py │ ├── david.py │ ├── research.py │ └── tech_research.py ├── systemd/ │ └── iolaus.service ├── pyproject.toml └── .env.example ``` ## Agents | Agent | Port | MCP URL | Purpose | |-------|------|---------|---------| | Shawn | 24001 | `http://puck.incus:24001/mcp` | Personal general assistant — calendar, contacts, email, and daily life | | Watson | 24005 | `http://puck.incus:24005/mcp` | Relationship memory & emotional safety — reflection, values, habits, emotional experiences, dialogue notes | | Cristiano | 24006 | `http://puck.incus:24006/mcp` | Football analyst — live data, match tracking, tactics | | Nate | 24007 | `http://puck.incus:24007/mcp` | Travel and adventure companion — trip planning, navigation | | David | 24008 | `http://puck.incus:24008/mcp` | Arts & culture — music, film, art, fashion, and Kawai piano | | Infrastructure | 24050 | `http://puck.incus:24050/mcp` | Shell, git, and Grafana router | | Research | 24051 | `http://puck.incus:24051/mcp` | Web search + knowledge graph chain | | Tech Research | 24052 | `http://puck.incus:24052/mcp` | Technical investigation — library docs, code examples, API comparisons | | Mikael | 24053 | `http://puck.incus:24053/mcp` | News briefings — topic-driven, source-verified, image-rich | | Registry | 24000 | `http://puck.incus:24000/.well-known/mcp/server.json` | Agent discovery | ## Configuration ### `agents.yaml` — Deployment Topology Single source of truth for agent names, ports, dependencies, host, and namespace. Read by Pallas at startup. ```yaml name: iolaus version: "1.0.0" host: puck.incus namespace: ca.helu.iolaus registry_port: 24000 agents: shawn: module: agents.shawn port: 24001 title: Shawn description: "Personal general assistant — calendar, contacts, email, and daily life management" depends_on: [research] # ... ``` To deploy a different agent group, swap `agents.yaml` — no code changes needed. Override the config path with `PALLAS_AGENTS_CONFIG` env var. ### `fastagent.config.yaml` — LLM + Model Capabilities Committed to the repo. Contains LLM provider settings and explicit model capability declarations. ```yaml default_model: openai.Qwen3.5-35B-A3B-UD-Q4_K_XL.gguf model_capabilities: vision: false context_window: 40960 max_output_tokens: 8192 ``` The `model_capabilities` section declares capabilities explicitly rather than inferring from the model name. Exposed in the registry for Daedalus to use when routing requests. ### `news:` — Mikael News Agent Configuration Top-level block in `fastagent.config.yaml`, consumed by `agents/mikael.py` at startup. Edits take effect on restart — no code changes needed to tweak topics or sources. ```yaml news: topics: - Canadian federal politics - Generative AI and LLM research # ... add/remove freely preferred_sources: # seeded into queries, not exclusive - reuters.com - apnews.com - cbc.ca avoided_sources: # excluded via -site: AND post-filtered by host - foxnews.com - breitbart.com - dailymail.co.uk default_lookback_hours: 24 max_items_per_topic: 5 ``` Mikael excludes `avoided_sources` from search results with `-site:` operators *and* post-filters by hostname as a second line of defence. It will never summarize or cite content from an avoided source, even if another outlet syndicates the claim. ### `fastagent.secrets.yaml` — API Keys and Tokens Gitignored — never commit. Place in the repo root alongside `fastagent.config.yaml`. ```yaml openai: api_key: "your-key-here" mcp: servers: angelia: headers: Authorization: "Bearer your-token" kairos: headers: Authorization: "Bearer your-token" periplus: headers: Authorization: "Bearer your-token" nike: headers: Authorization: "Bearer your-token" # ... ``` ## Quickstart ```bash # 1. Install dependencies (Python 3.13 required) source ~/env/iolaus/bin/activate pip install -e . # 2. Configure secrets cp fastagent.secrets.yaml.example fastagent.secrets.yaml # Edit: set api_key and service tokens # 3. Start all agents iolaus # 4. Verify curl http://localhost:24001/mcp # 5. Start a single agent iolaus --agent shawn ``` ## Daedalus Integration Daedalus connects to agents via the MCP Python SDK's `streamable_http_client`. Registry endpoint: `http://puck.incus:24000/.well-known/mcp/server.json` The registry includes model capabilities on each agent entry: ```json { "capabilities": { "model": "Qwen3.5-35B-A3B-UD-Q4_K_XL.gguf", "vision": false, "context_window": 40960, "max_output_tokens": 8192 } } ``` ## Deployment (systemd) ```bash # 1. Copy project to /srv/iolaus sudo cp -r . /srv/iolaus sudo chown -R iolaus:iolaus /srv/iolaus # 2. Install into venv cd /srv/iolaus source ~/env/iolaus/bin/activate pip install -e . # 3. Configure secrets cp fastagent.secrets.yaml.example fastagent.secrets.yaml # Fill in API keys and tokens # 4. Install and start systemd service sudo cp systemd/iolaus.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now iolaus sudo systemctl status iolaus ``` ## Downstream MCP Servers | Server | Host | URL | |--------|------|-----| | argos | miranda.incus | `http://miranda.incus:25534/mcp` | | neo4j_cypher | circe.helu.ca | `http://circe.helu.ca:22034/mcp` | | kernos | caliban.incus | `http://caliban.incus:22021/mcp` | | rommie | caliban.incus | `http://caliban.incus:22031/mcp` | | gitea | miranda.incus | `http://miranda.incus:25535/mcp` | | grafana | miranda.incus | `http://miranda.incus:25533/mcp` | | korax | korax.helu.ca | `http://korax.helu.ca:22021/mcp` | | orpheus | orpheus.helu.ca | `https://orpheus.helu.ca/mcp` | | angelia | ouranos.helu.ca | `https://ouranos.helu.ca/mcp/` | | kairos | ouranos.helu.ca | `https://kairos.ouranos.helu.ca/mcp/` | | periplus | ouranos.helu.ca | `https://periplus.ouranos.helu.ca/mcp/` | | nike | ouranos.helu.ca | `https://nike.ouranos.helu.ca/mcp/` | | github | local (Docker stdio) | `ghcr.io/github/github-mcp-server` | | context7 | local (stdio) | `npx -y @upstash/context7-mcp` | | time | local (stdio) | `mcp-server-time` | ## Notes - **Python 3.13** required (`fast-agent-mcp` pins `>=3.13`) - **Runtime:** [Pallas](https://git.helu.ca/r/pallas) — `pallas-mcp @ git+ssh://git@git.helu.ca:22022/r/pallas.git` - **Transport:** StreamableHTTP (`/mcp`) throughout — not SSE - **LLM:** OpenAI-compatible API at `http://nyx.helu.ca:22079/v1` (personal Qwen model) - **Logging:** Console output — stdout → syslog → Alloy → Loki in production - **Port scheme:** registry at 24000, personal agents 24001–24049, sub-agents 24050–24099