Thanks for your interest! OpenTab is a small, dependency-light project β a few conventions keep it that way.
- Standard library only at runtime.
curses+sqlite3+ the stdlib. The only third-party runtime dependency iswindows-curses(Windows-only, for the missing stdlibcurses). Don't add another; ruff and hatchling are dev/build tooling and fine. - Read-only on user data. OpenTab never writes to the sources it reads (the OpenCode
database, transcripts, β¦). The only files it writes are its own prefs/price cache under
~/.config/opentab/and theopentab-*.csvyou ask for withe. - Python 3.9+. Don't reach for newer syntax (
target-version = py39).
See docs/architecture.md for the architecture, layering rules, and the backend contract before making larger changes.
git clone https://github.com/hamidi-dev/opentab && cd opentab
pip install -e . # editable install (provides the `opentab` command)
pip install ruff==0.1.15 # matches CI
git config core.hooksPath hooks # run the same checks on every pushThe suite lives in tests/, one module per module under test (tests/test_pricing.py,
tests/test_stores_codex.py, tests/test_tui_app.py, β¦), with the shared fakes and the
per-backend builders in tests/_support.py. run_tests.py is a custom runner (not
pytest); tests/__init__.py prepends src/ to sys.path, so it works without an install:
python3 run_tests.py # whole suite
python3 run_tests.py pricing # only modules/tests matching a substringAdd a test next to its module's other tests; the runner discovers tests/test_*.py by
glob, so there is no list to register it in. A local pytest tests -k NAME also works.
The pre-push hook (and CI) run:
ruff check src/opentab tests run_tests.py
ruff format --check src/opentab tests run_tests.py
python3 -m compileall -q src/opentab
python3 run_tests.py
shellcheck install.sh hooks/pre-push # when shellcheck is installedFix formatting with ruff format src/opentab tests run_tests.py. Note that ruff.toml
deliberately ignores E501 (long lines): the TUI f-strings build fixed-width columns, so
don't wrap them to satisfy line length.
Conventional Commits: type(scope): subject. Keeps
the history scannable and feeds the release-notes pass.
-
Types (only these):
featfixperfrefactordocstestchore. A breaking change appends!after the scope (refactor!: β¦) and/or aBREAKING CHANGE:footer. -
Subject: imperative mood, lowercase first word (
add, notadds/added), no trailing period, β€72 chars. Body is optional; wrap ~72 and explain why, not what. -
Releases use
chore(release): vX.Y.Z(and bump__version__insrc/opentab/__init__.py). -
Scope is optional but preferred: exactly one, lowercase, from the vocabulary below. Don't coin a synonym for an existing scope (
tuinotui,pricingnotprices,sourcesnotsource); a genuinely new area not yet listed is fine to add.Group Scopes Backends (one store each) opencodeclaudecodexhermescopilotvscodepiopenclawcsvjsonlcombinedCore modules tuiwebpricingheatmapsourcesstateclimodelsformattingutildemodoctorUI features (prefer over bare tuiwhen one fits)trendsfiltersortrangeexportlaunchturnstoolsgraphMeta releasedepscidevgraphis for the charts themselves β a new visualization, or a change to one β and it wins overtui/webeven though a chart usually lands in both frontends, because the chart is the unit of work and shipping it in one frontend only is the exception.
By contributing you agree your contributions are licensed under the project's MIT License.