Contributing workflow
Use the same Poetry-based commands locally that CI runs on pull requests. The goal is to keep the repository readable after the collapsed-file cleanup and to catch formatting, lint, test, docs, and eval regressions before review.
Public installs vs. development installs
End users should install released OTerminus packages from PyPI, preferably with
pipx install oterminus so the CLI is isolated from the system Python environment. If pipx is
unavailable, the user-facing fallback is python -m pip install oterminus. Keep these public
install instructions in README and the user guide aligned with actual package metadata and CLI
behavior.
Contributors working from a source checkout should use Poetry instead of a public PyPI install.
Set up development dependencies
poetry install --with dev
Formatting and linting
Ruff is the Python formatter and linter for OTerminus. Do not add Black or another overlapping tool for normal Python formatting or lint enforcement.
Format Python code before opening a PR:
poetry run ruff format .
Verify formatting without changing files:
poetry run ruff format --check .
Run lint checks across the repository:
poetry run ruff check .
Keep non-Python source readable too:
- Markdown should use normal headings, blank lines, lists, and valid fenced code blocks.
- YAML and TOML should stay expanded and reviewable, not collapsed into one-line files.
- Avoid mixing large formatting-only rewrites with feature or behavior changes; split them into a separate PR when practical.
Tests and evals
Run the unit test suite locally:
poetry run pytest
CI reports package coverage with:
poetry run pytest --cov=src/oterminus --cov-report=term-missing
Run deterministic eval fixtures when command support, router/planner behavior, validator/policy behavior, direct-command detection, ambiguity behavior, or structured rendering changes:
poetry run oterminus-evals
poetry run oterminus-evals --fixtures-dir evals/cases
Eval fixtures are JSON arrays organized by capability or behavior under evals/cases/, with a
packaged mirror under src/oterminus/eval_fixtures/. Keep fixture IDs unique across all files and
prefer readable capability or behavior prefixes such as network-, project-health-, direct-,
release-, planner-, or ambiguity-. New command-pack work should include representative eval
coverage for accepted behavior plus focused unsafe, unsupported, and ambiguous cases. Use
release_smoke.json only for cross-cutting public-install or first-use flows such as direct command
entry, deterministic shortcuts, ambiguity blocking, dry-run/explain preview behavior, or a
minimal planner-fixture path. Keep capability-specific behavior in its capability file, and cover
oterminus --version, oterminus version, and oterminus doctor with CLI tests because the eval
harness does not execute console-script commands.
Use planner_proposal for natural-language planner-path cases so the eval remains deterministic.
These local test and eval commands should not require an Ollama service, live network access, a real
Git repository state, filesystem contents, a real installed wheel, or subprocess execution. CI uses
the same deterministic fixture path, so no Ollama service/model/network call is required for the
regression gate. See Evals for fixture organization and format details.
Do not add natural-language phrase variants as deterministic shortcut fixtures. Direct-command evals
cover local command detection, deterministic-shortcut evals cover only the retained fixed utility
shortcuts, and flexible natural-language behavior should be represented with mocked
planner_proposal payloads.
For contributor-created candidate files, validate the sanitized JSON before moving it into
evals/cases/:
poetry run oterminus-evals --validate-file path/to/candidate.json
poetry run oterminus-evals --validate-file path/to/candidate.json --run
The first command checks JSON shape, EvalCase schema, non-empty content, and duplicate IDs within
the candidate file. The --run form additionally runs deterministic evaluation for that candidate
file only. Candidate files can live outside evals/cases/; neither mode calls Ollama or executes
shell commands.
Dogfooding findings
Use the Dogfooding playbook before turning real unsupported or surprising requests into issues, eval fixtures, docs examples, planner/schema follow-ups, command-spec changes, or bug reports. Dogfooding notes should capture the request pattern and expected behavior, not private logs, file contents, audit records, history files, hostnames, tokens, or project details. Do not add deterministic shortcuts for broad natural-language phrase coverage. Flexible language should be handled through planner prompts, schema-constrained outputs, diagnostics, and mocked planner eval fixtures; the shortcut layer is limited to retained fixed utility requests. Do not add broad regex coverage, argument extraction, or shortcut recipes to work around model schema failures. A new deterministic shortcut needs strong justification: tiny, stable, low-ambiguity, read-only, and no path, count, search-term, manual-page topic, process-name, Git, project-health, or other argument interpretation.
CI coverage
The main CI workflow keeps Ubuntu as the full regression gate. It runs the complete pytest suite,
Ruff lint and format checks, deterministic evals, generated command-reference checks, docs link
checks, a strict MkDocs build, and scripts/validate_package_install.py.
CI also runs a separate macOS Python 3.13 platform smoke lane. That job is intentionally narrower: it exercises platform-aware command registry behavior, direct-command detection, validator behavior, shell completion/config tests, Ruff linting, and installed CLI smoke validation on a real macOS runner. The macOS smoke lane does not require Ollama, local models, or natural-language planning, and it does not publish packages or run release workflows.
Documentation rules
Update /docs in the same PR when you change behavior, architecture, command support,
configuration, policy, validation, evals, or user-facing behavior. Documentation is part of the
change, not follow-up work.
Keep documentation organized this way:
- Keep
README.mdas the landing page and quick orientation. - Put detailed product, architecture, reference, eval, and contributor material under
website/docs/. - Update
website/sidebars.tswhen adding, moving, or deleting docs pages. - Keep public install docs aligned with PyPI/pipx behavior, development docs aligned with Poetry, and release/package-validation docs aligned with the package validation script.
- Update the root
CHANGELOG.mdfor user-facing changes. - Release PRs must update
pyproject.tomlandCHANGELOG.mdtogether. - Do not include secrets, real tokens, real audit logs, persisted history files, or personal local paths in docs or fixtures.
- When audit, history, failure-explanation, output, install behavior, packaging metadata, or env privacy behavior changes, update the relevant docs in the same PR.
Validate docs before review:
poetry run python scripts/check_docs_links.py
poetry run python scripts/generate_command_reference.py --check
cd website
npm ci
npm run build
npm run typecheck
The CI workflow validates the Docusaurus site and Docusaurus docs links. The docs
workflow deploys the Docusaurus website/build artifact only after a push to main or a manual
workflow dispatch. Confirm the repository Pages setting is Settings → Pages → Build and
deployment → Source → GitHub Actions.
Pre-PR quality commands
Run the checks that match your change before opening a PR:
poetry run ruff format .
poetry run ruff format --check .
poetry run ruff check .
poetry run pytest
poetry run pytest --cov=src/oterminus --cov-report=term-missing
poetry run python scripts/check_docs_links.py
poetry run python scripts/generate_command_reference.py --check
cd website
npm ci
npm run build
npm run typecheck
poetry run oterminus-evals
poetry run python scripts/validate_package_install.py
Local package build + wheel install validation
Validate local artifacts before publishing or changing packaging behavior. This script is for release/development validation, not the primary user install path:
poetry run python scripts/validate_package_install.py
The script will:
- remove stale local
dist/artifacts, then buildsdistandwheelwithpoetry build - create a temporary virtual environment
- install the local wheel
- verify
import oterminus - run CLI smoke checks:
oterminus --help,oterminus --version,oterminus version,oterminus doctor, config path/init/get/set/validate/show against a temporary config path,oterminus completion zsh,oterminus completion bash,oterminus completion fish, andoterminus-evals
Notes:
oterminus doctormay exit non-zero or report Ollama readiness issues in clean or CI environments; this does not block packaging validation because the script still confirms CLI installability.oterminus-evalsuses packaged fixture data fromsrc/oterminus/eval_fixtures/so it works after wheel install.- CI and the production PyPI workflow run the same package validation command before the production publish boundary.
- Publishing to TestPyPI and production PyPI is documented in
website/docs/release.mdand uses GitHub OIDC Trusted Publishing with protected deployment environments. The TestPyPI workflow still verifies the exact published version by installing it back from TestPyPI after publish. - End-user installs should use
pipx install oterminusafter PyPI release; contributors should not add install-time or runtime behavior that automatically edits user shell startup files for completion.
Pull request template and checklist
Every pull request should use .github/pull_request_template.md and keep every checklist item in
place. If an item is not applicable, mark it as N/A in the PR description instead of deleting it.
In addition to formatting, lint, test, docs, and eval checks, the PR template requires explicit confirmation that core architecture invariants still hold for behavior-affecting changes (for example capability-first command support, structured-first behavior, ambiguity gates, validator and policy separation, and local-only audit logging expectations).
When command registry/spec files change, refresh generated command reference docs in the same PR. When behavior, architecture, command support, config, evals, policy, validation, or user-facing behavior changes, docs updates are mandatory in the same PR (not follow-up work).