TOOLS
Type
External
Status
Published
Created
May 7, 2026
Updated
May 14, 2026
Updated by
Dosu Bot
Source
View

TOOLS.md -- Overdue Developer & Agent Tooling Reference#

This document catalogs every tool, command, and script available for developing, testing, deploying, and operating the Overdue application. It is designed for both human contributors and AI agents.

CLI (overdue)#

The Overdue CLI is built with Typer and registered as a console script via pyproject.toml. Install with pip install -e . to get the overdue command.

Top-Level Commands#

CommandDescription
overdue versionPrint the current version (0.1.0a1)
overdue serveStart the FastAPI server via uvicorn

overdue serve options:

FlagDefaultDescription
--host0.0.0.0Bind address
--port8000Bind port
--reloadfalseEnable auto-reload for development

Subcommand Groups#

overdue auth -- Librarian management#

CommandDescription
overdue auth createCreate a new librarian account
overdue auth removeRemove a librarian account

overdue shelves -- Shelf management#

CommandDescription
overdue shelves listList all shelves
overdue shelves createCreate a new shelf

overdue volumes -- Volume management#

CommandDescription
overdue volumes listList all volumes
overdue volumes createCreate a new volume

overdue bots -- AI bot player management#

CommandDescription
overdue bots addAdd bot librarians (casual, diligent, obsessive)
overdue bots simulateRun a round of simulated bot activity
overdue bots removeRemove all bot librarians and their data

overdue seed -- Demo data#

CommandDescription
overdue seed demoSeed the database with demo shelves, volumes, and bots

overdue stats -- Statistics#

CommandDescription
overdue statsDisplay library statistics (librarians, volumes, shelves, XP)

Scripts#

scripts/build_icons.py#

Pre-renders all pixel art icons and avatars as static SVG files to static/icons/.

python scripts/build_icons.py

What it does:

  • Renders all 26 base icons as bare SVGs (no width/height/class attributes)
  • Generates tinted variants for icons used in templates:
    • {name}--green.svg for: checkmark, play
    • {name}--gold.svg for: book-open, books, chart, crown, fire, gamepad, house, award
    • {name}--flame.svg for: fire
  • Renders all 8 avatar SVGs (avatar_01.svg through avatar_08.svg)
  • Prunes stale tinted SVG files no longer referenced by templates
  • Reports count of written and pruned files

When to run: After any change to icon pixel maps (src/game/icons/_*.py), avatar definitions (src/game/avatars.py), or tint configuration.

CSS Build (Tailwind)#

Overdue uses Tailwind CSS with a custom configuration. The built output lives at static/css/tailwind.css.

# One-time build
npm run css:build

# Watch mode (auto-rebuild on template changes)
npm run css:watch

When to run: After adding or removing Tailwind utility classes in any template file.

Development Tools#

Testing#

# Run the full test suite
pytest

# Run with coverage
pytest --cov=src

# Run a specific test file
pytest tests/test_icons.py

Test configuration is in pyproject.toml under [tool.pytest.ini_options]:

  • asyncio_mode = "auto" -- async tests run without explicit markers
  • testpaths = ["tests"]

Linting & Formatting#

# Lint (errors, style, imports, naming, upgrades)
ruff check src/

# Auto-fix lint issues
ruff check src/ --fix

# Format code
ruff format src/

# Full quality check
pytest && ruff check src/

Ruff configuration (pyproject.toml):

  • Target: Python 3.12
  • Line length: 100
  • Rules: E (pycodestyle errors), F (pyflakes), I (isort), N (naming), W (warnings), UP (pyupgrade)

Type Checking#

mypy src/

Configuration: strict mode, Python 3.12 target.

REST API Endpoints#

All API routes are mounted under /api/. Authentication uses JWT bearer tokens (library cards).

Librarians (/api/librarians)#

MethodPathAuthDescription
POST/api/librarians/registerNoneRegister a new librarian
POST/api/librarians/loginNoneAuthenticate and receive a library card (JWT)
POST/api/librarians/refreshBearerRefresh an expiring library card
GET/api/librarians/leaderboardNoneTop librarians ranked by pages read

Volumes (/api/volumes)#

