an ai chatbot that recommends books via SMS and discord messages. powered by claude ai.
marty is a burnt-out wizard who used to do software engineering and now works at dungeon books. he's genuinely magical but completely casual about it.
- chat with customers about books via SMS and Discord
- give book recommendations using claude ai with tool calling
- remember conversation history
- integrate with hardcover api for book data
- handle customer info and orders (eventually)
- send responses that sound like a real person texting
mention @marty to chat in a thread
rich embeds via /book, !book, or chatting about a book
recent releases via /recent
- python 3.13
- fastapi with async support
- hypercorn asgi server (dual-stack ipv4/ipv6)
- claude ai for conversations
- postgresql with sqlalchemy
- hardcover api for book data
- pytest for testing
- ruff for code quality
- ty for type checking
- uv for dependency management
- just for command running
- python 3.13
- uv (for dependency management)
- just (for command running)
- postgresql database (supabase recommended)
- redis server (for rate limiting and caching)
- anthropic api key
- hardcover api token
- sinch sms api credentials
# install uv if not already installed
curl -LsSf https://astral.sh/uv/install.sh | sh
# install just command runner
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to ~/bin
# install GNU parallel (required for CI and fast local checks)
# Debian/Ubuntu:
sudo apt-get update && sudo apt-get install -y parallel
# macOS (with Homebrew):
brew install parallel
# clone repository
git clone <repository-url>
cd marty
# complete project setup
just setupcp .env.example .env
# edit .env with your actual credentialsrequired environment variables:
DATABASE_URL=postgresql+asyncpg://user:password@host:5432/dbname
ANTHROPIC_API_KEY=your_claude_api_key_here
HARDCOVER_API_TOKEN=Bearer your_hardcover_token_here
SINCH_API_TOKEN=your_sinch_api_token
SINCH_SERVICE_PLAN_ID=your_service_plan_id
SINCH_FROM_NUMBER=your_virtual_phone_number
SINCH_WEBHOOK_SECRET=your_webhook_secret
REDIS_URL=redis://localhost:6379/0
production (supabase):
# apply migrations
alembic upgrade headlocal development (sqlite):
# set sqlite in .env
DATABASE_URL=sqlite+aiosqlite:///./marty.db
# apply migrations
alembic upgrade head# test database connection
python src/database.py
# comprehensive integration test (⚠️ makes real API calls - costs money)
uv run python scripts/smoke_test.pyDevelopment server with hot reload:
uv run fastapi dev src/main.pyProduction server:
uv run python src/main.pyserver runs on http://localhost:8000 with dual-stack ipv4/ipv6 binding
GET /health
returns database connectivity and system status
POST /webhook/sms
request:
{
"From": "+1234567890",
"Text": "looking for a good fantasy book",
"MessageUUID": "unique-id"
}response:
{
"status": "received",
"message_id": "uuid"
}POST /chat
request:
{
"message": "looking for a good fantasy book",
"phone": "+1234567890"
}response:
{
"response": "try the name of the wind by rothfuss, really solid fantasy. good worldbuilding and the magic system is interesting",
"conversation_id": "uuid",
"customer_id": "uuid"
}Interactive Testing (internal use only):
just chatTerminal chat interface for testing AI responses without SMS pipeline.
SMS Testing (
just smsInteractive SMS testing interface for sending real SMS messages and testing webhook processing. Requires Sinch API credentials.
Integration Testing (
# enable real API calls and run smoke test
MARTY_ENABLE_REAL_API_TESTS=1 just smoke-testComprehensive test of all integrations: Claude AI, Hardcover API, and database. Makes real API calls - use sparingly.
Unit Tests (fast, no infrastructure):
# run unit tests only
just ci
# or manually
pytest -m "not integration"Integration Tests (requires infrastructure):
# run all tests including integration
just test-all
# run only integration tests
just test-integrationAdditional Test Commands:
# specific test files
just test-file test_ai_client.py
# with coverage
just test-cov
# verbose output
just test-verboseAI Testing: All Claude AI calls are automatically mocked in tests to prevent costs. Real API calls only happen in smoke tests when MARTY_ENABLE_REAL_API_TESTS=1 is set.
Pre-commit Hooks (recommended):
# install hooks (runs linting, type checking, and unit tests)
just pre-commit-install
# run all pre-commit checks manually
just pre-commit-runManual Code Quality:
# format code
just format
# lint code
just lint
# type check
just check
# run all checks
just check-all# generate migration
just db-revision "description"
# apply migrations
just db-migrate
# rollback
just db-rollback
# reset database
just db-resetAvailable Commands:
# show all available commands
just --list
# fast CI checks (no infrastructure)
just ci
# full CI with integration tests
just ci-full
# watch mode for development
just watchParallelized Checks:
- Lint, type check, and security scan (Bandit) are run in parallel for faster feedback using GNU parallel.
- GNU parallel is required for CI and pre-commit hooks. On Linux, it is auto-installed by pre-commit/CI. On macOS, install it manually with
brew install parallel. - If you see errors like
parallel: command not found, install GNU parallel as above.
Test Infrastructure:
- Docker Compose setup for isolated testing
- PostgreSQL and Redis containers for integration tests
- Automatic infrastructure management with
just test-all - CI-ready with proper test isolation
get api key from console.anthropic.com add to .env as ANTHROPIC_API_KEY
request access at hardcover.app/api add token as HARDCOVER_API_TOKEN=Bearer your_token
- DATABASE_URL: postgresql connection string
- ANTHROPIC_API_KEY: claude ai api key
- HARDCOVER_API_TOKEN: book data api token
- BOOKSHOP_AFFILIATE_ID: optional affiliate links
- SINCH_API_TOKEN: sinch api token for sms sending
- SINCH_SERVICE_PLAN_ID: sinch service plan identifier
- SINCH_FROM_NUMBER: virtual phone number for sending sms
- SINCH_WEBHOOK_SECRET: webhook signature verification
- REDIS_URL: redis connection string for rate limiting
- SMS_RATE_LIMIT: messages per window (default: 5)
- SMS_RATE_LIMIT_WINDOW: rate limit window in seconds (default: 60)
- SMS_RATE_LIMIT_BURST: burst limit per hour (default: 10)
- DEFAULT_PHONE_REGION: default region for phone parsing (default: US)
- DEBUG: true/false
- LOG_LEVEL: INFO/DEBUG
claude ai handles conversation intelligence and book recommendations
postgresql with async sqlalchemy for data persistence alembic for schema migrations
fastapi with async endpoints hypercorn asgi server for production deployment
marty's personality defined in prompts/marty_system_prompt.md and prompts/marty_discord_system_prompt.md casual texting style with wizard references
- customers: phone numbers and basic info
- conversations: message threads with context
- messages: individual texts with direction tracking
- books: catalog from hardcover api
- inventory: stock levels and availability
- orders: purchases and fulfillment
implemented:
- fastapi application with async support
- claude ai integration with conversation history and tool calling
- database layer with migrations
- hardcover api integration
- comprehensive test suite
- terminal chat interface
- sms webhook handler with signature verification
- sms provider integration with multi-message support
- redis-based rate limiting with burst protection
- phone number validation and normalization
- discord bot integration with thread management
in development:
- square api for payments
- purchase flow
- inventory management
# test connection
just test-db
# check environment
echo $DATABASE_URL
# reset database
just db-reset# test integration (⚠️ costs money)
MARTY_ENABLE_REAL_API_TESTS=1 just smoke-test
# check api key
echo $ANTHROPIC_API_KEYIf you see errors about parallel: command not found during CI or local runs, install GNU parallel:
- Debian/Ubuntu:
sudo apt-get update && sudo apt-get install -y parallel - macOS (Homebrew):
brew install parallel
# run unit tests only (fast)
just ci
# verbose output
just test-verbose
# specific test with output
just test-file test_database.py
# check if integration tests need infrastructure
just test-integration# check pre-commit setup
just pre-commit-run
# verify all quality checks pass
just check-all
# full CI pipeline
just ci-full# add to .env
DEBUG=true
LOG_LEVEL=DEBUG- fork repository
- create feature branch
- make changes
- run quality checks:
just check-all - run tests:
just ci - commit (pre-commit hooks run automatically)
- submit pull request
Development Workflow:
- Use
just cifor fast feedback during development - Use
just test-allfor comprehensive testing before commits - Pre-commit hooks enforce code quality automatically
- Health Check:
/healthendpoint monitors database connectivity and migration status - Logs: Railway provides real-time logs in dashboard
- Metrics: Built-in Railway metrics for CPU, memory, and request volume
- Deployment: Railway Project Dashboard
MIT License - see LICENSE file for details.
Copyright (c) 2025 Script Wizards


