Skip to main content
ollim-bot is a standard Python project managed with uv. This guide covers setting up a development environment, running the bot locally, and understanding the project structure and conventions.

Prerequisites

  • uvcurl -LsSf https://astral.sh/uv/install.sh | sh (automatically installs the required Python version)
  • A Discord bot token (see Discord bot setup)
  • Google OAuth credentials (see Google OAuth setup) if using Google integrations

Setup

1

Clone the repository

git clone https://github.com/Ollim-AI/ollim-bot.git
cd ollim-bot
2

Install dependencies

uv tool install --editable .
uv tool install claude-history@git+https://github.com/Ollim-AI/claude-history.git
uv sync
uv run pre-commit install
The first command installs ollim-bot as a global command. claude-history is a global CLI tool required by subagents. uv sync installs dev dependencies (pytest, ruff, ty). Pre-commit hooks enforce linting and type checking on every commit.
3

Configure environment variables

Create a .env file in the project root:
.env
DISCORD_TOKEN=your-discord-bot-token
OLLIM_USER_NAME=YourName
OLLIM_BOT_NAME=Ollim
VariableRequiredDescription
DISCORD_TOKENYesDiscord bot token
OLLIM_USER_NAMEYesYour display name (used in the system prompt)
OLLIM_BOT_NAMEYesThe bot’s display name
OLLIM_TIMEZONENoIANA timezone (e.g. America/New_York); defaults to system local
WEBHOOK_PORTNoPort for the webhook HTTP server (e.g. 8420)
WEBHOOK_SECRETConditionalBearer token for webhook auth (required if WEBHOOK_PORT is set)
4

Run the bot

ollim-bot
The bot checks for an existing instance via a PID file at ~/.ollim-bot/state/bot.pid and exits if one is already running.

Running tests

uv run pytest
Dev dependencies include pytest, pytest-asyncio, and pytest-cov. See Testing for the test philosophy and conventions.

Linting and type checking

ollim-bot uses ruff for linting and formatting, and ty for type checking. Pre-commit hooks run both automatically on every commit.
# Lint
uv run ruff check

# Format
uv run ruff format

# Type check
uv run ty check

# Install pre-commit hooks (one-time setup)
uv run pre-commit install
The pre-commit config runs ruff --fix (auto-fixes safe lint issues), ruff format, and ty check on staged Python files. CI runs the same checks — see below.

CI

GitHub Actions runs on every push and pull request to main:
  • Lint jobruff check, ruff format --check, ty check
  • Test jobpytest across Python 3.11, 3.12, and 3.13

Project structure

The source lives under src/ollim_bot/. Each file owns a single domain — there are no utils, helpers, or common modules.
src/ollim_bot/
├── main.py              # CLI entry point and command router
├── bot.py               # Discord interface (DMs, slash commands)
├── agent.py             # Claude Agent SDK brain (sessions, MCP tools, subagents)
├── prompts.py           # System prompt for main agent and fork prompt helpers
├── subagent_prompts.py  # System prompts for subagents
├── agent_tools.py       # MCP tools (discord_embed, ping_user, enter_fork, etc.)
├── config.py            # Env vars loaded from .env via dotenv
├── forks.py             # Fork state (bg + interactive), pending updates I/O
├── sessions.py          # Session ID persistence and session history JSONL log
├── permissions.py       # Discord-based tool approval (canUseTool callback)
├── streamer.py          # Streams agent responses to Discord (throttled edits)
├── storage.py           # JSONL/markdown I/O and git auto-commit
├── embeds.py            # Embed/button types, builders, and build_embed/build_view
├── views.py             # Persistent button handlers via DynamicItem
├── inquiries.py         # Button inquiry prompt persistence (7-day TTL)
├── ping_budget.py       # Refill-on-read ping budget for background fork notifications
├── formatting.py        # Tool-label formatting helpers
├── webhook.py           # Webhook HTTP server for external triggers
├── google/
│   ├── auth.py          # Shared Google OAuth2 (Tasks + Calendar + Gmail)
│   ├── tasks.py         # Google Tasks CLI + API helpers
│   ├── calendar.py      # Google Calendar CLI + API helpers
│   └── gmail.py         # Gmail CLI (read-only)
└── scheduling/
    ├── scheduler.py     # APScheduler-based proactive scheduling
    ├── routines.py      # Routine dataclass and markdown I/O
    ├── reminders.py     # Reminder dataclass and markdown I/O
    ├── preamble.py      # Bg preamble and forward schedule builder
    ├── routine_cmd.py   # Routines CLI (ollim-bot routine)
    └── reminder_cmd.py  # Reminders CLI (ollim-bot reminder)

CLI subcommands

The ollim-bot command doubles as both the bot runner and a CLI for managing routines, reminders, and Google integrations. Running ollim-bot with no arguments starts the Discord bot. Subcommands route to their respective modules:
CommandDescription
ollim-botStart the Discord bot
ollim-bot routine add|list|cancelManage recurring routines
ollim-bot reminder add|list|cancelManage one-shot reminders
ollim-bot tasks list|add|done|update|deleteGoogle Tasks operations
ollim-bot cal today|upcoming|show|add|update|deleteGoogle Calendar operations
ollim-bot gmail unread|read|searchGmail (read-only)
ollim-bot helpShow help text
See the CLI reference for full flag documentation.

Code conventions

These rules come from the project’s CLAUDE.md and apply to all contributions.

Hard invariants

Violating these causes runtime bugs.
Channel-sync invariant — every path into stream_chat must call both agent_tools.set_channel and permissions.set_channel. This applies to _dispatch, _check_fork_transitions, slash_fork, send_agent_dm, button handlers in views.py, and check_fork_timeout in scheduler.py.

Design rules

RuleRationale
No utils/helpers/common filesEvery function belongs in a domain module
No catch-all directoriesName for what it does (google/, scheduling/), not what it is
Max ~400 lines per fileSplit by responsibility when approaching the limit
No duplicate logic across modulesIf 3 modules share a pattern, extract it
One logging systemlogging.getLogger(__name__) for library code, print() only in CLI commands

Dependencies

Key runtime dependencies (from pyproject.toml):
PackagePurpose
discord.pyDiscord bot framework
claude-agent-sdkClaude Agent SDK for persistent AI sessions
google-api-python-clientGoogle API access (Tasks, Calendar, Gmail)
google-auth-oauthlibGoogle OAuth2 flow
apschedulerCron-based scheduling for routines and reminders
python-dotenv.env file loading
pyyamlYAML frontmatter parsing
aiohttpWebhook HTTP server
jsonschemaWebhook payload validation
Key dev dependencies:
PackagePurpose
ruffLinting and formatting
tyType checking
pre-commitGit hooks for automated lint/format/type checks
pytestTest framework
pytest-asyncioAsync test support
pytest-covCoverage reporting

Data directory

All persistent state lives in ~/.ollim-bot/. If this directory is a git repository, storage.py auto-commits on writes to routines, reminders, and other managed files. See Data directory for the full layout.

Next steps