An AI agent bot for Discord, built on Bun. OpenBorys runs as a Discord bot that processes messages through a state machine, calling LLM APIs and executing tools in a loop.
bun install
cp .env.template .env # fill in your keys
bun devFor production:
bun startCopy .env.template and fill in the values.
| Variable | What it's for |
|---|---|
DISCORD_TOKEN |
Bot token from the Discord developer portal |
DISCORD_CLIENT_ID |
Application ID for the bot |
REDIS_URL |
Redis connection string (stores tool call history) |
ANTHROPIC_API_KEY |
Anthropic API key for Claude |
OPENAI_API_KEY |
OpenAI API key |
REPLICATE_API_TOKEN |
Replicate API token (image generation) |
TAVILY_API_KEY |
Tavily API key (web search tool) |
AWS_ACCESS_KEY_ID |
Tigris object storage access key |
AWS_SECRET_ACCESS_KEY |
Tigris object storage secret |
AWS_ENDPOINT_URL_S3 |
Tigris endpoint (default: https://fly.storage.tigris.dev) |
AWS_REGION |
Storage region (default: auto) |
AWS_BUCKET |
S3 bucket name (default: openborys) |
PROMPTS_PREFIX |
S3 key prefix for prompt files |
FRIENDS_PREFIX |
S3 key prefix for friend data |
QDRANT_API_KEY |
Qdrant vector DB API key |
QDRANT_URL |
Qdrant instance URL |
QDRANT_COLLECTION |
Qdrant collection name |
QDRANT_BOT_NAME |
Bot identity name for Qdrant queries |
BOT_NAME |
Display name for the bot |
The agent is modelled as a recursive state machine. Each state is a handler function that receives a mutable context and returns the next state (or null to stop).
States:
- Message Received - Builds the system prompt and conversation context from the Discord message. Transitions to Thinking.
- Thinking - Sends the message history to the LLM to get the next step. If the model returns text (
stop), transitions to Sending Message. If it returns tool calls, queues them and transitions to Tool Call. - Tool Call - Pops the next pending tool call, sends a Discord embed showing what tool is being invoked, logs the call to Redis, and transitions to Executing Tool.
- Executing Tool - Runs the tool, appends the result to the message history, and logs it to Redis. If more tool calls are pending, loops back to Tool Call. Otherwise, transitions to Thinking for another LLM turn.
- Sending Message - Sends message to the Discord channel. Terminal state.
- Error - In case of unexpected failures. Terminal state.
The agent has access to these tools during a conversation:
| Tool | Description |
|---|---|
| Bash | Runs shell commands via Anthropic's bash tool |
| Web Search | Searches the web via Tavily |
| Web Fetch | Extracts page contents from a URL via Tavily |
| Remember | Saves a piece of text to Qdrant as a vector embedding for long-term memory |
| Phone | Sends a message to a "contact" (another LLM persona), with conversation history |
| Load Skill | Fetches a SKILL.md from a URL and injects its instructions into the system prompt |
| Unload Skill | Removes a previously loaded skill from the system prompt |
AGPL-3.0