Metadata-Version: 2.4
Name: hla-compass
Version: 5.9.3
Summary: Python SDK for HLA-Compass bioinformatics platform - Build powerful modules for immuno-peptidomics analysis
Author-email: Alithea Bio <armanas.povilionis@alithea.bio>
License-Expression: MIT
Project-URL: Homepage, https://alithea.bio
Project-URL: Documentation, https://docs.alithea.bio
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Requires-Python: <3.15,>=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Requires-Dist: boto3>=1.26.0
Requires-Dist: click>=8.0.0
Requires-Dist: rich>=12.0.0
Requires-Dist: cryptography>=41.0.0
Requires-Dist: jsonschema>=4.17.0
Requires-Dist: keyring>=25.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: packaging>=23.0
Provides-Extra: dev
Requires-Dist: build>=1.2.0; extra == "dev"
Requires-Dist: pip-tools>=7.0.0; extra == "dev"
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=3.0.0; extra == "dev"
Requires-Dist: pytest-mock>=3.6.0; extra == "dev"
Requires-Dist: pytest-asyncio>=1.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=0.950; extra == "dev"
Requires-Dist: types-requests>=2.28.0; extra == "dev"
Requires-Dist: PyYAML>=6.0.0; extra == "dev"
Requires-Dist: sphinx>=4.0.0; extra == "dev"
Requires-Dist: sphinx-rtd-theme>=1.0.0; extra == "dev"
Provides-Extra: data
Requires-Dist: pandas>=2.2.0; extra == "data"
Requires-Dist: pyarrow>=15.0.0; extra == "data"
Requires-Dist: s3fs>=2026.6.0; extra == "data"
Requires-Dist: xlsxwriter>=3.0.0; extra == "data"
Requires-Dist: polars>=0.20.0; extra == "data"
Provides-Extra: ml
Requires-Dist: scikit-learn>=1.0.0; extra == "ml"
Requires-Dist: torch>=1.10.0; extra == "ml"
Requires-Dist: transformers>=4.20.0; extra == "ml"
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1.28.1; extra == "mcp"
Provides-Extra: authoring
Requires-Dist: mcp<2,>=1.28.1; extra == "authoring"
Requires-Dist: pytest>=7.0.0; extra == "authoring"
Dynamic: license-file

# HLA-Compass Python SDK

