A local, single-command platform to build, wire, run, and observe collaborating AI agents. One agent is reachable from Telegram so a human can converse with the swarm.
Prerequisite: Docker Desktop (Windows / macOS / Linux). No other tools required.
Windows (PowerShell):
copy .env.example .env # then edit .env with OPENAI_API_KEY and TELEGRAM_BOT_TOKEN
docker compose up --build # one command: API + UI + Telegram worker
# open http://localhost:3000macOS / Linux:
cp .env.example .env # then edit .env with OPENAI_API_KEY and TELEGRAM_BOT_TOKEN
docker compose up --build
# open http://localhost:3000Leaving OPENAI_API_KEY and TELEGRAM_BOT_TOKEN blank is fine — the platform still boots, agents run on a deterministic stub, and the Telegram adapter gracefully disables itself.
Two pre-built workflow templates (Research → Writer and Triage → Specialist → Summarizer) are seeded on first boot — pick one in the UI, click Run, then DM your Telegram bot to interact.
If you'd rather not install Docker, you can run the backend and frontend directly. Requires Python 3.11+ and Node.js 20+.
One-time setup:
copy .env.example .env # optional: edit to add OPENAI_API_KEY / TELEGRAM_BOT_TOKEN
# Backend
cd backend
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
cd ..
# Frontend
cd frontend
npm install
cd ..If PowerShell blocks the venv activation script, run once:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Then in two terminals:
# Terminal 1 — backend
cd backend
.\.venv\Scripts\Activate.ps1
uvicorn app.main:app --reload --port 8000# Terminal 2 — frontend
cd frontend
npm run devOpen http://localhost:3000.
cp .env.example .env
# Backend
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cd ..
# Frontend
cd frontend
npm install
cd ..
# Run both (or use `make dev` as a shortcut)
( cd backend && source .venv/bin/activate && uvicorn app.main:app --reload --port 8000 ) &
( cd frontend && npm run dev )Open http://localhost:3000.
cd backend
pytest -q| Capability | Where |
|---|---|
| Create agents (name, role, prompt, model, tools, memory, schedule, guardrails) | UI → Agents |
| Visual workflow builder w/ conditions + feedback loops | UI → Workflows (React Flow) |
| Real, async multi-agent runtime executing real tools | backend/app/runtime/ (LangGraph) |
| Telegram chat with the swarm | backend/app/channels/telegram.py |
| Live log stream + inter-agent messages + token/cost | UI → Monitor (WebSocket) |
| Persisted message history, visible in UI | SQLite via SQLAlchemy |
| 2 seeded workflow templates | backend/app/seeds/templates.py |
| Tests for critical paths | backend/tests/ |
Why these choices (short version — long version in docs/ARCHITECTURE.md)
- Python + FastAPI — gravitational center of the AI ecosystem; async-native; minimal ceremony.
- LangGraph as the runtime — a workflow is a graph. Nodes = agents, edges = transitions, conditional edges = branches, cycles = feedback loops. The visual builder maps 1:1 to the runtime, so there is no impedance mismatch between what the user draws and what executes.
- SQLite + SQLAlchemy — zero-ops persistence that ships in one container. Swappable for Postgres by changing one env var.
- Telegram (long-polling) — fully local: no public URL, no ngrok, no webhook gymnastics. Adapter pattern leaves Slack/WhatsApp as drop-in replacements.
- Next.js 14 + React Flow + shadcn/ui — the de-facto stack for shipping polished internal-tool UIs fast.
- WebSocket event bus in-process — live monitoring without Redis/Kafka for a local-first product.
┌────────────────────────────────────────────────────────────────────┐
│ Next.js 14 UI (port 3000) │
│ Agents · Workflows (React Flow) · Runs · Live Monitor (WS) │
└──────────────┬─────────────────────────────────────┬───────────────┘
REST / JSON WebSocket / events
│ │
┌──────────────▼─────────────────────────────────────▼───────────────┐
│ FastAPI (port 8000) │
│ /agents /workflows /runs /channels /ws/monitor │
│ │
│ ┌──────────────┐ ┌────────────────┐ ┌──────────────────────┐ │
│ │ API layer │──▶│ Runtime │──▶│ ChannelAdapter │ │
│ │ (Pydantic) │ │ (LangGraph) │ │ base → telegram.py │ │
│ └──────┬───────┘ └───────┬────────┘ └──────────┬───────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ SQLAlchemy ⇄ SQLite (data/agentx.db) │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ EventBus (asyncio pub/sub) — runtime → WS clients │ │
│ └──────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
Layer boundaries are enforced:
api/never imports fromruntime/internals — it callsruntime.engine.run_workflow(...).runtime/never importsapi/— it emits events through theEventBus.channels/depend only on theChannelAdapterABC and the API; swapping Telegram → Slack means a new file.
See docs/ARCHITECTURE.md for the deeper rationale, data model, and sequence diagrams.
| Dimension | Field | Effect |
|---|---|---|
| Identity | name, role, avatar |
Display + routing |
| Personality | system_prompt |
Injected as system message |
| Brain | model, temperature, max_tokens |
LLM call params |
| Tools | tools: string[] |
Subset of registered tools the agent may call |
| Memory | memory_strategy (none | window:N | summary) |
Context window policy |
| Schedule | cron |
Trigger workflow on a schedule |
| Skills | skills: string[] |
Free-form tags surfaced to router agents |
| Interaction rules | can_talk_to: agentId[] |
Hard ACL on agent-to-agent messaging |
| Guardrails | max_steps, max_cost_usd, denylist_regex |
Runtime kill-switches |
| Channels | channels: ['telegram', ...] |
Which inboxes the agent listens on |
All of this is editable in the Agents form and persisted as JSON columns.
- Add a function returning a
WorkflowSpectobackend/app/seeds/templates.py. - Register it in the
TEMPLATESdict at the bottom of that file. - Restart — it appears in the UI's + From template menu.
- Create
backend/app/channels/slack.pysubclassingChannelAdapter(start,stop,send). - Register it in
channels/__init__.py'sREGISTRY. - Add the channel string to an agent's
channelsfield in the UI.
No other code changes required — the API and UI iterate the registry.
cd backend && pytest -qCritical-path coverage:
test_agents.py— agent CRUD + validationtest_workflow.py— graph compilation + a 2-agent run executing a real tooltest_telegram.py— adapter delivers an inbound message to the runtime (mocked transport)
agentx/
├─ backend/ Python · FastAPI · LangGraph
│ ├─ app/
│ │ ├─ api/ HTTP + WS routes
│ │ ├─ runtime/ Engine, tools, memory, guardrails
│ │ ├─ channels/ Telegram adapter (+ ABC for more)
│ │ ├─ models/ SQLAlchemy ORM
│ │ ├─ seeds/ Pre-built workflow templates
│ │ ├─ events.py In-process pub/sub
│ │ ├─ db.py · config.py · main.py
│ └─ tests/
├─ frontend/ Next.js 14 · TS · Tailwind · React Flow
│ ├─ app/ Routes: /, /agents, /workflows, /runs, /monitor
│ ├─ components/
│ └─ lib/
├─ docs/
│ └─ ARCHITECTURE.md
├─ docker-compose.yml
├─ Makefile
└─ .env.example
docker compose up— UI + API + Telegram worker boot.- Open
/agents— show the 4 seeded agents and edit one's guardrails. - Open
/workflows— open the Research → Writer template, walk the graph. - Click Run, send the goal: "Write a 150-word brief on AgentX's value proposition."
- Open
/monitor— watch the live log stream, inter-agent messages, and cost ticker. - Switch to Telegram, message
@your_bot: "Status?" — the Concierge agent answers, then delegates to the workflow. - Walk the code: API layer → runtime → channel adapter → tests passing.
MIT — see LICENSE.