Contributing to Katana OpenAPI Client¶
Thank you for your interest in contributing to the Katana OpenAPI Client! This document provides guidelines and instructions for contributing.
Development Setup¶
- Clone the repository
- Install uv (if not already installed)
- Install dependencies
- Set up environment variables
Development Workflow¶
Code Quality¶
We maintain high code quality standards. Before submitting changes:
# Format code
uv run poe format
# Check formatting
uv run poe format-check
# Run type checking
uv run poe lint
# Run tests
uv run poe test
Running Tests¶
# Run all tests
uv run poe test
# Run with coverage
uv run poe test-coverage
# Run specific test file
uv run poe test tests/test_katana_client.py
# Run integration tests (requires API credentials)
uv run poe test-integration
Code Style¶
- Ruff for code formatting and linting
- pyright for type checking — canonical, per
pyrightconfig.jsonand the LSP integration. Run viauv run pyright <path>(the LSP can be stale; the CLI is the source of truth). - ty for type checking — secondary fast checker (Astral's
Rust-based). Both run in CI via
uv run poe lint; both must pass. - mdformat for Markdown formatting
All formatting is automated via uv run poe format.
Submitting Changes¶
Pull Request Process¶
- Fork the repository and create a feature branch
Branch names use the same type prefixes as conventional commits (see
COMMIT_STANDARDS) — feat/,
fix/, docs/, chore/, etc. — so the branch name signals the kind of change.
(Note: feat, fix, etc. are the conventional-commit type; the scope is the
package, e.g. (client) or (mcp), applied to the commit message, not the branch
name.)
-
Make your changes following the code style guidelines
-
Add or update tests for your changes
-
Update documentation if needed
-
Run the full test suite
- Commit your changes with a clear commit message using scopes
# For client changes
git commit -m "feat(client): add new domain helper"
# For MCP server changes
git commit -m "feat(mcp): add inventory tool"
- Push to your fork and create a pull request
For the first push of a new branch, use the explicit destination ref so the push
doesn't depend on push.default, upstream-tracking config, or shell habits:
The form HEAD:refs/heads/<name> names both the source (current HEAD) and the
destination ref explicitly, so it's immune to git configs (e.g.
push.default = upstream) that can reroute an under-specified push to whatever the
branch tracks — which, if you created the branch via
git checkout -b <name> origin/main, is main. A pre-push hook
(scripts/pre-push-guard.sh) blocks the specific case where a non-main local ref
would land on refs/heads/main, so the originating incident can't recur — but the
hook doesn't reject every under-specified push, so the explicit refspec is the
contributor-facing rule. Never bypass with --no-verify. Full rationale + the
incident that prompted the rule live in
COMMIT_STANDARDS "First-Push Safety".
Commit Message Format¶
We follow Conventional Commits with scopes for monorepo versioning:
Type + Scope:
feat(client):new features in the client (triggers client release)feat(mcp):new features in MCP server (triggers MCP release)fix(client):bug fixes in the client (triggers client release)fix(mcp):bug fixes in MCP server (triggers MCP release)docs:documentation changes (no release)test:adding or updating tests (no release)chore:maintenance tasks (no release)
Examples:
# Release client package
git commit -m "feat(client): add Products domain helper"
# Release MCP server package
git commit -m "feat(mcp): implement check_inventory tool"
# No release (documentation only)
git commit -m "docs: update README with new examples"
Important: Use the correct scope based on what you're changing:
- Files in
katana_public_api_client/→ use(client)scope - Files in
katana_mcp_server/→ use(mcp)scope - Documentation or CI only → use
docs:orci:(no scope)
See docs/RELEASE.md for complete release documentation
Pull Request Guidelines¶
- Include a clear description of the changes
- Reference any related issues
- Ensure all tests pass
- Update documentation if needed
- Keep the scope focused and atomic
Project Structure¶
The repo is a 3-package monorepo (Python client, MCP server, TypeScript client). The canonical tree lives in the root README.md → Project Structure; see also the linked package READMEs from that section. The structure isn't reproduced here — keeping the tree in two places is exactly the kind of drift-prone hand-maintained reference the rule below forbids.
Architecture Guidelines¶
Core Principles¶
- Transparency: Features should work automatically without configuration
- Resilience: All API calls should handle errors gracefully
- Type Safety: Use comprehensive type annotations
- Performance: Leverage async/await and efficient HTTP handling
- Compatibility: Maintain compatibility with the generated client
Adding New Features¶
When adding features:
- Transport Layer First: Implement core functionality in
ResilientAsyncTransport - Automatic Behavior: Make features work transparently without user configuration
- Comprehensive Testing: Include unit tests, integration tests, and error scenarios
- Documentation: Update relevant documentation and examples
Testing Guidelines¶
Test Categories¶
- Unit Tests: Test individual components in isolation
- Integration Tests: Test real API interactions (marked with
@pytest.mark.integration) - Transport Tests: Test the transport layer behavior directly
Writing Tests¶
- Use descriptive test names that explain the scenario
- Include both success and error cases
- Mock external dependencies appropriately
- Use fixtures for common test setup
Test Environment¶
Integration tests require valid Katana API credentials. Set these in your .env file:
Documentation¶
Updating Documentation¶
- Update relevant
.mdfiles in thedocs/directory - Keep examples current and working
- Update the README.md if adding user-facing features
- Include docstrings for all public methods
No hand-maintained drift-prone references¶
When writing or updating documentation, do not hard-code facts that have a source-of-truth elsewhere. They drift on every release, every spec sync, every refactor, and every closed issue, and nobody can be expected to update both places. Rule of thumb: if a fact in a doc requires updating in two places when something changes, the fact is in the wrong place.
Things that are guaranteed to drift if hand-maintained:
- Package version numbers — use a shields.io PyPI/npm badge instead. The badge fetches the live version at render time.
- Endpoint counts / tool counts / model counts — either remove ("see the OpenAPI
spec for the canonical endpoint surface", "see
katana://help/toolsfor the current tool list") or generate from the source-of-truth via apoetask wired into pre-commit. - Hand-curated ADR lists — link to the per-scope ADR
README.mdindex instead. The indexes are short, easy to keep current, and live next to the ADRs they list. - Issue numbers cited as roadmap markers — link to the project board instead. The board reflects current state; the issue number you cited may close, get renumbered, or scope-creep.
- "Coming soon" / "planned" callouts — either remove (git history is the answer) or link to a specific issue (which the project board can surface).
- Dated "last updated" footers — remove. Git history already records this.
- File paths inside generated trees — point at the parent dir or the spec, not individual files that move on regeneration.
If you find yourself adding such a fact, that's the signal to invert the relationship: link out to where the fact lives instead of duplicating it. PRs that re-introduce hand-maintained drift-prone references will be asked to abstract them.
Client Regeneration¶
The OpenAPI client is automatically generated from katana-openapi.yaml using
openapi-python-client.
Spec Maintenance¶
Before regenerating, audit the local spec against upstream. The full workflow lives in
docs/upstream-specs/README.md
in the repo (kept out of the published docs site since the upstream-spec YAML and audit
reports are maintainer-only artefacts). Quick reference:
uv run poe refresh-upstream-spec # pull cached upstream specs
uv run poe audit-spec # request-side drift vs. live gateway
uv run poe validate-response-examples # response-side drift vs. README.io portal
uv run poe validate-examples # local example/schema consistency
refresh-upstream-spec writes to docs/upstream-specs/ (idempotent — no-op if upstream
hasn't changed); the other three are read-only. Run them whenever you're changing
docs/katana-openapi.yaml or investigating possible upstream drift.
Regeneration Process¶
What Gets Regenerated¶
The canonical list of generated vs preserved paths lives in three places that stay in sync with the actual generators:
- The "Generated Files (DO NOT EDIT)" and "Editable Files (Can Modify)" sections of FILE_ORGANIZATION.md, which describe the boundary in detail.
scripts/regenerate_client.pydecides which attrs files get rewritten — read thegenerated_itemslist insidemove_client_to_workspacefor the exact list.scripts/generate_pydantic_models.pydecides which pydantic files get rewritten (the_generated/subtree and_auto_registry.pyundermodels_pydantic/).
If the docs and either script ever disagree, the script wins.
The high-level rule: anything under api/, models/, client.py, client_types.py,
errors.py, py.typed, __init__.py (rewritten from a flattened-import template every
regen — not preserved despite the inline comment in the script suggesting otherwise),
and models_pydantic/_generated/ (plus _auto_registry.py) is rewritten on every
regen. Everything else under katana_public_api_client/ (including the rest of
models_pydantic/ — hand-maintained pydantic infrastructure) is preserved.
Regeneration Features¶
- 🔄 Flattened Structure: No more
generated/subdirectory - 🛡️ File Preservation: Custom files are never overwritten
- 🔧 Automatic Fixes: Uses
ruff --unsafe-fixesfor code quality - ✅ Dual Validation: Both openapi-spec-validator and Redocly validation
- 🎯 Source-Level Fixes: Issues resolved in OpenAPI spec when possible
Documentation Style¶
- Use clear, concise language
- Include practical examples
- Follow the existing format and style
- Test any code examples to ensure they work
Release Process¶
Releases are fully automated using python-semantic-release. See RELEASE.md for complete documentation.
Quick summary for contributors:
- Use Conventional Commits format
feat:commits trigger minor version bump (0.x.0)fix:commits trigger patch version bump (0.0.x)- Releases happen automatically when PR is merged to
main
Getting Help¶
- Documentation: Check the
docs/directory - Issues: Search existing issues or create a new one
- Discussions: Use GitHub Discussions for questions
Code of Conduct¶
This project follows the Contributor Covenant Code of Conduct. Please read and follow it in all interactions.
Thank you for contributing! 🎉