Code style
These are preferences that keep the codebase consistent. None of them will block a PR on their own. If you have a reason to deviate, deviate — just say so in the PR description.
Python
- Python 3.12+ is the floor, so modern syntax is fine.
- Type annotations are nice to have where they help — especially on public APIs and anything that crosses a module boundary.
pathlib.Pathreads better than raw string paths.pydanticmodels for JSON shapes save a lot of guard code.httpxoverrequestsfor async paths (there’s already anhttpx.AsyncClientin the runtime).- Short functions are easier to read than long ones; nothing magic about 40 lines.
- Use
loggingoverprintso log filters can see your output.
Comments
Write them when they help. Default to none. If the code is clear, a comment is noise. If a constant has a non-obvious source or there’s a workaround for a specific bug, say so in a line of comment.
Templates and HTML
- Server-rendered Jinja under
pixie/templates/. Tailwind utility classes already in use. - Sentence case for buttons and labels.
- One partial per input/output type — keeps the renderer dispatch trivial.
JavaScript
- Vanilla JS, hung off
window.Pixie. No bundler. - Use
Pixie.initOnSwap(fn)for anything that needs to bootstrap on initial load and after htmx swaps. - Charts:
Pixie.makeChart(el, data, layout)so theme switching works. - Maps:
Pixie.makeMap(el, opts)so base layers stay consistent.
SQL
- Migrations are
ALTER TABLEvia_safe_alter()so re-running is a no-op. - Explicit indexes — don’t rely on SQLite to guess.
- WAL mode is on by default; the connection helper sets it.
Tests
pytest.- Test names describe behaviour, not implementation.
- Fixtures live in
tests/conftest.py. - Heavy tests get a marker (
perf,visual,a11y,e2e) so they skip by default.
Spelling
The codebase mostly uses British English in user-facing strings (“colour”, “behaviour”, “centre”). Stick with that for consistency in new strings, but it’s not worth a PR to flip “color” → “colour” on existing code.
Commit messages
Conventional-commit-ish, informal. The shape:
feat(area): add the thingfix(area): handle the edge casedocs(area): clarify the thingrefactor(area): move things aroundtest(area): cover the thingPR title in the same shape. Squash-merge keeps history tidy.
When in doubt
Look at the code around the spot you’re editing and follow that. Style consistency in any one file matters more than global rules.