"""The smallest setup: one agent, one tool, one job, the built-in frontends. The loader execs this file with ``ClaudeAgent``, ``RaycastAgent``, ``McpServer``, ``ExposedMcp`` and ``Gateway`` already bound; the imports below are for type checkers. A real setup grows into a package next to this file (see beaver-agent). """ import logging import tempfile from datetime import UTC, datetime from pathlib import Path from beaver_gateway.agents.base import ExposedMcp from beaver_gateway.agents.claude import ClaudeAgent, Prompts from beaver_gateway.config import Gateway from beaver_gateway.frontends.admin import AdminFrontend from beaver_gateway.frontends.anthropic import AnthropicMessagesFrontend from beaver_gateway.frontends.api import ApiFrontend from beaver_gateway.frontends.markdown import MarkdownFrontend from beaver_gateway.frontends.mcp_server import McpServerFrontend from beaver_gateway.jobs.scheduler import Job, JobRun from beaver_gateway.mcp.types import McpServer log = logging.getLogger("example") VAULT = Path(tempfile.mkdtemp(prefix="beaver-vault-")).resolve() PROMPT = VAULT / "assistant.md" PROMPT.write_text( "You are a concise assistant. When asked the time, call `current_time`.\n" ) def current_time() -> str: return datetime.now(UTC).astimezone().isoformat() async def heartbeat(run: JobRun) -> None: master = await run.master() log.info("heartbeat: master=%s", master.external_id if master else None) gateway = Gateway( agents=[ ClaudeAgent( name="assistant", model="claude-sonnet-5", cwd=VAULT, prompts=Prompts(master=(PROMPT,), branch=(PROMPT,), deep=(PROMPT,)), gateway_tools=("spawn", "say", "schedule"), expose_mcps=(ExposedMcp(name="time"),), ) ], mcps=[McpServer.python_tool(name="time", tools=[current_time])], frontends=[ AnthropicMessagesFrontend(), McpServerFrontend(), AdminFrontend(), ApiFrontend(master_agent="assistant", branch_agent="assistant"), MarkdownFrontend(vault_path=VAULT / "chats", default_agent="assistant"), ], jobs=[Job("heartbeat", heartbeat, cron="0 * * * *")], tz="UTC", )