# ocx_sdk

*module*

Python SDK for [OCX](https://github.com/ocx-sh/ocx).

`ocx-sdk` drives the ocx binary rather than reimplementing it: ocx owns
resolution, verification, and the identifier grammar, and this package gives
you typed, CWD-independent handles over the commands it exposes.

```python
from ocx_sdk import Ocx, bootstrap

ocx = Ocx(exe=bootstrap.ensure())
project = ocx.project("/srv/build")
project.pull()
project.exec(["task", "verify"])
```

**This module is the API.** Everything listed in `__all__` is the stable
surface; every other module is underscored and package-private, and the one
public submodule is `ocx_sdk.bootstrap`. Reaching into an underscored path
means the next release may move it without notice — pre-1.0, breaking
changes ship without shims.

Start at `Ocx` for the runtime API and `bootstrap.ensure` for provisioning.

[View source](https://github.com/ocx-sh/ocx-sdk-python/blob/main/src/ocx_sdk/__init__.py#L1-L1)

## ocx_sdk.PullReport

*class* · *dataclass*

```python
class PullReport
```

Re-exported from: `ocx_sdk._results`

`ocx pull` at the **project** tier — paths plus advisories.

The wire object mixes both: identifiers key `{path, kind}` values, and a
sibling `advisories` key sits among them. An identifier is always at least
`<repo>/<name>`, so it can never collide with that key.

**Attributes**

- `packages` (`Mapping[str, WhichResult]`) — Pinned identifier to where it landed.
- `advisories` (`tuple[Mapping[str, Any], ...]`) — Warnings, carried untyped — no probe has seen a populated one, and `ocx env`'s advisory shape is not known to apply here.

[View source](https://github.com/ocx-sh/ocx-sdk-python/blob/main/src/ocx_sdk/_results.py#L1149-L1171)

### ocx_sdk.PullReport.advisories

*attribute* · *class attribute* · *instance attribute*

```python
advisories: tuple[Mapping[str, Any], ...] = ()
```

[View source](https://github.com/ocx-sh/ocx-sdk-python/blob/main/src/ocx_sdk/_results.py#L1164-L1164)

### ocx_sdk.PullReport.packages

*attribute* · *class attribute* · *instance attribute*

```python
packages: Mapping[str, WhichResult] = _EMPTY
```

[View source](https://github.com/ocx-sh/ocx-sdk-python/blob/main/src/ocx_sdk/_results.py#L1163-L1163)

### ocx_sdk.PullReport.from_json

*method* · *classmethod*

```python
def from_json(raw: str) -> PullReport
```

Parse `ocx --format json pull` output.

[View source](https://github.com/ocx-sh/ocx-sdk-python/blob/main/src/ocx_sdk/_results.py#L1166-L1171)

## ocx_sdk.PushResult

*class* · *dataclass*

```python
class PushResult
```

Re-exported from: `ocx_sdk._results`

`ocx package push` — what landed in the registry.

**Attributes**

- `identifier` (`str`) — What was pushed.
- `status` (`str`) — What happened, e.g. `"pushed"`.
- `manifest_digest` (`str`) — Digest of the manifest that was written.
- `cascade_tags_written` (`tuple[str, ...]`) — Cascading tags updated by the push.
- `keep_tags_written` (`tuple[str, ...]`) — The `__ocx.keep.sha256-<hex>` tags written, one per platform manifest — `push`'s `--keep-tag` flag, which is on by default. Named for the wire key ocx 0.6 emits (C-005); 0.5 called it `canonical_tags_written` and wrote a `sha256.<hex>` tag, so a 0.1 call site reading the old attribute must be edited.
- `layers` (`Mapping[str, Any]`) — Layer counts (`mounted`, `uploaded`, `verified`).
- `platform_digests` (`Mapping[str, str]`) — Manifest digest per pushed platform (C-005). Absent-when-unused (D7).
- `signatures` (`tuple[SignedPlatformReport, ...]`) — One row per platform's signing outcome, when `push(..., sign=True)` was requested (C-005, C-018). Absent-when-unused (D7).
- `attestation` (`AttestationOutcome | None`) — The push's attestation outcome, when one was requested (C-005, C-019). Absent-when-unused (D7).

[View source](https://github.com/ocx-sh/ocx-sdk-python/blob/main/src/ocx_sdk/_results.py#L1472-L1532)
