Metadata-Version: 2.5
Name: runlocal-external-interface
Version: 0.1.0
Summary: Portable Runlocal workload authoring, compilation, and validation
Author: Runlocal
Requires-Python: <3.15,>=3.8
Requires-Dist: eval-type-backport>=0.2; python_version < '3.10'
Requires-Dist: jsonschema<5,>=4.18
Requires-Dist: pydantic<3,>=2.8
Requires-Dist: referencing<1,>=0.30
Requires-Dist: rfc8785<1,>=0.1.2
Requires-Dist: typing-extensions>=4.6
Provides-Extra: onnx
Requires-Dist: onnx<2,>=1.16; extra == 'onnx'
Provides-Extra: test
Requires-Dist: build<2,>=1; extra == 'test'
Requires-Dist: pytest<9,>=7; extra == 'test'
Description-Content-Type: text/markdown

# Runlocal External Interface

Portable workload authoring, compilation, validation, and authenticated cloud storage.

```text
source JSON + local artifacts
        |
        v
 authoring/compilation -----> content/bundle (request + exact object bytes)
        |                           |
        v                           v
 request/contract <-------- interface/codec (strict JSON + schemas)
        |                           |
        v                           v
 validation/contract <---- validation/onnx
        |
        v
 response/validation -----> interface/cli (JSON results)
                                    |
                                    v
                           interface/transport
                                    |
                                    v
                         private request cloud API
```

The request and response contract modules own the portable DTOs. The codec owns
strict JSON and canonical encoding. Compilation produces a `RequestBundle`.
Validation consumes the submission and its content reader. The transport sends
only that explicit bundle and its client validation report. It does not read
private local bindings or execute customer code.

## Local use

Install with the `onnx` extra for native validation. Use `--help` on any command.

```sh
runlocal-external-interface compile examples/shared_weight/source.json --out ./bundle
runlocal-external-interface validate ./bundle
runlocal-external-interface inspect request ./bundle
```

## Cloud use

Sign in to https://dropzone-eight-rust.vercel.app and create a key under
**CLI & API keys**. Keys grant upload, list, and download access to your private
workspace. They expire after 90 days and can be revoked from that page.

```sh
export RUNLOCAL_API_URL='https://veracious-bison-418.eu-west-1.convex.site'
read -s RUNLOCAL_API_TOKEN
export RUNLOCAL_API_TOKEN
runlocal-external-interface upload ./bundle
runlocal-external-interface list --limit 20
runlocal-external-interface list --cursor CURSOR
runlocal-external-interface download REQUEST_ID --out ./restored
```

`--api-url` overrides the origin environment variable. Tokens are read from the
environment only. HTTPS is required except on localhost. Redirects are refused.
The CLI has a 60-second request timeout. It does not retry automatically. An
identical upload is safe to repeat: the server returns the existing revision.
A changed document under the same lineage/revision fails with a conflict.

Upload runs the installed validator first. `--require-complete`, `--workload`,
`--region`, and `--no-native` have the same meaning as on `validate`. Invalid
requests do not upload. Incomplete or unsupported scopes retain those states;
without `--require-complete` they can be stored for inspection. Local-only
parameter bindings remain identifiers; their real values are never fetched.

The server checks wire shape and exact object size/digest. It retains the
client report with checked digest binding, but does not endorse its claims or
run native/semantic checks itself. No upload starts optimization.

The transport limit is 8 MiB, including base64 overhead; request JSON and the
optional client report each have a 512 KiB limit. There are at most 128 objects.
List pages contain 1–50 requests; `next_cursor: null` ends the list. Download
writes a new portable bundle directory and verifies all cataloged object bytes.
It never replaces an existing directory.

All commands default to JSON output and use nonzero exit codes on failure.
HTTP failures retain the server code/message in an operational diagnostic.

## Publish this package

Use the manual release script from the repository root. It releases only
`runlocal-external-interface`. A Git push does not run this script.

First, build and check the release without an upload:

```sh
uv run --script packages/runlocal-external-interface/scripts/publish.py
```

To build, check, and publish to PyPI:

```sh
uv run --script packages/runlocal-external-interface/scripts/publish.py --publish
```

The script reads `pypi.password` from the repository root `.env` as a PyPI API
token. It also accepts `UV_PUBLISH_TOKEN` or `PYPI_TOKEN` in that file or in the
environment. Environment tokens take priority. `pypi.username` is not needed.
The script does not execute the `.env` file, print the token, or pass it in
command arguments. Only the upload process receives the token.

```text
package source -> source archive -> wheel
                                     |
                      install in a temporary environment
                                     |
                      metadata + CLI + package tests
                                     |
                       retained artifacts + SHA-256 list
                                     |
                          --publish -> PyPI
```

Each build has a separate directory under `dist/releases/`. The script prints
that path. It retains the wheel, source archive, and `release.json` with their
SHA-256 hashes. Old files from other builds are not uploaded. Checks run against
the installed wheel, with ONNX support and the tests from the source archive.
The extracted package source is removed before tests to prevent local imports.
Failed commands stop the release and return a nonzero exit code.

To publish a checked build or retry a partial upload, use its exact directory:

```sh
uv run --script packages/runlocal-external-interface/scripts/publish.py \
  --artifacts packages/runlocal-external-interface/dist/releases/ARTIFACT_DIRECTORY \
  --publish
```

This runs the checks again without rebuilding. The package name and version
must match `pyproject.toml`. PyPI uploads use an explicit list of two files.
Identical files already on PyPI can be skipped; conflicting files cause failure.
For a changed release, set a new version in this package's `pyproject.toml`.

The release script uses Python 3.12 or newer. `uv` manages its dependencies.
Wheel tests use Python 3.12 by default; use `--python VERSION` to select another
test interpreter. Use `--env-file PATH` to select another token file, or
`--help` to list the options. Package runtime requirements are unchanged.

After a successful release, users can install the CLI with:

```sh
uv tool install --python 3.12 "runlocal-external-interface[onnx]"
```

For the release process, see the [uv publishing guide](https://docs.astral.sh/uv/guides/package/).
