ProjectBEA — AI Persona Engine
ProjectBEA is a modular AI persona engine. It runs Bea: one always-on consciousness that talks out loud, plays Minecraft on a vanilla server with other people, holds conversations on Discord, Telegram and Twitch, remembers who you are across sessions, and works through the objectives her owner sets for the stream.
Everything she perceives arrives on one bus, passes an attention gate, and reaches a single mind that acts through tools. Every capability is a swappable plugin.
https://github.com/user-attachments/assets/00991f61-5eed-48cc-aefb-f2f6460120d7
The control room: everything she is perceiving, thinking and doing, on one screen.
Try it in five minutes#
One command. It installs uv if you don't have it, pulls the dependencies,
builds the dashboard and then asks you five questions.
macOS / Linux
curl -LsSf https://raw.githubusercontent.com/emqnuele/projectBEA/main/install.sh | bash
Windows (PowerShell)
irm https://raw.githubusercontent.com/emqnuele/projectBEA/main/install.ps1 | iex
The default profile is Solo chat: the dashboard and her voice, one API key, nothing else. No OBS, no Discord bot, no Minecraft server, no virtual audio cable — those are three separate profiles you can pick later, or turn on one at a time from the Abilities screen.
Already cloned the repo? make setup does the same thing.
Run it in Docker#
One image carries the engine, the dashboard and the Discord bot.
make docker # builds the image, then asks you the same five questions
make docker-up # http://127.0.0.1:8000
Or without the Makefile:
cp config.example.json config.json && touch .env && docker compose run --rm setup && docker compose up
What runs in a container: the dashboard, her memory, Discord (voice included — it travels over the network), Telegram, Twitch and Minecraft.
What does not: her speaking out of your computer's speakers. That needs a
real audio device. On Linux, uncomment the devices: block in
docker-compose.yml. On macOS and Windows, Docker Desktop cannot pass an audio
device through at all — so if you are streaming with OBS, run her natively.
The compose file publishes the dashboard to 127.0.0.1:8000, never to
0.0.0.0: the API has no authentication and must not be reachable from your
network. OBS lives on the host, so point obs_host at host.docker.internal.
Features#
| Feature | Description |
|---|---|
| One mind, many places | Discord, Telegram, Twitch, Minecraft and the dashboard all feed a single consciousness |
| Attention | She reacts to what concerns her and merely notices the rest, so a busy chat costs almost nothing |
| Parallel conversations | One turn at a time per channel, several channels at once — she talks on stage and texts at the same time |
| Memory | Diary, person cards and self-lore in one SQLite file, with local embeddings |
| Minecraft | A body on a vanilla server: she plays toward objectives, reads game chat and remembers players |
| Stream Plan | Set today's objectives from the dashboard — she works through them and ticks them off |
| Swappable LLMs | OpenRouter, OpenAI, Groq — configured per role, pooled for rotation and fallback |
| Multiple TTS engines | EdgeTTS (free), Kokoro (local ONNX), Orpheus (API) |
| OBS Integration | Avatar swap and animated text bubble over WebSocket |
| Control Room | React + FastAPI: a bento overview, chat, stream plan, live attention gate, her memory, abilities and every setting |
| Hot Reload | Change models, voices or settings at runtime, without a restart |
| Plugin Skills | Every capability is a Skill — add your own in minutes |
Architecture Overview#
Every sense pushes onto one bus. An attention gate decides what is worth a thought. One mind reasons over it and acts through tools.
discord · telegram · twitch · minecraft · donations · the dashboard
│ perceptions
▼
┌───────────────┐
│ PerceptionBus │
└───────┬───────┘
▼
┌───────────────┐ react / note / drop
│ Attention │───────────────┐
└───────┬───────┘ │
react ────────┤ │ noted
▼ ▼
┌─────────────────────────┐ [WHILE YOU WERE BUSY]
│ the live loop (stage) │ peripheral awareness
│ voice · game · owner │
└────────────┬────────────┘
│ written channels
▼
┌─────────────────────────┐
│ scoped conversation turns│ one per channel, in parallel
└─────────────────────────┘
│
▼ tools
speak · mc_chat · discord_reply · play_minecraft · objective_done · …
│
▼
Expression → TTS + OBS · bea.db (memory)
Full Architecture Documentation →
Project Structure#
ProjectBEA/
├── main.py # thin wrapper; the entrypoint is src/cli.py
├── config.example.json # copy to config.json and edit
├── install.sh / .ps1 # one-command bootstrap for a fresh machine
├── Dockerfile # engine + dashboard + discord bot in one image
├── docker-compose.yml # `setup` runs the wizard, `bea` runs the engine
├── Makefile # setup · docker · run · web · test · lint · migrate
├── data/
│ ├── bea.db # everything she remembers (gitignored)
│ ├── conversations/ # session transcripts
│ ├── pngs/ # avatars per mood (idle/talking)
│ └── prompts/ # soul · operating · monologue · minecraft
├── docs/
├── tests/ # 611 tests, no network
└── src/
├── cli.py # argument parsing and composition
├── core/
│ ├── brain.py # composition root
│ ├── consciousness.py# the one always-on loop
│ ├── config.py
│ ├── events.py # pub/sub + SSE fan-out
│ ├── perception/ # bus, Perception, Author
│ ├── attention/ # the gate: rules (pure) + state
│ ├── mind/ # routing, scheduler, conversations, correlation
│ ├── memory/ # sqlite, rag, embedder, profiler, plan
│ ├── expression/ # the single output sink + humanizer
│ ├── agent/ # LLMClient, role pools, tools, runner
│ └── skills/ # one package per capability
├── interfaces/ # TTS · STT · OBS contracts
├── modules/ # llm · tts · STT · obs implementations
├── utils/
└── web/
├── app.py # FastAPI
└── frontend/ # React + Vite + Tailwind
Manual setup#
make setup covers everything below. This is the same thing, by hand.
1. Prerequisites#
- uv — manages Python and dependencies (installs Python for you)
- Node.js 18+ (for the web dashboard and the Discord bot)
- OBS Studio with WebSocket plugin enabled (Tools → WebSocket Server Settings)
- A virtual audio cable such as VB-Audio Cable (optional but recommended)
2. Install dependencies#
uv sync # or: make install
3. Configure#
Run the wizard — it writes both files for you, and re-running it is safe:
uv run bea --setup # or: make setup
Or do it by hand. Copy .env.example to .env (or set environment variables directly):
OPENROUTER_API_KEY=sk-or-...
OPENAI_API_KEY=sk-...
GROQ_API_KEY=gsk_...
DISCORD_TOKEN=...
Review config.json to set your OBS source names, audio device ID, TTS voice, and which skills are enabled.
4. Run#
CLI mode (terminal interactive):
uv run bea # or: make run
Web Dashboard mode (FastAPI + React UI):
uv run bea --web # or: make web (builds the frontend too)
Override provider at launch:
uv run bea --llm-provider openrouter --tts-provider kokoro --web
5. Tests and lint#
make test # uv run pytest -q
make lint # uv run ruff check src tests
The suite runs without network access or API keys: every model client, surface and transport is faked.
Modules#
The engine is built around three types of components, each defined by an abstract interface in src/interfaces/base_interfaces.py. Any provider can be swapped without touching the core.
| Component | Interface | Implementations |
|---|---|---|
| LLM | LLMClient (tool-aware) | OpenRouter, OpenAI, Groq |
| TTS | TTSInterface | EdgeTTS, Kokoro (local), Orpheus |
| STT | STTInterface | Groq, OpenRouter (Whisper) |
| OBS | OBSInterface | OBS WebSocket (obs-websocket-py) |
Models are configured per role rather than one at a time: mind for the
consciousness, background for the diary, the dreamer and the game body. Each
role is a pool that round-robins to spread rate limits and falls back when a
provider is down.
LLM Modules → · TTS Modules → · STT → · OBS →
Skills — Plugin System#
A skill is one capability of the single mind. It can perceive, expose tools, contribute prompt rules and own infrastructure — and every one can be toggled at runtime from the dashboard. Bea can never arm a capability herself.
| Skill | Description |
|---|---|
| Discord | Voice calls and text channels; owns the Node.js bot |
| Telegram | Private chats and groups, in-process |
| Twitch | Chat read anonymously; volume becomes texture, not thoughts |
| Minecraft | A body on a vanilla server: she plays, chats and remembers players |
| Donations | A webhook that always earns a reaction |
| Stream Plan | Today's objectives, set by the owner |
| Memory | Diary entries and recall, over one SQLite file |
| Social | Who people are: a tally for everyone, a card for the ones who matter |
| Dream | Sleep, self-lore and nightly consolidation |
| Monologue | Filling the silence when nothing is happening |
Web Dashboard#
The --web flag starts a FastAPI backend (port 8000) and serves a React + Tailwind frontend.
It opens on a boot screen that checks the brain is actually answering before it lets you in, then on a bento overview of everything at once.