MethodPathAuthDescription
GET/api/volumesBearerList volumes (filterable)
POST/api/volumesBearerCreate a new volume
GET/api/volumes/{id}BearerGet a single volume
PATCH/api/volumes/{id}BearerUpdate a volume
DELETE/api/volumes/{id}BearerDelete a volume
POST/api/volumes/{id}/reviewBearerReview a volume (triggers game engine)

Shelves (/api/shelves)#

MethodPathAuthDescription
GET/api/shelvesBearerList all shelves
POST/api/shelvesBearerCreate a new shelf
GET/api/shelves/{id}BearerGet a shelf with its volumes
DELETE/api/shelves/{id}BearerDelete a shelf

Catalog (/api/catalog)#

MethodPathAuthDescription
GET/api/catalog/autocompleteBearerQuick autocomplete suggestions

Reading Room (/api/reading-room)#

MethodPathAuthDescription
GET/api/reading-room/healthNoneLibrary health snapshot (used by Docker healthcheck)
GET/api/reading-room/overdueBearerReport of overdue volumes

Bulletins (/api/bulletins)#

MethodPathAuthDescription
GET/api/bulletinsBearerList webhook subscriptions
POST/api/bulletinsBearerCreate a webhook subscription
DELETE/api/bulletins/{id}BearerRemove a webhook subscription

Web Routes#

Web routes serve HTML pages via Jinja2 templates. Authentication uses session cookies.

PathMethodDescription
/GETReading room dashboard
/loginGET, POSTLogin page and form handler
/registerGET, POSTRegistration page and form handler
/logoutGETLog out and clear session
/shelvesGETBrowse all shelves
/shelves/createGET, POSTCreate a new shelf
/shelves/{id}GETView a shelf and its volumes
/volumes/{id}GETView a volume with review action
/volumes/createGET, POSTCreate a new volume
/my-libraryGETPersonal library view
/profile/{id}GETLibrarian profile page
/settingsGETLibrary card editor
/settings/cardPOSTSave library card changes (username, email, role, avatar)
/settings/avatarPOSTLegacy avatar update route (redirects to /settings/card)
/leaderboardGETLeaderboard page
/how-to-playGETHow to play guide

Keyboard Shortcuts#

PageKeyAction
Volume detail (/volumes/{id})EnterReview / next volume / done (priority order)
Volume detail (/volumes/{id})Escape / ArrowLeftBack to shelf
Volume detail (/volumes/{id})ArrowRightNext volume
Shelf detail (/shelves/{id})EnterOpen the most overdue volume for review
Shelf detail (/shelves/{id})Escape / ArrowLeftBack to shelves list

Docker#

Build and Run#

# Build and start
docker compose up --build

# Run in background
docker compose up -d

# Stop
docker compose down

Environment Variables (docker-compose.yml)#

VariableDefaultDescription
OVERDUE_PORT8000Host port mapping
OVERDUE_SECRET_KEYchange-me-in-productionJWT signing secret
OVERDUE_DATABASE_URLsqlite+aiosqlite:////app/data/overdue.dbDatabase path inside container
OVERDUE_DEBUGfalseDebug mode

Container Details#

  • Base image: python:3.12-slim
  • User: librarian (non-root)
  • Data volume: overdue-data mounted at /app/data/
  • Healthcheck: GET /api/reading-room/health every 30 seconds
  • Restart policy: unless-stopped

Dependencies#

Runtime (from pyproject.toml)#

PackagePurpose
fastapiWeb framework
uvicorn[standard]ASGI server
sqlalchemy[asyncio]ORM with async support
aiosqliteAsync SQLite driver
pydantic[email]Data validation
pydantic-settingsSettings from environment variables
PyJWTJWT library card encoding/decoding
passlib[bcrypt]Password hashing
bcryptbcrypt backend
typerCLI framework
richCLI output formatting
jinja2Template engine
python-multipartForm data parsing
httpxAsync HTTP client (webhooks)
itsdangerousSession cookie signing

Development#

PackagePurpose
pytestTest runner
pytest-asyncioAsync test support
pytest-covCoverage reporting
ruffLinter and formatter
mypyStatic type checker
PyYAMLYAML parsing (freshness script)
tree-sitterAST parsing framework (freshness script)
tree-sitter-typescriptTypeScript grammar for tree-sitter

Install dev dependencies: pip install -e ".[dev]"

Automation & CI#

Documentation Freshness (.github/scripts/freshness.py)#

