Metadata-Version: 2.4
Name: gridlinegpu
Version: 0.1.5
Summary: Python client for Gridline YAML workload routing
Author: Gridline GPU
License: Proprietary
Project-URL: Documentation, https://gridlinegpu.com/cli
Project-URL: Repository, https://github.com/GridlineGPU/gridline-gpu
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: PyYAML<7,>=6.0.2

# Gridline Python SDK

Submit one YAML workload through Gridline's authenticated API. The Python client stages
files referenced by YAML, returns a route for review, then launches only that exact
fresh plan when you supply a cost ceiling and idempotency key. The package also installs
the `gridline` command in the same Python environment on macOS and Linux.

## Install

```sh
python -m pip install 'gridlinegpu>=0.1.4,<0.2'
```

Run browser setup once. It creates a 30-day scoped token in a private file, attempts to
revoke the temporary browser session, and never prints the token. Keep the token file out of
source control and AI chats.

```sh
gridline setup --apply
```

Use a YAML file beside its referenced inputs. Task, model, engine, providers, output,
budget, and deadline belong in YAML rather than Python arguments.
Server-advertised artifact limits govern each submission. Newer Gridline deployments
use direct, signed resumable Storage uploads for large local inputs; older deployments
may still cap inputs at 40 MiB and outputs at 8 MiB.

```python
from gridlinegpu import GridlineClient

client = GridlineClient()
search = client.search("workload.yaml")
print(search["coverage"], search["offers"])  # Catalog facts may be unknown; coverage may be partial.
plan = client.plan("workload.yaml")
print(plan.review)  # Check selected GPU, exclusions, estimate, and maximum.

# Launch only after reviewing the fresh plan and accepting its maximum spend.
launch = client.launch(plan, max_cost_usd="5.00", idempotency_key="my-job-2026-09-27")
job_id = launch["jobId"]
ready = client.wait(job_id, timeout=7200)
print(ready["job"]["outputs"], ready["job"]["outcome"])
print(client.outputs(job_id, "results"))
```

The same installed package supports a terminal flow:

```sh
gridline workload search workload.yaml
gridline workload validate --file workload.yaml
gridline workload plan --file workload.yaml
gridline workload run --file workload.yaml --apply --max-cost-usd 5 \
  --idempotency-key my-job-2026-09-27
gridline workload status JOB_ID
gridline workload outputs JOB_ID --directory results
```

The paid `run` command plans a fresh quote, prints it, and asks for explicit confirmation.
For an approved noninteractive run, add `--yes` and explicit `--profile production`
alongside `--apply`, a cost ceiling, and an idempotency key. Cancellation similarly
requires `--apply` and confirmation. A custom
token path may be passed as global `--token-file` or through `GRIDLINE_API_TOKEN_FILE`.
Workload commands also honor `GRIDLINE_API_TOKEN` when no token file is selected.
The existing standalone Bun CLI remains available during transition; check which
`gridline` executable your shell selects when both are installed. Run
`python -m gridlinegpu` to choose this package's command explicitly.
Use `gridline auth token list` to find a token ID and
`gridline auth token revoke TOKEN_ID --apply` to revoke it. Both require fresh browser
approval; the Python CLI never stores a privileged refresh token.
After revoking a token, remove its local file before running setup again; setup never
overwrites an existing file.

`plan()` validates YAML and checks advertised task readiness before reserving or
uploading inputs. An explicitly unavailable managed ASR/LLM runtime, minimal managed
model resolver, or custom finite path raises `GridlineError` with code
`planning_unavailable`. Qualify the custom container and enable its launch path, or
use available managed runtime/full YAML settings as indicated by the error. Missing
task readiness fields on older servers preserve existing behavior. Custom endpoint
support remains a server planning decision; finite readiness does not describe it.
`plan()` stages input bytes but does not allocate a GPU. `launch()` never silently
changes a plan or retries an ambiguous paid request. If launch outcome is unknown,
inspect `LaunchOutcomeUnknown.workload_id` with the same idempotency key; do not use a
new key. `outputs()` verifies byte count and SHA-256 before creating private files.
Cancellation requests stop; cleanup and final provider billing can remain pending.
For finite jobs, `wait()` returns when outputs are complete, even if cleanup and billing
leave `outcome` pending. Check `status()` later for final settlement.

`search()` reads only YAML and connected-provider catalogs. It does not inspect or
upload referenced inputs, resolve a model or image, create a workload, or allocate a
GPU. `availability()["searchAvailable"]` is separate from planning and execution
readiness. Missing price, VRAM, capacity, or topology facts remain unknown. Partial
catalog coverage and unsupported execution remain visible; a search result is not a
launch quote. `scopeStatus: "empty_scope"` with `catalogCompleteness: "not_applicable"`
means no accounts were searched. Servers with catalog search disabled return a
search availability error. The CLI prints the same JSON response and also accepts
`gridline workload search --file workload.yaml`.

When worker progress is enabled on the hosted API/control service and supported by the
deployed worker image, `status()` also returns optional `progress`:

```python
status = client.status(job_id)
progress = status.get("progress")
if progress:
    for event in progress["events"]:
        print(event["stage"], event["observedAt"])
```

Events are bounded, ordered worker reports for `progress["attemptId"]` and its fence.
Stages include input staging, model preparation/loading, inference start/completion,
and output upload. `observedAt` is the server's receipt time. Poll no faster than every
five seconds; deduplicate by attempt/fence/stage. Missing progress or skipped stages
mean unavailable evidence, not failure or an inferred stage. Inference completion
does not imply stored outputs, job success, cleanup, or settled billing. `wait()` keeps
its existing completion behavior and does not stream progress callbacks.
