Metadata-Version: 2.4
Name: panofabric
Version: 0.1.1
Summary: Command-line interface and Python SDK for the PanoFabric distributed-training control plane
Author-email: Panocular AI <hello@panocular.ai>
License-Expression: Apache-2.0
Project-URL: Homepage, https://panofabric.ai
Project-URL: Control plane, https://panofabric.panocular.ai
Project-URL: Support, https://panocular.ai/#contact
Keywords: panofabric,distributed-training,diloco,torchtitan,cli,sdk,gpu
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pyyaml<7,>=6
Requires-Dist: pyjwt<3,>=2.8
Dynamic: license-file

# panofabric

Command-line interface and Python SDK for **PanoFabric** — a control plane for
fault-tolerant, decentralized distributed training.

`panofabric` is a **thin client**. It talks to the PanoFabric control-plane.

## Install

```bash
pip install panofabric
# or, as an isolated tool:
uv tool install panofabric      # pipx install panofabric
```

Python 3.10+.

## Quickstart

```bash
panofabric login                      # Authentication flow against the hosted control plane
panofabric run submit spec.yaml       # returns a run id
panofabric run list
panofabric run status <run-id>        # run + per-island state
panofabric run logs <run-id> -f       # stream island stdout
panofabric run metrics <run-id>       # parsed loss / tps / mfu
panofabric run cancel <run-id>
```

A minimal RunSpec:

```yaml
name: hello-diloco
workload: { kind: pretrain, strategy: diloco }
model:    { module: models.llama3, preset: llama3_debugmodel }
training: { steps: 60 }
ft:       { sync_steps: 20 }
islands:
  - count: 2
    local_batch_size: 8
    resources: { accelerators: "H100:8" }
```

Training your own model code? `panofabric run submit spec.yaml --code ./my_model/`
packs the directory as a deterministic overlay, uploads it (deduplicated by digest),
and injects it into the spec.

## Bring your own compute

One verb covers every backend — enrolled SSH machines, Slurm clusters, and cloud
accounts:

```bash
panofabric backend add ssh --host ubuntu@1.2.3.4    # enrolls with a revocable deploy key
panofabric backend add slurm --name my-cluster --host login.hpc.example --user alice
panofabric backend add nebius --name my-account --auto
panofabric backend list
panofabric backend check
```

## Configuration

| Variable | Meaning |
|---|---|
| `PANOFABRIC_URL` | control-plane URL (default: the instance you last logged into, else the hosted plane) |
| `PANOFABRIC_TOKEN` | bearer token — preferred over `--token` in CI (flags leak into `ps` and shell history) |
| `PANOFABRIC_TOKEN_FILE` | read the token from a file instead |
| `PANOFABRIC_HOME` | where credentials are stored (default `~/.panofabric`) |

Flags `--base-url`, `--token`, `--workspace`, and `--json` override per invocation.
Non-`https` control-plane URLs are rejected outside of loopback: the bearer token rides
on every request.

## Python SDK

Same API surface as the CLI, for scripting:

```python
from panofabric.client import PanoFabricClient

with PanoFabricClient() as pf:           # env/stored creds, or PanoFabricClient(base_url, token=...)
    run_id = pf.submit_run(spec_dict)["run_id"]
    print(pf.get_run(run_id)["run"]["status"])
    for entry in pf.get_logs(run_id):    # [{"id", "replica_id", "line", ...}]
        print(entry["line"])
```