Scores each documentation page by comparing its freshness.sources references against symbols actually present in the source files and checking how recently the doc was edited.

How it works:

  • Reads frontmatter from each .md file in the repository
  • Extracts symbol references from the document body (functions, classes, types mentioned in inline code or code blocks)
  • Compares those references against live symbols extracted from the declared source files
  • Applies penalties for: age (time since last edit), missing source files, and unrecognized references
  • Emits a JSON report and fails the CI check if any page scores below 80

Multi-language symbol extraction:

  • Python (.py): Regex-based extraction of top-level def, async def, and class names
  • TypeScript (.ts, .mts, .cts): Tree-sitter AST parsing for functions, classes, methods, interfaces, and type aliases
  • Unknown extensions: Contribute nothing to the live symbol set — pages behave as if the source had no definitions until an extractor is added

The tree-sitter grammar and query compile lazily on first TypeScript file encountered, so Python-only repos pay no import cost. Requires tree-sitter>=0.24 and tree-sitter-typescript>=0.23 (both in the dev extra).

Bootstrap mode: --bootstrap (or FRESHNESS_BOOTSTRAP=1) skips the drift signal for pages that don't yet declare a freshness.sources block, so day-one adopters aren't penalized for unmapped pages. Age and TTL still apply.

Dependabot (.github/dependabot.yml)#

Automated dependency updates configured for:

  • pip (uv): Weekly updates, prefix chore(deps):, minor/patch grouped as uv-minor-patch
  • npm: Weekly updates, prefix chore(deps):, minor/patch grouped as npm-minor-patch
  • docker: Weekly updates, prefix chore(deps):, minor/patch grouped as docker-minor-patch
  • github-actions: Weekly updates, prefix chore(deps):, minor/patch grouped as github-actions-minor-patch

Minor and patch version updates are grouped by ecosystem to reduce PR noise; major updates remain as individual PRs for careful review.

Jinja2 Template Globals & Filters#

Registered in src/web/templates.py and available in all templates:

Globals#

NameSignatureDescription
render_avatar(avatar_id: str, size: int = 32) -> MarkupRender a monster librarian avatar as inline SVG
render_icon(name: str, size: int = 16, color: str | None = None) -> MarkupRender a pixel art icon (static <img> or inline SVG for custom tints)

Filters#

NameSignatureDescription
title_hash(title: str) -> intDerive a stable integer from a string (used for visual variation)

Key Internal APIs#

Game Engine (src/game/engine.py)#

The central game action processor. Call it from routes after a librarian action:

from src.game.engine import process_review

result = await process_review(session, librarian_id, volume_id)
# result = {"xp_gained": 10, "badges_earned": [...], "streak": 5, ...}

Icon Rendering (src/game/icons)#

from src.game.icons import render_icon_svg, render_icon_svg_bare, get_icon_names

# Full SVG with width/height/class (for inline use)
svg_html = render_icon_svg("star", size=16)

# Bare SVG without attributes (for static files)
svg_bare = render_icon_svg_bare("star")

# List all registered icon names
names = get_icon_names() # ["books", "star", "award", ...]

Avatar Rendering (src/game/avatars.py)#

from src.game.avatars import render_avatar_svg, render_avatar_svg_bare, AVATAR_CATALOG, get_avatar_choices

# Full SVG with size attributes
svg_html = render_avatar_svg("avatar_01", size=32)

# Bare SVG for static files
svg_bare = render_avatar_svg_bare("avatar_01")

# Catalog of all avatars (dict keyed by avatar_id)
catalog = AVATAR_CATALOG

# List of avatar choices with id and display name (for forms)
choices = get_avatar_choices() # [{"id": "avatar_01", "name": "..."}, ...]

Auth Helpers (src/auth/library_card.py)#

from src.auth.library_card import create_library_card, verify_library_card

# Issue a JWT
token = create_library_card(librarian_id=1, username="archie", role="Librarian")

# Verify (used as FastAPI dependency)
# payload = verify_library_card(credentials)

Settings (src/config/settings.py)#

from src.config.settings import settings

settings.secret_key # Raw secret from env
settings.signing_secret_key # HMAC-safe key (>= 32 bytes, cached)
settings.database_url # Database connection string
settings.token_expiry_minutes # JWT lifetime