Metadata-Version: 2.4
Name: klio-compute
Version: 0.5.9
Summary: Python SDK and CLI for Klio Compute: serverless GPUs, functions and endpoints.
Author: Klio
License-Expression: AGPL-3.0-only
Keywords: klio,gpu,serverless,compute
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: <3.14,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: beta9==0.1.292
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Requires-Dist: fastapi>=0.110; extra == "test"
Requires-Dist: httpx>=0.27; extra == "test"
Dynamic: license-file

# klio-compute

Python SDK and command line for **Klio Compute**: run functions, endpoints and
GPU workloads on Klio's serverless platform.

## Quick start

```bash
pip install klio-compute
klio login
```

The newest release is on PyPI and is also named in <https://klio.tech/sdk/latest.txt>.

```python
from klio_compute import function, Image

@function(image=Image(python_version="python3.12"))
def hello(name: str) -> str:
    return f"Hello, {name}"

if __name__ == "__main__":
    print(hello.remote("Klio"))
```

```bash
python app.py
klio --help
```

For CI, set `KLIO_TOKEN` instead of running `klio login`. Your login is stored
in `~/.klio/config.ini`.

## Coming from Modal

Change one line and keep the rest of your code:

```python
import klio_compute.compat as modal   # was: import modal
```

```bash
klio login
klio migrate --check .      # what works, what warns, what is refused. Changes nothing.
klio migrate --write .      # changes the import lines, and nothing else
klio run app.py             # the local_entrypoint, or the only function
klio run app.py::fn --x 1   # a named function, with arguments from its type hints
klio deploy app.py          # every function and class, as <app>-<name>
```

Functions and classes reuse warm containers, `.map()` keeps input order, and exceptions come back as the
type your function raised. Web functions are public unless they say `requires_proxy_auth=True`, in which case
callers send a Klio key as `Authorization: Bearer`. Anything that can't be honored stops with a clear message;
nothing is silently dropped.

What differs:

- `klio secret create NAME K=V K2=V2 --from-dotenv .env --force` makes a group, as you're used to.
- `klio volume put/get/ls/rm/cp` work on volumes. `Volume.reload()` right after a commit in another container
  waits until the data is readable there, which can take longer than you may be used to.
- `@modal.clustered`, `@modal.batched`, `@modal.web_server`, `@modal.wsgi_app`, `.remote_gen()`, `CloudBucketMount`, `region=` and `cloud=` aren't available, and say so when used.
- `Image.run_function` runs your function during the build, without a GPU, volumes or secrets.
- A `Cron` in a time zone starts a short container often enough to check its local clock, and that time is billed. A `Dict` entry lasts a week from when it was written, and a `Queue` a day from its last write.
- What a function prints appears in your terminal when each call finishes, not line by line.
- `gpu=` takes the types in your console, with up to 8 of one type as `gpu="H100:2"`, `"H100:4"` or `"H100:8"`. For another type, or more of anything, write to support@klio.tech.
- `klio app list/info/logs/stop`, `klio curl URL`, `klio dashboard` and `klio shell` are there too.

The same file can move back by restoring the import. Modal is a trademark of its owner; Klio Compute is not
affiliated with it.

## GPU prices

GPU prices are live. Every 5 minutes Klio finds the cheapest machine it can get for each GPU type and
prices it, so a price can go up or down during the day.

```bash
klio gpus           # every GPU type, its price per hour right now, and whether it can start
klio gpus --json    # the same list as JSON
```

A container pays the price in effect when it starts, and keeps that price for as long as it runs. A price
change only affects containers that start after it.

Before a GPU workload starts (`klio run`, `klio deploy`, `.remote()`, `klio model deploy`), Klio prints
what that GPU costs right now, once per GPU. For example (the real price will differ):

```text
L40S costs $2.85 per GPU-hour right now (updated 3 min ago). A container keeps the price it starts at.
```

With a list of GPUs, each price is shown. If none of the GPUs you asked for can start right now, the
workload stops before anything starts, and nothing is charged. If the price list can't be read, the
workload goes on and a short note says so.


Klio Compute runs Python 3.12. `Image(python_version="python3.12")` (and plain `Image()`)
is the supported image, and anything built on it (`python_packages`, `commands`) can import
`klio_compute` in the container with nothing to install. Asking for another version stops with
a message before anything is sent.

An image with its own `base_image` or Dockerfile may use any Python. `klio_compute.Image`
adds one build step that installs this release of `klio-compute` (without its dependencies,
which the platform provides), so `from klio_compute import function` works inside it too. Use
`Image` from `klio_compute`, not from another package. Set `KLIO_SDK_INSTALL_SPEC` to install
from somewhere else, such as a private mirror.

Do not list `klio-compute` in `python_packages`: pip would then install its dependencies, and
those conflict with the versions the platform fixes in images.

## Several GPUs in one container

A container can have 1, 2, 4 or 8 GPUs of one type, all on the same machine, so they can talk to each other
directly (for example with NCCL or tensor parallelism):

```python
from klio_compute import function

@function(gpu="L4", gpu_count=2)
def train():
    import torch
    return torch.cuda.device_count()  # 2
```

With the Modal syntax, write `gpu="L4:2"`. Any other count stops before anything starts, and nothing is
charged. Several GPUs need a paid workspace; the free tier runs one GPU at a time. Each GPU count has its
own price per GPU-hour, and a container pays it for each of its GPUs. `klio gpus` lists the counts that
can start right now:

```text
Several GPUs in one container (gpu_count=N, or gpu="TYPE:N"):
GPUs    Per GPU-hour  Per hour, all GPUs
L4:2    $1.50/h       $3.00/h
```

## Deploy a model

```bash
klio model deploy qwen3-14b
```

This deploys Qwen3 14B behind an OpenAI-compatible API on your own address, shows progress while it
starts, and prints how to call it. It needs a key: requests without one are refused. Use the address
as the base URL of any OpenAI client, with a key from Keys in the console.

From no machine, the first start has taken about 12 minutes, and that can vary. It stops by itself after
5 minutes without requests (`--keep-warm` changes that), and you pay while it runs. The next request starts
it again and waits while it loads. `klio deployment stop <id>` removes it. `klio model list` shows what you can deploy.

## Troubleshooting

- `Your key isn't valid. Run klio login`: the key was revoked or mistyped. Sign in again, or
  create a new key under Keys in the console if you use `KLIO_TOKEN`.
- `GPUs aren't turned on for your account yet`: nothing was started or charged. Write to
  support@klio.tech. Workloads without a GPU work now.
- `... can't be started right now`: no machine for that GPU is available at the moment. Nothing was
  started or charged. Run `klio gpus` to see which GPUs can start, or ask for several GPUs as a list
  (`gpu=["L40S", "A100"]`) so the workload can use whichever is available.
- `klio doctor` checks your connection and credentials.

## License

`klio-compute` is licensed under the GNU Affero General Public License v3.0; the full text is in
[LICENSE](LICENSE). Source and notices for everything it uses are at
[klio.tech/licenses](https://klio.tech/licenses).