[![PyPI version](https://badge.fury.io/py/hla-compass.svg)](https://badge.fury.io/py/hla-compass)
[![Python Versions](https://img.shields.io/pypi/pyversions/hla-compass.svg)](https://pypi.org/project/hla-compass/)

The official Python SDK (Python 3.11–3.14) for developing modules and integrations on the HLA-Compass platform.

Before publishing, choose the default source-upload path or the advanced
custom-image path using the authoritative
[module publishing prerequisite ladder](https://docs.alithea.bio/publishing-prerequisites/).

## 🚀 Quick Start

```bash
# 1. Install the dev/staging candidate; dependencies come from PyPI.
python -m pip download --index-url https://test.pypi.org/simple/ --no-deps --only-binary=:all: --dest sdk-wheel "hla-compass==5.9.3"
python -m pip install "hla-compass[authoring]==5.9.3" --index-url https://pypi.org/simple/ --find-links sdk-wheel

# 2. Authenticate
hla-compass auth login --env dev

# 3. Optionally pin a default organization for publish operations
hla-compass auth use-org 00000000-0000-0000-0000-000000000000 --env dev

# 4. Create
hla-compass init my-module --template no-ui
cd my-module

# 5. Run repository-independent source gates
hla-compass validate --strict
pytest
hla-compass mcp schema

# 6. Run the container gate only when this SDK release has the required
# managed runtime/UI-builder image (see "Release-controlled build images")
hla-compass test --input examples/sample_input.json

# 7. Publish (source-upload — the platform builds the container)
hla-compass publish --env dev --scope org --wait
```

Interactive login uses an ephemeral IP-literal loopback callback, CSRF state, and S256
PKCE. The browser callback contains only a short-lived single-use authorization
code; access and refresh tokens are returned directly to the SDK during the
code exchange and then stored in the operating-system keyring (or the
permission-restricted encrypted fallback). The SDK never accepts a token
payload from the loopback URL.

For unattended publishing, create a publish-only API key in the platform
profile and store it as a CI secret. The SDK automatically selects the
API-key machine route when `HLA_API_KEY` is set:

```bash
export HLA_API_KEY="<publish-only-key>"
hla-compass publish --env dev --scope org --wait
```

Do not reuse a data or MCP key: the platform requires `publish` to be the
key's only permission and binds publication and status access to that key's
organization. The generated GitHub workflow maps its repository publish
secret to the canonical `HLA_API_KEY` variable for the CLI. Every
`hla-compass init` scaffold includes it at `.github/workflows/publish.yml`.
That workflow is self-contained: dev/staging install the exact SDK candidate from
TestPyPI, while prod uses PyPI. Dependencies always come from PyPI; it does not call or check out the private platform
repository. Do not replace it with a reusable workflow pinned to `main`. A
custom-image reusable workflow is not a public release artifact until it is
hosted in an Actions-accessible repository and identified by a reviewed
full-length commit SHA.

For headless module execution, use a separate developer key with `read` and
`write`; add `delete` only if the integration must cancel runs. The SDK selects
the API-key control plane automatically:

```bash
export HLA_API_KEY="<read-write-developer-key>"
```

```python
from hla_compass import APIClient

client = APIClient(environment="dev")
run = client.start_module_run("MODULE_UUID", parameters={"name": "world"}, mode="async")
result = client.wait_for_module_run(run["run_id"])
```

Developer keys use `/v1/api/module-runs`; bearer sessions use
`/v1/module-runs`. Short-lived keys issued to running modules cannot use either
control plane. Publish-only keys cannot execute modules.

### Explicit Module redeployment

Source publishing remains the normal release workflow: `hla-compass publish
--wait` submits governed source intake and the platform deploys the accepted
Module Version automatically.
Managed source intake first performs platform-owned, constrained static AST
and manifest-schema analysis of the bounded source archive without importing
or executing publisher Python. A successful check persists structured
`mcpEntrypointValidation` evidence, bound to the canonical manifest, source
archive, and final image digest, in the content-addressed publication
attestation. The callback and later publication/run-admission checks require
that matching evidence.

The canonical image build separately installs the declared dependency closure,
copies the module source, and repeats SDK `ModuleValidator` entrypoint checks
with network access disabled as the final numeric non-root runtime identity.
That check imports publisher Python and can execute module-level code even
though it does not invoke native MCP callables. Treat it as a cooperative
build-quality smoke test, not a hostile-code sandbox, security boundary, or
the result proved by `mcpEntrypointValidation`. Missing, non-callable, async,
or signature-incompatible declarations still fail the build before push or
registration.

Native MCP is source-only in this release. If `manifest.mcp.tools` is
non-empty, publish with the default source-upload flow; `hla-compass publish
--image-ref ...` and every image-only compatibility adapter reject the request,
including dry runs. Local `hla-compass validate --strict` remains useful, but
cannot substitute for the platform-owned static analysis and attestation of a
bounded managed source archive.

The compressed source ZIP is limited to 3 MiB by the synchronous publication
transport. Keep datasets, model weights, generated builds, and other large
assets outside the module source tree and access them through governed Catalog
or storage interfaces at runtime. A larger prebuilt artifact without native
MCP capabilities requires the separately governed custom-image publication
path.

Use the following bearer-only surface only when an existing version needs an
explicit operational redeploy:

```python
from hla_compass import APIClient

client = APIClient(environment="dev")  # run `hla-compass auth login` first
receipt = client.deploy_module(
    "MODULE_UUID",
    version="1.2.3",
    deployment_target="auto",
)
deployment = client.wait_for_module_deployment(
    receipt["module_id"],
    receipt["deployment_id"],
    timeout=900,
    poll_interval=5,
)
```

`deploy_module()` returns durable admission with `status="in_progress"` and a
`dispatch_state` of `submitted`, `pending`, or `unchanged`; it does not prove
deployment success. `get_module_deployment()` performs one status read.
`wait_for_module_deployment()` returns only for `deployed`; `failed`,
`cancelled`, and `superseded` raise `APIError` with the platform error message.
API keys and module-run credentials are rejected locally for all three methods.
The deploy request accepts only the existing version selector, target, and
runtime configuration. It never accepts package bytes, an S3/object path, a
container reference, or replacement manifest data: the platform resolves the
exact persisted artifact and scan/schema evidence for that governed Module
Version.

### Pipeline API

The Python client exposes the standalone Pipeline authoring, inspection, and
existing-run lifecycle:
`list_pipelines`, `get_pipeline`, `update_pipeline`, `delete_pipeline`, preset
add/read/default/delete methods, and run start/status/tasks/logs/cancel methods.
A params file supplies base values and the optional inline `parameters` mapping
overrides top-level keys. Local `params_file` and S3 `params_file_uri` are
mutually exclusive with each other, but either may be combined with inline
overrides or a `samplesheet` override. Run submission also accepts
`output_uri`, `user_config_uri`, `priority`, `tags`, `resource_profile`,
`nextflow_profile`, `on_demand`, and `resume_from_run_id`. Submission reserves
ACT from the selected resource profile; a completed run consumes that
reservation and anything else refunds it.

Pipelines whose response has `launchedViaModuleOnly: true` are internal
artifacts. Manage them through their owning Module; direct Pipeline mutation
endpoints reject them, and Module-backed dispatch reaches the same release
gate.

`hla-compass test` is offline by default and does not forward host credentials
or selected catalog state. Non-pipeline templates build and exercise a local
container; pipeline templates exercise the configure handler in-process. Use
`hla-compass test --live ...` only when the test intentionally calls the
authenticated platform; CI jobs that require live integration must opt in with
that flag explicitly.

## Request access

Prospective users can submit a durable access request for platform-admin review:

```python
from hla_compass.auth import Auth

request = Auth().request_access(
    "user@example.org",
    "Example",
    "User",
    "Example Bio",
    environment="dev",
    position="Scientist",
    field_of_interest="TCR",
)
```

This queues a request; it does not create an account or grant organization
membership. Accounts are provisioned through administrator invitations.
`Auth.register()` and `Auth.developer_register()` remain as compatibility
methods but fail locally with request-access and invitation guidance instead of
calling retired endpoints.

### MFA challenge and recovery

`Auth.login()` can return `challenge="MFA_REQUIRED"`, the opaque `session`, and
`recovery_available`. Complete a normal authenticator challenge with
`Auth.complete_mfa(email, session, six_digit_code)`, which returns and stores
the authenticated token payload.

Offer a saved recovery code only when `recovery_available` is true:

```python
reset = Auth().complete_mfa_recovery(email, session, recovery_code)
assert reset["mfa_reset"] is True
assert reset["reauthentication_required"] is True
```

Recovery deliberately returns no tokens. It globally signs out the account,
disables the lost authenticator, and revokes the recovery-code batch. Call
`Auth.login()` again, then enroll a new authenticator before attempting
privileged mutations.

This README is intentionally concise. The public documentation portal is
[docs.alithea.bio](https://docs.alithea.bio); every generated module also ships
with a version-aligned `SKILL.md` and linked `DATA_ACCESS.md` reference.

## 📚 Docs Model

- [Public documentation](https://docs.alithea.bio): SDK, module-authoring, API, and release workflows.
- `SKILL.md` generated by `hla-compass init`: canonical in-module authoring and runtime reference for developers and AI assistants.
- `DATA_ACCESS.md` generated by `hla-compass init`: companion typed-data and scoped-storage contract linked from `SKILL.md`.
- `INTEGRATIONS.md` generated by `hla-compass init`: copy-ready catalog, Python API, REST API, and MCP integration reference.
- `AGENTS.md` generated by `hla-compass init`: a bounded Codex loader that routes agents to the managed guidance without private repository access while preserving project-specific instructions.
- `CLAUDE.md` generated by `hla-compass init`: short in-module orientation that points back to `SKILL.md`.
- `UI_EXTENSION.md` / `MCP_CAPABILITIES.md` when required by a composite manifest: feature overlays that preserve both the compute and UI/native-MCP contracts.

---

## 🤖 AI-Assisted Development

Every module scaffolded by `hla-compass init` includes a documentation set for
both human developers and AI coding assistants:

| File | Purpose |
|------|---------|
| **`SKILL.md`** | Canonical in-module authoring and runtime reference. **Point your AI assistant here first.** |
| **`DATA_ACCESS.md`** | Companion typed-data, Catalog Version, storage, and ingestion-boundary reference linked from `SKILL.md`. |
| **`INTEGRATIONS.md`** | Catalog-selection, Python API, REST API, and MCP integration examples linked from `SKILL.md`. |
| **`AGENTS.md`** | Bounded Codex loader; existing project-specific text is preserved around the managed discovery block. |
| **`CLAUDE.md`** | Thin managed loader/orientation that directs Claude to `SKILL.md` and any linked feature references; it does not duplicate the template contract. |
| **`UI_EXTENSION.md` / `MCP_CAPABILITIES.md`** | Conditional feature references for compute modules: React UI authoring, or native MCP tools. |

> **Tip:** When using an AI coding assistant (Claude, Copilot, etc.), ensure it reads
> `SKILL.md` and follows its links to `DATA_ACCESS.md` and `INTEGRATIONS.md` in
> your module directory. Together they provide the version-aligned contract
> without requiring private repository context. Production readiness still
> requires domain tests and verification in the target environment.

### Refresh an existing module's SDK guidance

After installing a newer SDK, inspect the module's generated guidance before
updating it:

```bash
hla-compass skill check [MODULE_DIR]
hla-compass skill update [MODULE_DIR]
```

`skill update` refreshes the SDK-managed bundle: `SKILL.md`, `DATA_ACCESS.md`,
`INTEGRATIONS.md`, the concise `CLAUDE.md` loader, and any manifest-required
`UI_EXTENSION.md` / `MCP_CAPABILITIES.md` feature references. It also creates
or refreshes a bounded block in `AGENTS.md` while preserving existing
project-specific instructions. Put
module-specific instructions only between the
`hla-compass-user-guidance:start` and `hla-compass-user-guidance:end` markers;
the updater preserves that block across releases. Edits outside that block, or
unrecognized legacy guidance, fail closed. Review those files and use
`hla-compass skill update [MODULE_DIR] --force` only for an intentional
migration. Existing files are backed up by content hash under
`.hla-compass/backups/sdk-guidance/` by default; that private SDK state is
ignored from Git, source archives, and SDK-generated Docker build contexts.

The same inspection and update operations are available to Python tooling:

```python
from hla_compass import inspect_module_skill, update_module_skill

status = inspect_module_skill("path/to/module")
if not status.current:
    result = update_module_skill("path/to/module")
```

These operations update documentation only; they do not rerun `init`, replace
module source, publish a module, or prove that a deployment works.

They also verify `backend/requirements.txt`. A `runtime-gap` status is
non-zero unless the module pins the exact installed SDK release (for example
`hla-compass==<installed-sdk-version>`). The guidance updater does not silently change executable
dependencies: update that pin deliberately, regenerate
`backend/requirements.lock.txt` when present, then rerun `skill check`, strict
validation, and tests.

---

## 🛠️ CLI Entry Points

| Command | Description |
|:--------|:------------|
| `init` | Scaffold a new module (includes `SKILL.md` reference guide) |
| `skill` | Check or update an existing module's SDK-managed guidance bundle |
| `validate` | Validate module structure and manifest |
| `test` | Run a local module smoke execution (containerized except pipeline configure tests) |
| `dev` | Run the interactive local rerun loop |
| `serve` | Serve the UI template locally |
| `publish` | Upload module source to the platform for server-side build and registration |
| `publish-status` | Inspect or watch module intake status |
| `auth` | Manage platform login and keys |
| `mcp` | Print MCP schema or run a local MCP server for the current module |

`hla-compass auth logout` attempts authenticated platform logout with the
stored refresh token before removing local credentials and organization
context. It exits successfully only when there was no local user session or the
platform returns `refreshSessionsRevoked: true`. Local state is still cleared
when the platform cannot confirm revocation; that case is reported as a warning
with exit code 2 so scripts do not mistake local cleanup for confirmed remote
refresh-session revocation. Already-issued platform ID JWTs remain valid until
their normal expiry because API Gateway validates them statelessly.

`hla-compass mcp serve` is an offline local tool server by default. After
authenticating, pass `--live` to exercise Catalog/API reads. Hosted MCP tool
names and execution-policy metadata are authoritative. `mcp schema` previews
the local manifest-derived input and output schemas using the same canonical
object-contract shape as the hosted Module descriptor; it does not reproduce
host-only policy or authorization metadata. The stdio server keeps its
protocol host free of publisher imports: every primary and native tool call
runs in a fresh child interpreter rooted at the directory containing
`manifest.json`. Embedders exposing native tools must likewise construct
`MCPModuleServer(None, manifest_path=...)`; passing a pre-imported publisher
class is rejected because its import may already have changed host process
state.

---

## 🔧 Local SDK Development

When iterating on the SDK itself, use the `HLA_COMPASS_SDK_PATH` environment variable
so that `dev`/`test`/`serve` commands pick up either your local checkout or a
built wheel:

```bash
export HLA_COMPASS_SDK_PATH=../sdk/python
hla-compass dev
hla-compass test --input examples/sample_input.json

# Repository-independent clean-wheel form:
export HLA_COMPASS_SDK_PATH=/absolute/path/to/hla_compass-5.2.0-py3-none-any.whl
```

For an artifact-reproducible authored module/SDK Python dependency closure,
generate and commit a complete hash lock after every dependency or SDK pin
change. Run the exact managed-build-image command in the generated module's
`INTEGRATIONS.md` under **Reproducible Python dependencies**. It selects the
manifest's digest-pinned Python 3.13 Linux build image. Do not run the release
lock directly on macOS or Windows: those resolvers can omit Linux-only
dependencies even when every emitted entry has a hash.

With that lock, released SDK wheels are installed by the hash-verified lock;
an explicitly supplied local SDK artifact is installed `--no-deps` before the
filtered lock supplies its closure. The build validates selected SDK extras and
runs `pip check`. Index installs are wheel-only, so missing target wheels fail
closed rather than executing sdist build backends. A scaffold without the lock
remains functional for immediate development, but the CLI warns that index
resolution at build time is not artifact-reproducible.

The scanned, digest-pinned base owns OS patches, packaging tools, and Lambda's
runtime client; generated child images do not upgrade those inputs live. A
custom compatible base must already supply Python and pip, plus
`awslambdaric` for Lambda. The module lock controls the authored module/SDK
closure while the exact base digest controls platform inputs. A local SDK
source directory is compiled in the released managed module-runtime builder,
independent of the final/custom base, so that base does not need SDK build
backends such as `setuptools` or `wheel`.

---

## Release-controlled build images

The SDK and deployed source-build service read the same packaged image-release
manifest, `hla_compass/module_build_images.json`. Production builds accept only
exact `image@sha256:<digest>` references. If a managed runtime or UI builder has
not passed its release gates, its manifest entry is intentionally empty and the
affected build fails before Docker starts with replacement-publication guidance.

At the current release boundary:

- Lambda source builds use the released, digest-pinned platform Lambda runtime
  derived from the signed/scanned Wolfi module runtime. Its release adds the
  hash-locked AWS Lambda Runtime Interface Client, scans both base
  architectures, then signs and attests the exact multi-architecture digest.
  The pin becomes release-ready only after the no-live-upgrade SDK generator
  also builds and blocking-scans representative final images on both targets.
- Fargate and Batch source builds use the released, signed and attested
  multi-architecture Wolfi runtime pinned by exact OCI digest.
- UI source builds use the released, signed and attested Node 24 builder pinned
  by exact OCI digest. After the managed build, verify the published module
  against the hosted React component contract.

An exact approved image can be supplied to local build commands with
`--base-image` or `--ui-build-image`. Mutable tags are rejected by default. The
only mutable-tag exception requires both
`HLA_COMPASS_ALLOW_MUTABLE_BUILD_IMAGES_LOCAL_ONLY=true` and
`HLA_COMPASS_BUILD_CONTEXT=local|offline|test`; it is never a production
release mechanism. Source ZIPs omit root `Dockerfile`/`Dockerfile.hla` files,
generated/cache directories, and common credential filenames using a
case-insensitive policy; an included symbolic link is rejected rather than
followed. This filename policy is defense in depth, not a secret scanner. Keep
all credentials outside the module tree and scan the repository before
publishing. Managed intake rejects directly supplied build recipes. Native
tools and custom operating-system layers belong in the signed custom-image
flow.

---

## 💎 Key Features

- **Module-first CLI**: Scaffold, test, and publish with a single toolchain.
- **Source-upload publishing**: `hla-compass publish` uploads source; the
  platform builds, scans, and registers the container. See the linked
  prerequisite ladder before choosing the advanced custom-image path.
- **Data helpers**: Storage + data access helpers for module runtimes.
- **Local dev loop**: Containerized `dev`/`serve`/`test` flow for the packaged
  runtime contract; environment-backed behavior still requires live verification.

The CLI uses the active org for the selected environment by default, or `--org-id` to override it.

Direct ZIP registration is not a publication Interface. SDK 5 retains the
published `APIClient.upload_module(module_path, module_name, version)`
signature only as a local migration stub: every call raises `APIError` with
status code 410 before reading the path or making an HTTP request. Existing
integrations must instead call
`APIClient.publish_module_source(manifest=..., source_zip=..., scope="org",
idempotency_key="<stable-retry-key>")`
or invoke
`hla-compass publish --env dev --scope org --idempotency-key <stable-retry-key> --wait`
from the Module source directory. Both paths enter the governed asynchronous build, immutable
digest, signature, and security-scan intake before a Module Version exists.
The retry key must contain 1-256 exact printable ASCII characters. Reusing it for the
same organization, manifest, scope, and source bytes returns the original build;
reusing it for different evidence returns HTTP 409 and never overwrites the
source archive. Re-signing unchanged content does not cause a conflict: the
platform verifies the signature, normalizes only its randomized RSA-PSS bytes,
and still binds the signed manifest and signer metadata.
Manifest signing canonicalization excludes signature metadata only at the
manifest root and excludes the platform-owned root `integrity` field. A
reserved signature-metadata key below the root is rejected instead of being
left unsigned, including when an org-scoped manifest otherwise omits a
signature. Nested `integrity` fields remain developer-authored content and are
covered by the signature; changing one invalidates verification.

## Module Runtime Credential Boundary

Published module code runs with a short-lived key bound to one module run and
organization. Inside `execute()`, use typed catalog helpers, read-only catalog
storage, `self.storage` for run outputs, and current-run progress/callbacks. The
run key is not a logged-in control-plane session: it cannot list/start/cancel
runs, inspect status/logs/results, publish modules, or mutate dataset-version
state. The `Module` composition/polling/result helpers raise
`ModuleCapabilityError` locally in this mode.

Hosted module roles have no direct S3 permission. `self.storage` uses the run
token to ask the platform storage broker for narrowly scoped operations under
the current run's private `files/` namespace, then transfers bytes through
short-lived pre-signed URLs without sending the run token to object storage.
Use `save_file`/`save_json`/`save_csv`, `load`/`load_json`/`load_text`,
`list_files`, `delete_file`, and `create_download_url`; pass logical keys such
as `results/output.json`, never bucket names, `s3://` URIs, or another run's
prefix. Direct S3 remains an explicit local-development compatibility path
when `HLA_COMPASS_RESULTS_BUCKET` is configured without a module-run token.

Use a standalone `APIClient()` with either `hla-compass auth login` or an
appropriately scoped developer API key for Module Run control outside
`execute()`. Deployment and governed ingestion remain bearer-only.

## 5.9 migration

New module publications must use the exact SDK version advertised by the target environment. SDK 5.9 adds cancellable uploads, exact run-file downloads and governed report attachments; deploy the matching API before migrating those clients. Existing deployed module images and historical results remain unchanged.

SDK 5.9.3 bundles UI kit 0.2.0 in UI and pipeline UI scaffolds, with scientific
charts, interactive research controls, host storage/module controls, and browser
PDF export. New scaffolds include it automatically. For existing UIs, follow the
adoption checklist in the generated `UI_STYLE.md`; updating guidance does not
replace executable UI code. The Python API and execution contracts remain
compatible. Existing MHCquant execution does not need to migrate to use this SDK.

Typed samples, peptides and proteins remain compatible with existing GET APIs.
On the first typed read, each client checks the public `/v1/system/version`
metadata and caches the result per API base URL. It uses POST filter bodies
only when `features.scientific_typed_post` is explicitly `true`; a missing or
false flag keeps GET with complete comma-separated ID filters. Recreate a
long-lived client after an API upgrade to discover newly enabled POST support.
Metadata failures and data authorization, version or validation errors are
reported; the SDK does not switch transport in response to an error or remove
a version pin. Empty or invalid ID arrays are rejected before a request.
New prepared-run, notebook and data-view operations require the matching API
release; installing the SDK alone does not add those server capabilities.

Upgrade the authoring environment and each module's runtime dependency together:

```bash
python -m pip install --upgrade 'hla-compass[authoring]==5.9.3'
hla-compass --version
```

In an existing module, set `hla-compass==5.9.3` in
`backend/requirements.txt`, run `hla-compass skill update`, and review the diff.
Managed guidance updates preserve the `hla-compass-user-guidance` block; review
customized legacy files before using `--force`. Guidance updates do not migrate
your Python or UI code automatically.

Regenerate and commit `backend/requirements.lock.txt` with `hla-compass lock`
after changing dependencies. Validate the manifest, run the module's tests and
local runtime check, then publish a new immutable module version. Rebuilding
with an old lock does not install the new SDK. Existing published versions and
scientific results remain unchanged.

SQL `query` and `query_df` now accept an explicit `version=` pin. Record an
immutable Catalog Version UUID, not only a mutable label or the current-version
default. Typed list readers also accept `filters={"version": catalog_version_id}`;
SQL accepts `version=catalog_version_id`. Unknown/unready versions must fail
rather than falling back to current data.

For CLI automation, parse `runs status` standard output as JSON; diagnostics
and the signed-URL redaction notice are on standard error. Keep redaction on
unless a protected consumer explicitly needs the temporary URLs. The local
MCP gateway preserves structured error codes/status as well as text, so callers
can distinguish permission, version, validation and transient failures.

For pipeline custom UIs, migrate obsolete `value`, `onChange`, `run`, `status`
and `output` props to the host's `input`, `onInputChange`, `onExecute`,
`executionStatus` and `result`. Preserve `error`, `dataContext` and
`hostContext`. Do not implement run admission or billing inside the module UI.
Validate the actual published UI after updating; a local bundle build alone
does not establish the deployed contract.

## Personal Account Data

Bearer-authenticated users can request a time-limited export of their own
account data without routing the export bytes through Python:

```python
from hla_compass.client import APIClient

client = APIClient(environment="dev")
export = client.request_personal_data_export(
    export_format="zip",
    date_range="last90days",
    include_jobs=False,
    include_results=True,
)
print(export["download_url"])  # signed URL; expires after 15 minutes
```

Run `hla-compass auth login --env <environment>` first. Personal-data exports
are intentionally unavailable to API keys and module-run credentials. The SDK
returns the signed-URL metadata and does not download personal-data bytes.
Result locations and metadata can be selected independently of module-run
history; job rows never include those locations implicitly.

## Compute Types

Public module manifests use these compute types:

- `lambda`
- `fargate`
- `batch`
- `pipeline` (pipeline-ui / Nextflow definitions with a thin configure Lambda and governed pipeline execution)

`docker` remains accepted only as a legacy publish alias and is normalized to `fargate`.

## Scientific Helper Notes

The convenience helpers `get_hla_alleles()`, `get_hla_frequencies()`, and
`get_protein_coverage()` are implemented as typed REST calls in SDK `3.0.0+`.
They no longer switch implicitly between direct database access and REST.

Migration guidance:

- High-level SDK callers now need a reachable HLA-Compass API endpoint for these helpers.
- API-key authenticated clients continue to work; the SDK now targets `/v1/api/data/...` typed endpoints instead of issuing raw SQL on the caller's behalf.
- Plain JWT user sessions now work through `/v1/data/...` typed endpoints.
- Prefer a canonical Catalog UUID input and call
  `catalog_api = client.for_catalog_id(catalog_id)` externally or
  `self.bind_catalog_id(catalog_id)` inside `execute()`. When only exact keys
  are available, `for_catalog(provider, catalog)` and
  `bind_catalog(provider, catalog)` remain supported. These methods keep typed
  reads plus Catalog storage on the same exact identity and never fall back to
  a prior configured Catalog. Binding does not select a Catalog Version; pass a
  separate explicit Version UUID to reproducible reads.
- `self.data.sql.query(...)` is available to bearer sessions, appropriately
  scoped API keys, and module run tokens for read-only queries within their
  permitted Catalog. Use it for server-side aggregation or queries that a typed
  helper cannot express. Catalog and table authorization apply to every query;
  a module token remains bound to its run and organization.
- For reproducible SQL reads on SDK 5.7 or later, use
  `client.data.sql.query(sql, params=values, version=catalog_version_id)` (or
  `query_df(..., version=catalog_version_id)`). Save the immutable Version UUID
  alongside the query and parameters. Omission reads the current ready version;
  typed list helpers accept the same pin through `filters={"version": catalog_version_id}`. See the
  [5.9 migration guidance](#59-migration) before redeploying modules.
- Direct SQL writes are disabled. Catalog publication goes through the governed
  ingestion workflow so source snapshots, attempts, lineage, and finalization
  remain auditable.
- The legacy `catalog-import` module template is retired and is not scaffolded
  for new modules. `create_catalog_import_upload()` is also retired.
- For normal local files, use `upload_catalog_import_file()`. It streams raw and
  per-part hashes, follows the server-issued fixed-size plan, retries transient
  part transfers, completes with exact ETags, and optionally waits until the
  verifier marks the immutable object version `claimed`.
- The lower-level governed control-plane upload contract remains exposed through
  `initialize_catalog_import_upload()`, `sign_catalog_import_upload_parts()`,
  `complete_catalog_import_upload()`, `abort_catalog_import_upload()`, and
  `get_catalog_import_upload()`. Completion returns
  `uploaded_unverified`; callers must poll until `claimed` before submitting
  the object to Catalog Ingestion. The deployed API/verifier wiring must be
  enabled by the platform—SDK availability alone does not make the workflow
  operational.
- Bearer-authenticated org administrators can then use
  `submit_catalog_ingestion()`, `get_catalog_ingestion()`,
  `cancel_catalog_ingestion()`, and `retry_catalog_ingestion()`. The API is
  default-off behind `CATALOG_INGESTION_ENABLED`; API-key and module-run
  credentials remain denied. Cancel/retry require the latest top-level job
  `stateVersion`. A `retry_idempotency_key` must differ from the original
  submit key; repeating it may return the prior retry with `outcome=replayed`.

Control-plane Python example (the SDK resolves each claimed upload UUID to the
server-returned canonical source URI; callers do not assemble S3 paths):

```python
upload = client.upload_catalog_import_file(
    catalog_id,
    "samples.parquet",
    idempotency_key="upload-2026-07-10",
    wait_until_claimed=True,
)
job = client.data.ingestion.submit(
    catalog_id,
    sources=[{"uploadId": upload["uploadId"], "targetTable": "samples"}],
    idempotency_key="import-2026-07-10",
)
state = client.data.ingestion.status(catalog_id, job["jobId"])
```

Equivalent CLI status/control commands:

```bash
hla-compass data catalog create \
  --provider-key alithea-bio \
  --catalog-key research \
  --schema-name scientific \
  --label "Research" \
  --source-table samples \
  --domain peptidome \
  --yes
hla-compass data ingestion upload CATALOG_ID samples.parquet \
  --idempotency-key upload-2026-07-10 \
  --yes
hla-compass data ingestion submit CATALOG_ID \
  --source UPLOAD_ID:samples \
  --idempotency-key import-2026-07-10 \
  --yes
hla-compass data ingestion status CATALOG_ID JOB_ID
hla-compass data ingestion cancel CATALOG_ID JOB_ID \
  --job-state-version 2 --yes
hla-compass data ingestion retry CATALOG_ID JOB_ID \
  --job-state-version 3 \
  --retry-idempotency-key retry-2026-07-10-1 \
  --yes
```

`predict_hla_binding()` is also implemented, but it is a wrapper over an async
module run and requires a configured binding module id
(`HLA_BINDING_MODULE_ID` or `hla_binding_module_id` in SDK config).

---

## Agent clients and the hosted MCP platform

Install the MCP extra and authenticate with the SDK before configuring Codex,
Claude Code, or another compatible MCP client:

These commands use SDK **5.9.3** and the matching platform API contracts.

```bash
python -m pip install 'hla-compass[mcp]==5.9.3'
hla-compass auth login --env dev
hla-compass mcp doctor --env dev
```

`mcp doctor` checks protocol initialization, authentication, all tool-discovery
pages and tool schemas. Success is `discovery_verified`, with
`toolExecutionVerified: false`: it does not execute tools or verify a research
workflow.

No public remote Codex or Claude Code marketplace release is available yet;
external users should configure the standalone stdio gateway described below.
The repository-local plugin manifests are maintainer validation artifacts.
Those manifests launch the bare `hla-compass` executable. For GUI clients, prefer
`pipx install 'hla-compass[mcp]==5.9.3'`, ensure the pipx apps directory is
on the client's `PATH`, and restart the client. If a project virtual
environment is required, launch the client from that activated environment or
configure a standalone MCP server with the absolute path to its
`hla-compass` executable.

Configure a compatible MCP client to launch the executable `hla-compass` with
arguments `mcp`, `gateway`. The local gateway reuses the SDK credential store,
so client configuration contains no credential value. Set `HLA_COMPASS_ENV` to
`dev`, `staging`, or `prod` only when intentionally overriding the SDK's
selected environment.

The gateway preserves standard tool metadata, structured output, images,
resource links and structured error details across the local stdio bridge.

Catalog Import MCP tools require an interactive org-admin bearer session.
Multipart completion remains `uploaded_unverified`; only a later `claimed`
status proves exact-version verification. `catalog_ingestion` with
`action="submit"` accepts only claimed upload UUIDs and replace mode; poll it
with `action="get"` and use its top-level `jobStateVersion` for confirmed
cancel/retry actions.
Use a retry key distinct from the original submit key; repeating the same retry
key may return `outcome=replayed`. Append ingestion and direct Catalog Version
publication are unavailable.

The hosted MCP `query_data` tool accepts authorized bearer/OAuth sessions with
explicit confirmation; no platform-admin role is required. Queries remain
read-only and enforce catalog access, relation allowlists, Catalog Version
scope, timeouts and pagination. Raw SQL is denied when data-profile row filters
or peptide masking cannot be enforced. Discover the exact catalog and inspect
its schema before constructing SQL. API keys and module run tokens cannot use
this tool; prefer typed tools when they cover the requested operation.
Compass's built-in chat has a separate inventory policy: it currently exposes
`query_data` only to platform administrators, and approval follows the selected
chat execution mode. This does not add a platform-admin requirement to external
MCP or the governed SQL API.

---

## 📖 Advanced Documentation

- **[Public documentation](https://docs.alithea.bio)** – SDK, module workflow, and API reference.
- **Generated documentation set** – Version-aligned `SKILL.md`, `DATA_ACCESS.md`, and concise `CLAUDE.md` orientation.
- **`hla-compass --help`** – Installed command and subcommand reference.

---

## 🤝 Support and security

Use the [Alithea Bio website](https://alithea.bio) to contact the team. Do not
send credentials or sensitive scientific data in an initial support message.
For a security report, request a private channel before sharing technical
details.

### Governed saved views and independent named sources

Save the displayed catalog version by default. For mixed catalogs, give each
source its own name, catalog identity and SQL; sources remain independent and do
not imply a database join or additional charged runs.

```python
from hla_compass import APIClient

client = APIClient()
view = client.data_views.create("Tumor and normal", sources=[
    {"name": "tumor", "catalogId": TUMOR_CATALOG_UUID,
     "providerKey": TUMOR_PROVIDER, "catalogKey": TUMOR_CATALOG_KEY,
     "catalogVersionId": TUMOR_VERSION_UUID, "source": "samples",
     "sql": "SELECT sample_id FROM samples", "columns": ["sample_id"]},
    {"name": "normal", "catalogId": NORMAL_CATALOG_UUID,
     "providerKey": NORMAL_PROVIDER, "catalogKey": NORMAL_CATALOG_KEY,
     "catalogVersionId": NORMAL_VERSION_UUID, "source": "samples",
     "sql": "SELECT sample_id FROM samples", "columns": ["sample_id"]},
])
plan = client.prepare_module_run(
    MODULE_UUID, parameters={}, mode="async",
    data_context={"type": "data_view", "viewId": view["id"]},
)
# Review plan["preparedRequest"], the input version pins and estimated cost.
# Only after approval:
run = client.start_prepared_module_run(plan)
```

Use a module that declares `data_requirements.source_composition: "named"` and an
input with `x-hla-data-role: "selection.manifest_uri"`. Existing single-source
modules remain usable for one source. Explicit `versionPinMode: "current"` follows
latest until preparation freezes the version; it never changes an admitted input.

Inside a hosted module, `context.data_selection.sources` lists the exact source
Dataset Versions and checksums. `context.data_selection.source("tumor")` returns
one source's metadata. `context.data_selection.load_source("tumor", self.storage)`
reads its bytes through the current run's admitted-input broker and verifies its
SHA256. `load_manifest(self.storage)` verifies and returns the aggregate manifest.
These helpers use run permissions, without catalog-wide storage credentials.

For a CLI plan, put the parameters in `inputs.json`, run
`hla-compass runs prepare MODULE_UUID --inputs inputs.json > plan.json`, review
that file, then run `hla-compass runs confirm plan.json`. Retry the same unchanged
plan/file after a lost response. An expired unused plan or changed cost requires a
new preparation and review; clients never automatically approve a replacement.
`hla-compass data views` provides list/show/create/status commands.

Typed sample, peptide and protein list helpers negotiate POST filter bodies in
SDK 5.7 when the API advertises `features.scientific_typed_post: true`; older
APIs retain GET. Both transports carry every selected ID and the explicit
version pin. Older APIs can reject unsupported pins or selections that exceed
their request limits; those errors are surfaced without truncation or a query
against current data. Raw SQL and saved SQL are denied for restricted or
unreadable row-filter profiles; use the typed data readers for those profiles.

## SDK 5.9 developer workflow interfaces

- `upload_storage_file` and `data uploads`: cancellable/resumable managed or
  external-S3 uploads with exact receipts. Keep stable idempotency keys and
  source-relative prefixes. Transferred bytes are separate from verified completion.
- `runs.download_artifact`: exact run/lineage/version access with byte checks;
  generic storage-prefix access is not widened.
- `runs.reports`, `report`, `attach_report`, `download_report`: immutable user-created
  PDF/snapshot attachments, separate from computation outputs and settlement.
- UI kit `ReportBuilder`, chart-export/PDF-print/report interfaces, complete shared
  standalone theme and collapsible optional inputs. See packaged `UI_STYLE.md`.
- `load_source` returns `bytes`; `load_manifest` returns an already parsed mapping.
- Successful API-key revocation permits up to 60 seconds of cached authorization.
  Existing signed storage URLs keep their separate expiry (15-minute upload parts,
  five-minute retained run/report downloads); revocation does not undo completed work.

Full executable examples and endpoint contracts live in packaged `INTEGRATIONS.md`.
These interfaces require the matching deployed API. Publication must use the exact
SDK release advertised by the target environment; existing images remain executable.
