Contributing to Precursor
Thanks for your interest in improving Precursor. The project is small and opinionated — issues and small, focused PRs are the easiest way to land changes.
Getting set up
Precursor uses uv for the Python toolchain (env, run, build, release). Install it once, then:
make sync # uv sync + npm --prefix frontend install
cp .env.example .envWithout make
uv sync
cp .env.example .env
cd frontend && npm install && cd ..Run the dev stack (uvicorn --reload + Vite HMR, both stop on Ctrl-C):
make dev
# or: uv run --extra agents precursor --dev (drop --extra agents to skip Agents mode)See the installation guide for all the launch options.
Quality gates
Before opening a PR, run the full gate set (it mirrors CI):
make checkIndividual commands
uv run ruff check .
uv run ruff format --check .
uv run mypy precursor
uv run pytest
npm --prefix frontend run typecheck
npm --prefix frontend run buildAll of these run in CI (.github/workflows/ci.yml) on every PR and must pass.
Code style
- Python — ruff config in
pyproject.toml(line length 100, target 3.12). Type-annotate public surfaces; rely onfrom __future__ import annotations. - TypeScript — strict mode is on. Prefer named exports and function components only. Tailwind classes for styling; CSS variables for theme tokens (
frontend/src/index.css). - Comments — only where the why isn't obvious. The codebase favors small, self-explanatory units over heavy docstrings.
When you change the API
Update both the Pydantic schema and the TS
types.tsfor any API change — they mirror each other.When models change, generate a migration and review it:
bashmake migration m="add foo to chats" # Alembic autogenerate # review the new file under precursor/backend/alembic/versions/, then commit it make migrate # (optional) apply it to your local DB nowAlembic is the single source of truth —
init_dbrunsalembic upgrade headon startup, so a fresh DB is built from migrations and an existing one is migrated in place. Keep one migration per change.Keep the
[Unreleased]section ofCHANGELOG.mdup to date when the change is user-facing.
What not to do
- Don't add new top-level dependencies without flagging it in the PR.
- Don't introduce a Node.js runtime requirement in production — the SPA must be pre-built and served by FastAPI.
- Don't echo secret values (API tokens) in API responses — use the
*_presentboolean pattern. - Don't hardcode the version anywhere — it's CalVer from git tags via hatch-vcs.
- Don't add unrelated refactors to a feature PR.
- Don't grow core to host a single use case — write a plugin instead.
Next
- Development workflow — branches, commits, and PRs.
- Releasing — how a version ships.