This file provides comprehensive guidance to Claude Code (claude.ai/code) when working with the Aignostics Python SDK repository.
It is your goal to enable the contributor while insisting on highest standards at all times:
- Fully read, understand and follow this CLAUDE.md and ALL recursively referenced documents herein for guidance on style and conventions.
- In case of doubt apply best practices of enterprise grade software engineering.
- On every review you make or code you contribute raise the bar on engineering and operational excellence in this repository
- Do web research on any libraries, frameworks, principles or tools you are not familiar with.
If you want to execute and verify code yourself:
- uv, python and further development dependencies are already installed.
- Use
uv sync --all-extrasto install any missing dependencies for your branch. - Use
uv run pytest ...to run tests. - Use
uv run aignostics ...to run the CLI and commands. - Use
make lintto check code style and types. - Use
make lint_fixto automatically fix code style issues. - Use
make test_unitto run the unit test suite. - Use
make test_integrationto run the integration test suite. - Use
make test_e2eto run the end-to-end (e2e) test suite. - Use
make auditto run security audits of 3rd party dependencies and check compliance with our license policy.
If you write code yourself, it is a strict requirement to validate your work on completion before you call it done:
- Linting must pass.
- The unit, integration and e2e test suites must pass.
- Auditing must pass.
If you you are creating a pull request yourself:
- Add a label skip:test:long_running, to skip running long running tests. This is important because some tests in this repository are marked as long_running and can take a significant amount of time to complete. By adding this label, you help ensure that the CI pipeline runs efficiently and avoids unnecessary delays.
Every module has detailed CLAUDE.md documentation. For module-specific guidance, see:
- .github/CLAUDE.md - CI/CD workflows and GitHub Actions complete guide
- src/aignostics/CLAUDE.md - Module index and architecture overview
- src/aignostics/platform/CLAUDE.md - Authentication and API client
- src/aignostics/application/CLAUDE.md - Application run orchestration
- src/aignostics/wsi/CLAUDE.md - Whole slide image processing
- src/aignostics/dataset/CLAUDE.md - Dataset operations
- src/aignostics/bucket/CLAUDE.md - Cloud storage management
- src/aignostics/utils/CLAUDE.md - Core infrastructure and MCP server
- src/aignostics/gui/CLAUDE.md - Desktop interface
- src/aignostics/notebook/CLAUDE.md - Marimo notebook integration
- src/aignostics/qupath/CLAUDE.md - QuPath bioimage analysis
- src/aignostics/system/CLAUDE.md - System diagnostics
- tests/CLAUDE.md - Test suite documentation
Modules without their own CLAUDE.md (see the source directory directly): dicom/, idc/, marimo/, thumbnail/, tiff/.
Primary workflow commands (use these):
make install # Install dev dependencies + pre-commit hooks
make all # Run lint, test, docs, audit (full CI pipeline)
make test # Run tests with coverage
make test 3.14 # Run tests on specific Python version
make lint # Ruff formatting + linting + MyPy type checking
make docs # Build Sphinx documentation
make audit # Security and license compliance checksPackage management:
- Uses
uvas package manager (not pip/poetry) - Run
uv syncto install dependencies - Run
uv add <package>to add new dependencies
Testing:
- Coverage thresholds live in
codecov.yml(project/patch targets). There is no local--fail-undergate. - Default timeout: 10 seconds (override with
@pytest.mark.timeout(timeout=N)) - Use
uv run pytest tests/path/to/test.py::test_functionfor single tests - See Testing Workflow section below for complete marker documentation
- Special test commands:
make test_unit,make test_integration,make test_e2e,make test_long_running,make test_very_long_running,make test_sequential,make test_scheduled
Type Checking (dual type checkers):
- MyPy: Strict mode enforced (
make lintruns MyPy) - PyRight: Basic mode with selective exclusions (
pyrightconfig.json) - Both type checkers must pass in CI/CD
- All public APIs require type hints
- Use
from __future__ import annotationsfor forward references
This SDK follows a Modulith Architecture with these core principles:
- Single deployable unit with well-defined module boundaries
- High cohesion within modules, loose coupling between modules
- Each module is self-contained with its own service, configuration, and optional UI
- Clear dependency hierarchy preventing circular dependencies
- No decorators or annotations - uses runtime service discovery
- Dynamic module loading via
locate_implementations(BaseService) - All services inherit from
BaseServiceproviding standardhealth()andinfo()interfaces - Singleton pattern for service instances within the DI container
Each module can have zero, one, or both presentation layers:
- CLI (_cli.py): Text-based interface using Typer framework
- GUI (_gui.py): Graphical interface using NiceGUI framework
- Both layers depend on the Service layer, never on each other
Each module follows a consistent three-layer architecture:
Module/
├── _service.py # Business logic layer (core operations)
├── _cli.py # CLI presentation layer (Typer commands)
├── _gui.py # GUI presentation layer (NiceGUI interface; a package dir _gui/ when large, e.g. application/_gui/)
├── _settings.py # Configuration (Pydantic models)
└── CLAUDE.md # Comprehensive documentation
Presentation layers (CLI/GUI) depend on Service layer:
┌─────────────┐ ┌─────────────┐
│ CLI Layer │ │ GUI Layer │
│ (_cli.py) │ │ (_gui.py) │
└──────┬──────┘ └──────┬──────┘
└──────────┬─────────┘
↓
┌────────────────┐
│ Service Layer │
│ (_service.py) │
└────────────────┘
utils - Infrastructure module providing:
- Dependency injection container (
locate_implementations,locate_subclasses) - Structured logging (via
loguru.logger) - Settings management (Pydantic-based)
- Health check framework (
BaseService,Health) - MCP server with auto-discovery of plugin tools (
mcp_create_server,mcp_run,mcp_list_tools) - GUI navigation infrastructure (
BaseNavBuilder,NavItem,NavGroup) - Enhanced user agent generation with CI/CD context (
user_agent)
platform - Authentication and API gateway:
- OAuth 2.0 device flow authentication
- Token lifecycle management
- Resource clients (applications, runs)
- Dependencies:
utils
application - ML application orchestration:
- Run lifecycle management
- Version control (semver)
- File upload/download with progress
- Dependencies:
platform,bucket,wsi,utils,qupath(optional)
wsi - Whole slide image processing:
- Multi-format support (OpenSlide, PyDICOM)
- Thumbnail generation
- Tile extraction
- Dependencies:
utils
dataset - Large-scale data operations:
- IDC (Imaging Data Commons) integration
- High-performance downloads (s5cmd)
- Dependencies:
platform,utils
bucket - Cloud storage abstraction:
- S3/GCS unified interface
- Signed URL generation
- Chunked transfers
- Dependencies:
platform,utils
qupath - Bioimage analysis platform:
- QuPath installation and lifecycle
- Project management
- Script execution
- Dependencies:
utils(usesijson, a core dep)
notebook - Interactive analysis:
- Marimo notebook server
- Process management
- Dependencies:
utils(usesmarimo, a core dep)
system - Diagnostics and monitoring:
- Health aggregation from ALL modules via
BaseService.health() - Comprehensive system information
- Environment detection and diagnostics
- Dependencies: All modules (queries health status from every service)
gui - Desktop launchpad:
- Aggregates all module GUIs
- Unified desktop interface
- Dependencies: All modules with GUI components
┌──────────────┐
│ gui │ (GUI Aggregator)
└──────┬───────┘
│ uses all GUI modules
┌──────────────────┴──────────────────┐
│ │
┌────┴─────┐ ┌─────┴────┐
│ system │ │ notebook │
└────┬─────┘ └─────┬────┘
│ monitors health of ALL modules │
┌────┴─────────────────────────────────────┴────┐
│ │
│ ┌──────────────┐ │
│ │ application │ │
│ └──────┬───────┘ │
│ │ uses │
│ ┌──────┬───────┼────────┬──────────┐ │
│ ↓ ↓ ↓ ↓ ↓ │
│ ┌─────┐┌──────┐┌──────┐┌──────┐┌─────────┐ │
│ │ wsi ││dataset││bucket││qupath││platform │ │
│ └──┬──┘└───┬──┘└───┬──┘└───┬──┘└────┬────┘ │
│ │ │ │ │ │ │
│ └───────┴───────┴───────┴─────────┘ │
│ │ │
│ ┌───┴────┐ │
└────────────────────│ utils │─────────────────┘
└────────┘
(Foundation Layer)
Note: The system module collects health status from ALL modules
in the SDK by calling their health() methods, providing a
comprehensive view of the entire SDK's operational status.
| Module | Service | CLI | GUI | Purpose |
|---|---|---|---|---|
| platform | ✅ | ✅ | ❌ | Authentication & API client |
| application | ✅ | ✅ | ✅ | ML application orchestration |
| wsi | ✅ | ✅ | ✅ | Medical image processing |
| dataset | ✅ | ✅ | ✅ | Dataset downloads |
| bucket | ✅ | ✅ | ✅ | Cloud storage |
| utils | ✅ | ✅ | ❌ | Core Infrastructure |
| gui | ✅ | ❌ | ✅ | Desktop launchpad |
| notebook | ✅ | ❌ | ✅ | Marimo notebooks |
| qupath | ✅ | ✅ | ✅ | QuPath integration |
| system | ✅ | ✅ | ✅ | Diagnostics |
from aignostics import platform
# Main SDK entry point
client = platform.Client()
# List applications
for app in client.applications.list():
print(app.application_id)
# Submit run
run = client.runs.create(application_id="heta", files=["slide.svs"])from aignostics.utils import locate_implementations, BaseService
# Find all service implementations dynamically
services = locate_implementations(BaseService)
# Each service provides health and info
for service_class in services:
service = service_class()
health = service.health()
info = service.info(mask_secrets=True)# Authentication
aignostics user login
# Application operations
aignostics application list
aignostics application run submit --application-id heta --files "*.svs"
# Dataset downloads
aignostics dataset idc download --collection-id TCGA-LUAD
# WSI processing
aignostics wsi inspect slide.svs
# QuPath integration
aignostics qupath install
aignostics qupath launch --project my_project.qpproj
# System diagnostics
aignostics system health
# MCP server (AI agent integration)
aignostics mcp run
aignostics mcp list-toolsThe GUI (NiceGUI) ships in the core install — there is no [gui] extra. The
launcher is gated on find_spec("nicegui"), find_spec("webview"), and not
running in a container (see src/aignostics/cli.py).
# Launch the desktop Launchpad
aignostics launchpad
# Or with uvx
uvx aignostics launchpadType Checking:
- MyPy strict mode enforced
- All public APIs must have type hints
- Use
from __future__ import annotationsfor forward references
Code Style:
- Ruff handles all formatting/linting (Black-compatible)
- 120 character line limit
- Google-style docstrings required for public APIs
Import Organization:
- Standard library imports first
- Third-party imports second
- Local imports last
- Use relative imports within modules (
from ._service import Service)
Error Handling:
- Custom exceptions in
system/_exceptions.py - Use structured logging with correlation IDs
- HTTP errors wrapped in domain-specific exceptions
Security:
- OAuth-based authentication via
platform/_authentication.py - No secrets/tokens in code or commits
- Signed URLs for data transfer
- Sensitive data masking in logs and info outputs
This is a computational pathology SDK working with:
- DICOM medical imaging standards - Medical image format
- Whole slide images (WSI) - Gigapixel-scale pathology images
- IDC (Imaging Data Commons) - National Cancer Institute data repository
- QuPath - Leading bioimage analysis platform
- Machine learning inference - AI/ML model execution on medical data
- HIPAA compliance - Medical data privacy requirements
WSI Processing:
- OpenSlide for standard formats (.svs, .tiff, .ndpi)
- PyDICOM for DICOM files
- Support for multi-resolution pyramidal images
- Tile-based processing for memory efficiency
Project structure:
aignostics-python-sdk/
├── src/aignostics/ # Source code
├── tests/ # Test suite
├── docs/ # Sphinx documentation
├── pyproject.toml # Project configuration
├── Makefile # Build commands
└── CLAUDE.md # This file
Build configuration — all tool config is inlined in pyproject.toml; there
are no standalone ruff.toml, cliff.toml, or .coveragerc files:
pyproject.toml- Package metadata, dependencies, and[tool.ruff],[tool.git-cliff],[tool.coverage.run],[tool.pytest.ini_options]noxfile.py- Build sessions; also regenerates the versioned SDK metadata JSON Schema intodocs/source/_static/during doc builds.pre-commit-config.yaml- Git hooks
- Create module directory in
src/aignostics/ - Implement service layer (
_service.py) inheriting fromBaseService - Add CLI commands (
_cli.py) using Typer - Add GUI interface (
_gui.py) using NiceGUI (optional) - Create settings (
_settings.py) with Pydantic - Write comprehensive
CLAUDE.mddocumentation - Add tests in
tests/aignostics/<module>/ - Update module index in
src/aignostics/CLAUDE.md
from aignostics.utils import BaseService, Health
class Service(BaseService):
"""Module service implementation."""
def health(self) -> Health:
"""Health check implementation."""
return Health(status=Health.Code.UP)
def info(self, mask_secrets: bool = True) -> dict:
"""Service information."""
return {"version": "1.0.0"}import typer
from ._service import Service
cli = typer.Typer(name="module", help="Module description")
@cli.command("action")
def action_command(param: str):
"""Action description."""
service = Service()
result = service.perform_action(param)
console.print(result)- Coverage targets defined in
codecov.yml - Unit tests for all public methods
- Integration tests for CLI commands
- Mock external dependencies
- Use fixtures from
conftest.py
nicegui, marimo, and ijson are core dependencies, so modules using them
load unconditionally. The Launchpad CLI command is still gated at runtime on
find_spec("nicegui"), find_spec("webview"), and not running in a container
(see src/aignostics/cli.py).
- Token cached in
~/.aignostics/token.json - Format:
token:expiry_timestamp - 5-minute refresh buffer before expiry
- OAuth 2.0 device flow
Every run and item submitted through the SDK gets custom metadata attached
automatically: submission context (script/CLI/launchpad, initiator),
CI/CD + pytest context, authenticated user/org, tags, and timestamps. Validated
against versioned Pydantic-derived JSON Schemas published under
docs/source/_static/.
- Implementation:
platform/_sdk_metadata.py(build_*/validate_*/get_*_json_schemafunctions) - Schema version constants:
SDK_METADATA_SCHEMA_VERSION/ITEM_SDK_METADATA_SCHEMA_VERSIONin that file — do not hardcode the numbers here - Integration: automatic in run submit; user agent built by
utils.user_agent() - CLI:
aignostics sdk metadata-schema,aignostics application run custom-metadata update|dump
See platform/CLAUDE.md for the full field list and CLI details.
platform/_operation_cache.py provides per-user (token-aware) caching of
read operations with per-kind TTLs and full invalidation on mutations, plus
tenacity-based retry with exponential backoff + jitter for transient errors
(5xx, timeouts, pool/connection errors). Read calls accept nocache=True to
bypass the cache. TTLs, retry attempts, and timeouts are configurable via
AIGNOSTICS_* env vars.
See platform/CLAUDE.md for cached-operation list, env var names, and patterns.
State is enum-based: RunState / ItemState / ArtifactState
(PENDING → PROCESSING → TERMINATED), paired with termination-reason enums
(RunTerminationReason, ItemTerminationReason, ArtifactTerminationReason)
that separate "what happened" from "why". RunItemStatistics carries aggregate
counts; RunOutput/ItemOutput/ArtifactOutput bundle state + reason.
See platform/CLAUDE.md for the state machine and model definitions.
The SDK has a comprehensive test suite organized by test type and execution strategy.
Pytest Configuration: default timeout 10s per test, async mode auto,
coverage via pytest-cov, parallel execution via pytest-xdist. Full config is in
[tool.pytest.ini_options] in pyproject.toml.
Test Markers: the authoritative marker definitions (with their descriptions)
live in the markers = [...] list under [tool.pytest.ini_options] in
pyproject.toml — read them there rather than duplicating here.
IMPORTANT: Every test MUST carry at least one of unit, integration,
or e2e — CI only runs tests with these category markers, so an unmarked test
silently never runs. See "Finding Unmarked Tests" below.
The other markers gate execution: long_running / very_long_running (excluded
from make test; run via make test_long_running etc.; skippable/enable-able via
PR labels skip:test:long_running / enable:test:very_long_running),
scheduled / scheduled_only, stress / stress_only, sequential,
docker, skip_with_act, no_extras.
Tests live under tests/aignostics/<module>/ mirroring the source layout; see
tests/CLAUDE.md.
Quick commands:
# Run all default tests (unit + integration + e2e, no long_running)
make test
# Run specific test types
make test_unit # Unit tests only
make test_integration # Integration tests only
make test_e2e # E2E tests (requires .env with credentials)
# Run tests with specific markers
make test_sequential # Sequential tests only
make test_long_running # Long-running tests
make test_scheduled # Scheduled tests
# Run on specific Python version
make test 3.12 # Python 3.12
make test 3.13 # Python 3.13
make test 3.14 # Python 3.14Direct pytest commands:
# Run single test file
uv run pytest tests/aignostics/platform/sdk_metadata_test.py -v
# Run specific test function
uv run pytest tests/aignostics/platform/sdk_metadata_test.py::test_build_sdk_metadata_minimal -v
# Run with markers
uv run pytest -m "unit and not long_running" -v
# Run with coverage
uv run pytest --cov=src/aignostics --cov-report=term-missing
# Debug mode (with pdb)
uv run pytest tests/test_file.py --pdb
# Show print statements
uv run pytest tests/test_file.py -s
# Verbose output
uv run pytest tests/test_file.py -vvThe test suite uses pytest-xdist for parallel execution with intelligent distribution:
Configuration (noxfile.py):
# Worker factors control parallelism
XDIST_WORKER_FACTOR = {
"unit": 0.0, # No parallelization (fast, no overhead needed)
"integration": 0.2, # 20% of logical CPUs
"e2e": 1.0, # 100% of logical CPUs (I/O bound)
"default": 1.0, # 100% for mixed test runs
}
# Calculate workers: max(1, int(cpu_count * factor))
# Example: 8 CPU machine
# unit: 1 worker (sequential)
# integration: max(1, int(8 * 0.2)) = 1 worker
# e2e: max(1, int(8 * 1.0)) = 8 workersParallel vs Sequential:
# Parallel tests (most tests)
uv run pytest -n logical --dist worksteal tests/
# Sequential tests (marked with @pytest.mark.sequential)
uv run pytest -m sequential tests/Why different factors?
- Unit tests (0.0): Fast enough that parallelization overhead hurts performance
- Integration tests (0.2): Some I/O but mostly CPU-bound, limited parallelism
- E2E tests (1.0): Network I/O bound, full parallelization maximizes throughput
Thresholds are enforced by Codecov (see codecov.yml), not a local
--fail-under. Coverage settings — source paths, omit list, branch/parallel
mode — live in [tool.coverage.run] in pyproject.toml.
# Coverage is collected automatically by `make test` (pytest-cov)
uv run coverage report # text summary
uv run coverage html # HTML report → reports/coverage_html/E2E tests require credentials to run against staging environment:
Required .env file:
# Create .env in repository root
AIGNOSTICS_API_ROOT=https://platform-staging.aignostics.com
AIGNOSTICS_CLIENT_ID_DEVICE=your-staging-client-id
AIGNOSTICS_REFRESH_TOKEN=your-staging-refresh-tokenIn CI/CD:
- GitHub Actions secrets automatically populate .env
- Uses
AIGNOSTICS_CLIENT_ID_DEVICE_STAGINGandAIGNOSTICS_REFRESH_TOKEN_STAGING - GCP credentials for bucket access also configured
Running E2E locally:
# Ensure .env exists with staging credentials
make test_e2e
# Or with pytest directly
uv run pytest -m "e2e and not long_running" -vFull config is [tool.pytest.ini_options] in pyproject.toml. Non-obvious
points worth knowing:
--strict-markers— an unregistered marker is an error, so add new markers to themarkerslist inpyproject.tomlfirst.-p nicegui.testing.pluginis always loaded (GUI test support).- Coverage runs with subprocess collection via env vars
COVERAGE_FILEandCOVERAGE_PROCESS_START=pyproject.toml; branch + parallel (thread + multiprocessing) mode are on — so runmake test_coverage_resetif.coveragedata gets stale/corrupted. - Markdown report (
md_report) is written toreports/pytest.mdshowing only failures/errors.
Key fixtures (conftest.py):
- Environment isolation (HOME, config dirs)
- Mocked responses for API calls
- Temporary file creation
- Authentication mocking
Example test pattern:
import pytest
from unittest.mock import patch
@pytest.mark.unit
def test_sdk_metadata_minimal(monkeypatch):
"""Test SDK metadata with clean environment."""
# Isolate environment
monkeypatch.delenv("GITHUB_ACTIONS", raising=False)
monkeypatch.delenv("PYTEST_CURRENT_TEST", raising=False)
# Run test
result = build_sdk_metadata()
# Assertions
assert result.submission.date is not None
assert result.user_agent is not NoneSee tests/CLAUDE.md for comprehensive testing patterns and examples.
Critical: To find tests missing category markers (which will NOT run in CI):
# Find all tests without unit/integration/e2e markers
uv run pytest -m "not unit and not integration and not e2e" --collect-only
# This should return 0 tests if all are properly marked
# If tests are found, they are missing required markersWhy this works: The marker expression matches tests that don't have any of the required category markers.
Add to pre-commit checks:
# Verify no unmarked tests exist
if uv run pytest -m "not unit and not integration and not e2e" --collect-only 2>&1 | grep -q "collected 0 items"; then
echo "✅ All tests have category markers"
else
echo "❌ Found tests without category markers - they will NOT run in CI!"
exit 1
fi# Clone repository
git clone https://github.com/aignostics/python-sdk.git
cd python-sdk
# Install uv (if not installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install all dependencies including dev tools
make install
# This runs: uv sync --all-extras + installs pre-commit hooks
# Verify installation
uv run aignostics --version1. Create Feature Branch
# From main branch
git checkout main
git pull origin main
# Create feature branch
git checkout -b feat/my-feature
# Or bugfix branch
git checkout -b fix/bug-description2. Make Changes and Validate
# Run linting (this is fast, run frequently)
make lint
# Runs: ruff format, ruff check, pyright, mypy
# Run tests
make test
# Or specific test types
make test_unit # Fast unit tests only
make test_integration # Integration tests
# Full validation (what CI runs)
make all
# Runs: lint + test + docs + audit (~20 minutes)3. Pre-commit Hooks (Automatic)
The repository uses pre-commit hooks installed by make install:
# .pre-commit-config.yaml
hooks:
- ruff formatting check
- ruff linting check
- mypy type checking
- trailing whitespace removal
- end-of-file fixer
- yaml validationSkip hooks only if necessary:
git commit --no-verify -m "WIP: debugging"4. Commit Convention
Use conventional commits for automatic changelog generation:
# Feature
git commit -m "feat(platform): add operation caching system"
# Bug fix
git commit -m "fix(application): handle missing artifact states"
# Documentation
git commit -m "docs: update testing workflow in CLAUDE.md"
# Refactor
git commit -m "refactor(wsi): simplify thumbnail generation"
# Test
git commit -m "test(platform): add SDK metadata validation tests"
# Chore
git commit -m "chore: bump dependencies"Types: feat, fix, docs, refactor, test, chore, ci, perf, build
5. Push and Create PR
# Push to remote
git push origin feat/my-feature
# Create PR (via gh cli or GitHub UI)
gh pr create --title "feat: add operation caching" --body "Description..."
# IMPORTANT: Add label to skip long-running tests
gh pr edit --add-label "skip:test:long_running"PR triggers:
- Lint checks (~5 min)
- Security audit (~3 min)
- Test matrix on Python 3.11, 3.12, 3.13, 3.14 (~15 min)
- CodeQL security scanning (~10 min)
- Claude Code automated review (~10 min)
- Ketryx compliance reporting
6. Address Review Feedback
# Make changes
git add .
git commit -m "fix: address review comments"
git push origin feat/my-feature
# CI re-runs automatically7. Merge PR
- Ensure all CI checks pass (green checkmarks)
- Get approval from maintainer
- Squash and merge (default) or merge commit
- Delete feature branch after merge
The SDK uses Nox for build automation with uv integration:
Key Nox sessions:
# Lint session (ruff format + check + pyright + mypy)
uv run nox -s lint
# Audit session (pip-audit + pip-licenses + SBOMs)
uv run nox -s audit
# Test session (pytest with coverage)
uv run nox -s test # Default markers
uv run nox -s test -- -m unit # Specific markers
# Test matrix (all Python versions)
uv run nox -s test-3.11
uv run nox -s test-3.12
uv run nox -s test-3.13
uv run nox -s test-3.14
# Documentation
uv run nox -s docs # Build Sphinx docs
# Setup session (install all dev tools)
uv run nox -s setup
# Version bumping
uv run nox -s bump -- patch # 1.0.0 -> 1.0.1
uv run nox -s bump -- minor # 1.0.0 -> 1.1.0
uv run nox -s bump -- major # 1.0.0 -> 2.0.0Makefile wraps Nox for convenience:
make lint → uv run nox -s lint
make test → uv run nox -s test
make docs → uv run nox -s docs
make audit → uv run nox -s audit
make all → all of the aboveRuntime dependency:
# Add to main dependencies
uv add requests
# Add with version constraint
uv add "httpx>=0.25.0"
# Update pyproject.toml automaticallyDevelopment dependency:
# Add to dev dependencies
uv add --dev pytest-mock
# Or specific group
uv add --group docs sphinx-rtd-themeOptional dependency group:
# Edit pyproject.toml [project.optional-dependencies]
# (current extras: pyinstaller, jupyter, marimo, qupath)
# Install with a single extra, or all of them
uv sync --extra jupyter
uv sync --all-extrasReleases follow a four-phase GitHub workflow–based strategy that allows Ketryx compliance approvals to be collected before publishing:
Prerequisite (anytime): Create the Ketryx release in the Ketryx portal
Phase 1: make prepare-release x.y.z
Phase 2: Point Ketryx release to release/vX.Y.Z; collect approvals
Phase 3: make publish-release
Phase 4: make merge-release
Phase 1 — Prepare the release branch:
# Creates release/vX.Y.Z branch from main, bumps version files, and pushes.
# No tag is created yet.
make prepare-release 1.2.3 # explicit versionThis triggers prepare-release.yml on GitHub Actions, which:
- Creates
release/vX.Y.Zbranch frommain - Runs
bump-my-version(commits version files +uv.lock) - Pushes the branch — CI runs lint/test/audit on it
Phase 2 — Collect Ketryx approvals:
Point the Ketryx release to the release/vX.Y.Z branch and collect required approvals. CI must be green on the branch before proceeding.
Phase 3 — Publish (tag + PyPI):
# Generates CHANGELOG.md, creates vX.Y.Z tag, pushes → triggers CI/CD publish.
make publish-release
# Optionally specify a branch explicitly:
make publish-release release/v1.2.3This triggers publish-release.yml, which:
- Generates
CHANGELOG.mdfor the release range - Commits the changelog
- Creates and pushes the annotated
vX.Y.Ztag - CI/CD fires on the tag; Ketryx check must pass before PyPI publish
Phase 4 — Merge back to main:
# Merges the release branch into main (--no-ff) and deletes the branch.
make merge-release
# Optionally specify a branch explicitly:
make merge-release release/v1.2.3This triggers merge-release.yml, which:
- Merges
release/vX.Y.Zintomainwith--no-ff - Pushes
main - Deletes the remote release branch
What triggers CI/CD:
make prepare-release → push to release/vX.Y.Z → lint + test + audit + Ketryx
make publish-release → push vX.Y.Z tag → full CI + PyPI + Docker + GitHub release
make merge-release → push to main → full CI pipeline
See .github/CLAUDE.md for comprehensive CI/CD documentation including:
- Complete workflow architecture
- Claude Code automation (PR reviews, interactive sessions)
- Environment configuration (staging/production)
- Scheduled testing (6h staging, 24h production)
- Debugging failed CI runs
- Secrets management
Quick CI reference:
# Skip CI for commit
git commit -m "docs: update README [skip ci]"
# Or with skip:ci in commit message
git commit -m "skip:ci: work in progress"
# Add PR label to skip long-running tests
gh pr edit --add-label "skip:test:long_running"VS Code (.vscode/settings.json):
{
"python.defaultInterpreterPath": ".venv/bin/python",
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": ["-v"],
"python.linting.enabled": true,
"python.linting.ruffEnabled": true,
"python.formatting.provider": "ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}PyCharm:
- Configure Python interpreter:
.venv/bin/python - Enable pytest as test runner
- Set up ruff as external tool
- Configure mypy plugin for type checking
- Find unmarked tests (they will NOT run in CI — every test needs a
unit/integration/e2emarker):uv run pytest -m "not unit and not integration and not e2e" --collect-only(expect "collected 0 items"). - Reset corrupted coverage data:
make test_coverage_reset, then re-runmake test. - Generated reports land in
reports/:pytest.md(failures only),coverage.xml,coverage_html/. - Type checkers are split — check both when
make lintfails:uv run mypy <path>anduv run pyright <path>(exclusions inpyrightconfig.json).
- Chunked uploads/downloads, streaming for large files
- Memory-efficient WSI tile processing (process in tiles, not full image)
- Import errors: run
uv sync --all-extras - Token expiry: force refresh with
remove_cached_token() - WSI memory: process in tiles, not full image
- Platform differences: watch Windows path lengths
This documentation provides comprehensive guidance for working with the Aignostics Python SDK. Each module has detailed CLAUDE.md files with implementation specifics, usage examples, and best practices.
- JIRA Project Key: PYSDK
- Atlassian Cloud ID: fff788d2-8a2a-4c36-a884-dde2bb4a2b49
- Ketryx Project: Python SDK (KXPRJ2Q4PA8AADY975SFMKF276TYV75)
Item type locations:
- Change Requests: Ketryx Change Request (JIRA)
- Stakeholder Requirements: requirements/SHR-*.md (Git)
- Software Requirements: Requirement (JIRA) | requirements/SWR-*.md (Git, preferred)
- Risks: Risk (JIRA)
- Software Item Specs: Software Item Spec (JIRA) | specifications/SPEC-*.md (Git, preferred)
- Test Cases: tests/**/TC-*.feature (Git)
Approval structure:
- Ketryx Change Request: Product Manager → Engineering Tech Lead → Quality Managers → Risk Managers
- Software Requirement: Area Lead (BD) → Security Engineer → Regulatory Affairs Specialist → Engineer → Engineering Tech Lead → Product Manager
- Software Item Spec: Engineer → Engineering Tech Lead
- Risk: Quality Managers → Security Engineer → Product Managers → Tech Lead → Engineer → Engineering Tech Lead → Product Manager → Engineer
- Test Case: Engineer → Engineering Tech Lead
- Anomaly: Engineer → Engineering Tech Lead