Metadata-Version: 2.4
Name: fcloud-sdk
Version: 0.1.3
Summary: Python SDK and CLI for the fcloud GPU compute platform
Author: fcloud
License-Expression: Apache-2.0
Keywords: gpu,cloud,compute,ml,training,cli
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
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
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: aiohttp>=3.9
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-xdist>=3.5; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Requires-Dist: mypy>=1.10; extra == "dev"
Requires-Dist: types-requests; extra == "dev"
Dynamic: license-file

# fcloud

Python SDK and CLI for the fcloud GPU compute platform: provision GPU or CPU
hosts, run commands and scripts on them, keep a persistent workspace between
runs, move files in and out, and drive long-running or batch jobs — from a
terminal, from Python, or from an AI coding agent.

Requires Python 3.10+.

## Install

```bash
pip install fcloud-sdk
```

## Setup

Create an account on https://fcloud-home.vercel.app.
Enter a credit card, and copy your API key.

```bash
fcloud setup            # prompts for the key; optionally installs the agent skill
fcloud health           # verify connectivity
```

`fcloud setup` also installs (by default) the fcloud skill file for supported
coding agents (Cursor, Claude Code, Codex) so an agent can drive fcloud for you.
Use `--agents none` to skip that.

## Quick start

```bash
# Run a one-off command on a GPU
fcloud exec --sku gpu_1x_l4 nvidia-smi -L

# Upload a script and run it
fcloud run train.py --sku gpu_1x_l4

# Upload a project directory, run one script in it, pass arguments through
fcloud run . --script train.py --sku gpu_1x_l4 -- --epochs 50

# See what hardware is available
fcloud skus
```

`fcloud run <dir>` uploads the whole directory. Keep secrets, virtualenvs and
large data out of the tree you point it at.

## How the pieces fit

- **session** — a persistent `/workspace` filesystem, not a held GPU. It costs
  nothing until used; `exec`/`run`/`shell`/`upload` bring it online with its
  files intact, and `fcloud stop` halts spend but keeps the files. Address an
  existing one with `--on <SID>`.
- **volume** — a named folder you mount into a session with `--volume`; this is
  how data moves between sessions. Writes commit back as a new version when the
  session detaches or closes.
- **process** — work running inside a session. `exec`/`run` wait in the
  foreground; `spawn` returns a process id you then `wait`/`logs`/`kill`.
- **job** — a run-to-completion session with no saved filesystem; its durable
  outputs are its volumes and its logs.
- **sweep** — `fcloud map` fans one command out over many argument bindings as a
  durable batch you inspect with `fcloud sweep`.

## CLI

`fcloud help` prints the full grouped list; `fcloud help <command>` prints details.

```
Find hardware
  fcloud skus                                          List SKUs and prices
  fcloud health                                        Check API connectivity

Run code
  fcloud exec [--sku SKU] [--on SID] <cmd...>          Run a command on a host
  fcloud run <file|dir> [--sku SKU] [--on SID]         Upload and run a script
  fcloud shell [--sku SKU] [--on SID] [--volume NAME]  Interactive shell
  fcloud ssh <SID>                                     SSH into a session
  fcloud tunnel <SID> [--port PORT]                    SSH ProxyCommand tunnel

Background processes (inside a session)
  fcloud spawn --on SID <cmd...>                       Start a background process
  fcloud wait <SID> <PID> [--timeout DUR]              Wait for it; exit with its code
  fcloud logs <SID> [PID] [--follow]                   Show process output
  fcloud kill <SID> <PID>                              Kill it

Sessions (the persistent filesystem)
  fcloud create [--sku SKU] [--min-disk-gb N]          Create a session ($0 until used)
  fcloud sessions [SID] [--all] [--limit N]            List sessions
  fcloud history <SID> [--limit N]                     Session event history
  fcloud stop <SID>                                    Stop now (files kept)

Files
  fcloud upload [--on SID] <local> [remote]            Upload files
  fcloud download [--on SID] <remote> [local]          Download a file
  fcloud ls <SID> [path]                               List a session's files
  fcloud mount <SID> <mountpoint>                      Mount session files read-only (needs rclone)

Volumes (data that outlives a session)
  fcloud volume <create|list|files|download|cat|import|delete> ...

Batch
  fcloud job <run|ls|logs|wait|kill> ...               Run-to-completion jobs
  fcloud map [--sku SKU] -- <cmd {}> ::: v1,v2...      Fan a command out over bindings
  fcloud sweeps / fcloud sweep <status|logs|retry|cancel|wait> <name>

Setup
  fcloud setup [--token KEY] [--agents all|cursor|claude|codex|none]
  fcloud set_token <api-key>
  fcloud --version
```

