Skip to content

Latest commit

 

History

History
165 lines (113 loc) · 5.41 KB

File metadata and controls

165 lines (113 loc) · 5.41 KB

Contributing

Clawbolt is open source and contributions are welcome.

Getting started

  1. Fork the repository on GitHub
  2. Clone your fork and set up local development
  3. Create a branch for your changes
  4. Make your changes and ensure all checks pass
  5. Open a pull request

Local setup

For development, you can run Clawbolt directly with Python and uv (no Docker required).

Prerequisites

  • Python 3.11+
  • uv (Python package manager)
  • PostgreSQL (for data storage)

Install dependencies

pip install uv
uv sync

Configure environment

cp .env.example .env

Edit .env with your credentials. At minimum:

  • An LLM API key
  • At least one messaging channel:
    • iMessage: pick one backend. Linq (LINQ_API_TOKEN + LINQ_FROM_NUMBER) for hosted iMessage/RCS/SMS, or BlueBubbles (BLUEBUBBLES_SERVER_URL + BLUEBUBBLES_PASSWORD) for a self-hosted bridge. The app surfaces either as a single "iMessage" channel to users. Configuring both at once is not supported.
    • Telegram: TELEGRAM_BOT_TOKEN and TELEGRAM_ALLOWED_CHAT_ID

Set up PostgreSQL

Create the development database:

createdb -U clawbolt clawbolt

Run migrations:

uv run alembic upgrade head

Start the server

uv run uvicorn backend.app.main:app --reload

The server starts on http://localhost:8000.

File storage in development

File storage is exposed through the Google Drive integration. To exercise the file tools (upload_to_storage, find_saved_files, etc.), set GOOGLE_DRIVE_CLIENT_ID and GOOGLE_DRIVE_CLIENT_SECRET in .env, restart the server, and ask the assistant in chat to "connect google drive" (it calls manage_integration and replies with an OAuth link). Without those env vars, the file tools stay hidden, which is fine for working on anything other than file flows. See Google Drive Setup for the OAuth client walkthrough.

Set up a messaging webhook

Without Docker, you need a tunnel to give messaging providers a public URL:

# Install cloudflared, then:
cloudflared tunnel --url http://localhost:8000

If using the iMessage channel backed by Linq, the webhook registers automatically when the server detects the tunnel URL. If using BlueBubbles as the iMessage backend, configure the webhook on your BlueBubbles server per its setup guide.

If using Telegram, copy the tunnel URL and register the webhook manually:

curl -X POST "https://api.telegram.org/bot<TOKEN>/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://<tunnel-url>/api/webhooks/telegram"}'

See Linq Setup, BlueBubbles Setup, or Telegram Setup for details.

Testing

Clawbolt uses pytest with FastAPI's TestClient. Tests require a running PostgreSQL instance with a clawbolt_test database.

Database setup

Tests connect to postgresql://clawbolt:clawbolt@localhost:5432/clawbolt_test. The conftest handles table creation and per-test transaction rollback automatically.

# Create the test database (one-time setup)
createdb -U clawbolt clawbolt_test

Run all tests

uv sync --all-extras
uv run pytest -v

Test infrastructure

Store isolation: The _isolate_file_stores autouse fixture patches settings.data_dir and calls reset_stores() to clear cached store singletons between tests. Each test runs in a database transaction that is rolled back after the test completes.

Mock factories: All external services are mocked in tests. Mock factories live in tests/mocks/:

Mock What it replaces
Telegram Telegram Bot API calls
LLM any-llm acompletion calls
Storage MockStorageBackend for Google Drive operations

Auth override: The get_current_user dependency is overridden in tests to return a fixed test user, bypassing authentication.

Code standards

  • Type annotations required on all functions
  • Ruff for linting and formatting (rules: E, F, I, UP, B, SIM, ANN, RUF)
  • Line length: 100 characters
  • Pydantic v2 for all data classes and request/response schemas
  • Async routes: all route handlers use async def
  • LLM calls: all LLM calls via any-llm acompletion (async)

Commit messages

Use conventional commit prefixes:

Prefix Use for
feat: New features
fix: Bug fixes
docs: Documentation changes
refactor: Code refactoring
test: Adding or updating tests
ci: CI/CD changes
chore: Maintenance tasks

Definition of done

Every change should pass all checks:

uv run pytest -v                                  # tests pass
uv run ruff check backend/ tests/                 # lint passes
uv run ruff format --check backend/ tests/        # format passes
uv run ty check --python .venv backend/ tests/    # type checking passes
  • Bug fixes include regression tests
  • New features include appropriate tests
  • Documentation is updated if needed

Architecture notes

  • Every data class and endpoint uses user_id scoping
  • External services are abstracted behind service classes in backend/app/services/
  • Config uses Pydantic BaseSettings with extra="ignore"