Screens:
- Overview — is she awake, what she last said, today's progress, the attention gate, spend, abilities, and the live feed, all on one screen
- Talk — the private line to her: streams voice in and out, and shows it plainly when she hears you and chooses not to answer
- Today — the orders she reads every turn, plus objectives you can reorder, edit and close; she closes them herself as she goes
- Activity — the attention gate drawn live, and a filterable, freezable event stream underneath it
- Memory — who she knows, everyone she has met, a search over what she remembers, and the things she has worked out about herself
- Abilities — every capability on or off at runtime, plus the Minecraft cockpit
- Settings — eight sections with connection tests, and one save for all of them
⌘K opens the command palette from anywhere.
The API has no authentication, so the server binds to 127.0.0.1 unless
--host says otherwise. Do not put it on a public address as it stands.
Full Documentation#
| Document | Contents |
|---|---|
| Architecture | System design, data flow, event system |
| Setup & Install | Installation, OBS setup, audio routing |
| Configuration | All config fields, CLI args, .env vars |
| LLM Modules | Providers, response format, adding new LLMs |
| TTS Modules | EdgeTTS, Kokoro, Orpheus |
| OBS Module | Avatar control, text animation |
| STT Module | Whisper transcription |
| Skills Overview | The Skill API, the registry, every tool |
| Memory | Recall, the diary, the embedding model |
| Social | The roster, person cards, promotion |
| Dream | Self-lore, hot facts, the nightly pass |
| Stream Plan | Objectives, and what makes her act on them |
| Discord | The bot, the voice pipeline, the tools |
| Telegram | In-process polling and scoped turns |
| Twitch | Anonymous IRC, tally, chat as texture |
| Donations | The webhook and what one donation writes |
| Minecraft | The body, the mod protocol, the goal loop |
| Monologue | The idle perception |
| Web API | Every REST endpoint |
| Frontend | React component structure |
Extending ProjectBEA#
The modular design makes adding new capabilities straightforward:
- New LLM provider → extend
OpenAICompatibleClient, add it tofactory.build_client() - New TTS engine → implement
TTSInterface, add the branch and the CLI choice insrc/cli.py - New skill → extend
Skill, register it inAIVtuberBrain._build_consciousness() - New text platform → extend
PlatformSkilland the roster, person cards, attention gate and scoped conversations work with no extra code
See Skills Overview for the full plugin API.
About#
Built by Emanuele Faraci, 19-year-old Computer Science student from Italy.
This project started as a way to learn Python properly, specifically async programming, API integrations, and modular system design, while building something actually fun. It grew from a simple TTS + OBS script into a full persona engine with skills, memory, and a web dashboard.
just a side project built for fun and learning.
Portfolio: emanuelefaraci.com
License#
This project is open-source. See LICENSE for details.