- integrations
- Python
- Guides
- Authoring packages
Authoring packages
The author flow lives on
Ocx.package — machine tier,
alongside install/select/exec, not on Project. Three methods carry
the core of it: create →
test →
push; the index side
— announce,
claim, and the
rolling-tag audit cascade_check /
cascade_repair
— follows below.
# illustrative: needs a real ocx binary and a real package directory.from ocx_sdk import Ocx
ocx = Ocx()ocx.package.create("./my-tool", identifier="ocx.sh/me/my-tool:1.0.0", platform="linux/amd64")result = ocx.package.test( "ocx.sh/me/my-tool:1.0.0", script="./test.star", metadata="./my-tool/metadata.json",)if result.passed: published = ocx.package.push("./my-tool.tar", identifier="ocx.sh/me/my-tool:1.0.0") print(published.manifest_digest)create — bundle a directory
Section titled “create — bundle a directory”create bundles a
local directory into a package archive, writing a build receipt beside it
that test and push read back — identifier and platform given here
don’t need repeating on the later calls. There is nothing to return: ocx
prints no payload for this command.
What it recorded reads back through
receipt, which
wraps ocx package receipt and returns a
BuildReceipt. A bundle with no
receipt beside it is ocx’s exit 79 and answers None here — the ordinary
state for a bundle handed over from elsewhere. A receipt ocx cannot read is
exit 65 and stays a DataError:
“unreadable” must never degrade into “absent”, because that turns a recorded
value into a usage error about a flag the publisher never needed.
receipt.ref is the identifier as a
PackageRef.
from ocx_sdk import BuildReceipt
receipt = BuildReceipt.from_json('{"identifier": "ocx.sh/me/my-tool:1.0.0"}')assert receipt.platform is Noneassert str(receipt.ref) == "ocx.sh/me/my-tool:1.0.0"test — the --script envelope
Section titled “test — the --script envelope”Only the --script form of ocx package test is typed. The trailing
-- CMD form prints the tested command’s raw stdout verbatim, even under
--format json, so nothing here could parse it reliably — reach for
invoke if you need that form.
The --script form runs a Starlark test script against a materialized copy
of the package and returns a
TestResult — the stable v1
envelope, one of the durable anchors re-verified on every ocx version
bump. status decides pass or fail; when it fails,
assertion.kind is the stable, machine-readable reason (assertion is
None on a pass):
from ocx_sdk import TestResult
result = TestResult.from_json( '{"status": "failed", ' '"run": {"exit_code": 1, "stdout": "", "stderr": "", "duration_ms": 3, "truncated": false}, ' '"assertion": {"kind": "exit_code_mismatch", "message": "expected 0, got 1"}}')assert not result.passedassert result.assertion is not Noneassert result.assertion.kind == "exit_code_mismatch"layers= takes layer archives or digest references, base first; metadata=
is required whenever no file layers are given; private=True composes
ocx’s --self surface for testing a package’s own private tooling.
push — publish, deliberately not retried by default
Section titled “push — publish, deliberately not retried by default”push publishes a
package’s layers and metadata to a registry and returns a
PushResult — the published
identifier, digest, and tags.
Like Ocx.login, push defaults
its per-call retry to None regardless of session policy: a push is a
registry write, and re-sending one after a timeout risks publishing twice.
Pass retry= explicitly when the target registry is known to be
idempotent-safe. cascade=True also advances the rolling tags above this
version.
Continues on Authoring packages: announce.