Rowan is a lean, local-first conversational AI engine written in Go. It routes text chat and real-time WebSocket voice through a single LLM-native dialog engine that decides which tools to call — no slot-filling FSM or NLU preprocessing.
Agents are configured entirely through a YAML profile (name, languages, tools, guidelines), so you never rebuild the binary to change behaviour. Out of the box Rowan runs against fully local models (Ollama, Whisper, a local TTS server) and requires no cloud account. Google Cloud is available as an opt-in backend.
- Two channels, one engine — HTTP chat (
/chat) and WebSocket voice & text (/voice-agent,/chat-agent). - LLM-native tool calling — the model calls webhook-backed tools defined in
your profile; built-in
end_callandswitch_languagemeta-tools. - Local-first backends — Ollama (LLM), Whisper (ASR), local TTS by default; switch any one to Google Cloud with an env var.
- YAML agent profiles — languages, verification, tools, policy, and custom guidelines without recompiling.
- Production plumbing — Prometheus metrics (
/metrics), structured logging, health endpoints (/healthz,/health,/ready), rate limiting, and graceful shutdown.
| Channel | Endpoint | Use case |
|---|---|---|
| Chat | POST /chat, POST /chat/welcome |
Text web/mobile apps |
| WebSocket (voice) | /voice-agent |
Real-time voice for browsers/SDKs (8 kHz PCM) |
| WebSocket (text) | /chat-agent |
Streaming text chat |
The fastest path is the bundled stack, which runs Rowan alongside Ollama, a Whisper ASR server, and a local TTS server:
docker compose -f deploy/docker-compose.yml up
# one-time, in another terminal: pull a model
docker compose -f deploy/docker-compose.yml exec ollama ollama pull llama3.1Then:
- Health: http://localhost:6789/health
- Chat:
curl -X POST http://localhost:6789/chat \ -H "Content-Type: application/json" \ -d '{"session_id":"demo","message":"Where is order 123456?"}'
- Voice & text-chat demo (development mode): http://localhost:6789/demo/
# Requires Go 1.25+ and reachable Ollama/Whisper/TTS servers (see .env.example)
cp .env.example .env
# edit .env to point at your backends (e.g. set the *_BACKEND vars to google)
make run # builds and runs with examples/agent.yamlA .env file in the working directory is loaded automatically — both by
make run and by the binary itself — so the values you set there take effect
without exporting them by hand. Variables already present in the real
environment take precedence over the file.
All configuration is via ROWAN_* environment variables — see
.env.example for the full list with defaults. A .env file
in the working directory is loaded automatically at startup (real environment
variables override it). Key ones:
| Variable | Default | Purpose |
|---|---|---|
ROWAN_LISTEN_ADDR |
:6789 |
HTTP/WS listen address |
ROWAN_PROFILE_FILE |
./agent.yaml |
Path to the agent profile YAML |
ROWAN_LLM_BACKEND |
ollama |
ollama or google |
ROWAN_ASR_BACKEND |
whisper |
whisper or google |
ROWAN_TTS_BACKEND |
local |
local or google |
ROWAN_MAX_CONCURRENT_CALLS |
10 |
Max simultaneous voice sessions |
Set the relevant backend to google and provide credentials:
ROWAN_LLM_BACKEND=google
ROWAN_GOOGLE_PROJECT_ID=your-project
ROWAN_GOOGLE_REGION=europe-west1
ROWAN_GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.jsonAn agent is defined by a YAML profile — see examples/agent.yaml
for a working example and docs/agent-profile-guide.md
for the full authoring guide. Tools can be mocked (mock: true) for demos or
point at real webhook URLs for production.
rowan/
├── cmd/rowan/ # entry point (HTTP server: chat + WebSocket)
├── internal/
│ ├── dialog/ # LLM-native dialog manager + session state
│ ├── llm/ # LLM client (Ollama default, Google optional)
│ ├── asr/ # Speech-to-text (Whisper default, Google optional)
│ ├── tts/ # Text-to-speech (local default, Google optional)
│ ├── chat/ # HTTP chat handler
│ ├── ws/ # WebSocket voice + text servers
│ ├── profile/ # runtime profile + tool types
│ ├── agentconfig/ # YAML profile loader + webhook tool builder
│ ├── config/ # env var configuration
│ ├── logging/ metrics/ health/ middleware/ resources/
├── examples/agent.yaml # sample profile
├── deploy/docker-compose.yml # local stack (Ollama + Whisper + TTS + Rowan)
├── web/voice-demo/ # browser voice client
└── docs/agent-profile-guide.md
make build # build the binary to out/rowan
make test # go test ./...
make vet # go vet ./...
make fmt # go fmt ./...