All commands accept `--json` for machine-readable output.

`fcloud exec` returns bounded stdout by default. If `--json` reports
`stdout_truncated: true`, fetch the full log instead of rerunning:

```bash
fcloud logs <session-id> <process-id> --output all
fcloud logs <session-id> <process-id> --stream stderr --output all
```

## Python SDK

```python
import fcloud

client = fcloud.Client()

image = fcloud.Image.debian_slim().pip_install(["torch", "numpy"])
project = client.project("my-run", image=image)

with project.session(sku="gpu_1x_l4") as s:
    s.upload("./data", "data/")
    result = s.run(["python3", "/workspace/data/train.py"])
    print(result.stdout)
    if result.stdout_truncated:
        print(s.logs(result.process_id, output_range="all").output)
    weights = s.download("model.pt")
```

Errors raise `fcloud.FcloudError` (or a subclass such as `PaymentOverdueError`).

## Configuration

API key, in order of precedence:

1. `api_key=` passed to `Client()`
2. `FCLOUD_API_KEY` exported in the shell
3. Saved token in `~/.fcloud/token` (from `fcloud setup` / `fcloud set_token`)
4. `FCLOUD_API_KEY` in the nearest `.env` file (searched upward from the cwd)

API URL, in order of precedence:

1. `url=` passed to `Client()`
2. `FCLOUD_URL` exported in the shell
3. Saved URL in `~/.fcloud/url`
4. `FCLOUD_URL` in the nearest `.env` — only honoured when that same `.env` is
   also supplying the API key, so a checked-out repo can't redirect a saved
   token elsewhere
5. `https://fcloud-dispatcher.fly.dev`

Other environment switches:

| Variable | Effect |
|---|---|
| `FCLOUD_QUIET=1` | Suppress "still waiting" progress lines while a host is provisioned |
| `FCLOUD_QUEUE_TIMEOUT=<seconds>` | How long to wait for capacity before giving up (default 1200) |
| `FCLOUD_MIGRATE_RESTART=never` | Don't automatically re-run a command after a host rebuild (default `auto`) |
| `FCLOUD_INSECURE_HTTP=1` | Allow a plaintext `http://` API URL to a non-loopback host (refused by default — the API key would travel unencrypted). Loopback URLs never need this |
| `FCLOUD_TELEMETRY=0` | Disable all client telemetry. When enabled (the default), the client reports failures the backend cannot otherwise see — an uncaught CLI error, a queue-wait timeout, exhausted connect retries — as a fixed-allowlist payload (session id, event type, error class, truncated message, SKU/timing fields); never file contents, paths from OS errors, or credentials |

A `fcloud.json` at the project root can set defaults (image build steps, default
volumes). Note that fcloud will run the build steps it finds there, so treat a
cloned repo's `fcloud.json` the way you would its Dockerfile.

## Agent skill

`fcloud setup` installs `SKILL.md` by default (`--agents none` to skip) for supported coding agents. It
is the long-form, agent-oriented guide: workflow patterns, monitoring loops,
and anti-patterns.

## Development

```bash
pip install -e ".[dev]"
pytest
ruff check src tests
```

## License

Apache License 2.0 — see [LICENSE](LICENSE).
