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.9+ (see Python versions).
Install
curl -fsSL https://fcloud-home.vercel.app/install.sh | sh
That installs the CLI from PyPI (via uv or pipx), signs you in through
the browser, and installs the fcloud skill for coding agents on your machine.
With your own Python:
pip install fcloud-sdk
fcloud login
fcloud is prepaid — fcloud credits buy 25 before your first run, and
fcloud credits to see the balance.
Python versions
Every row runs the full test suite in CI on every push (the matrix in
.github/workflows/unit-tests.yml is the source of truth; a CI check fails
if pyproject.toml's classifiers drift from it).
| Python | Status |
|---|---|
| 3.14 | supported |
| 3.13 | supported |
| 3.12 | supported |
| 3.11 | supported |
| 3.10 | supported |
| 3.9 | supported (macOS command-line-tools Python, Debian 11) |
| 3.8 and older | not supported; the installer script bootstraps uv, which fetches a supported Python |
The installer only uses your system Python (pipx/pip) when it is 3.9 or
newer; otherwise it installs uv, which brings its own.
Setup
fcloud login opens https://fcloud-home.vercel.app to sign in (Google or
email) and add a card, then saves a key minted for this machine. Running any
fcloud command on a fresh install starts the same login.
fcloud login [--no-browser] [--agents auto|all|cursor|claude|codex|none]
fcloud set_token <key> # already have a key (CI, agents, a second machine)
fcloud setup # save a key you already have; install agent skills
fcloud health # verify connectivity
fcloud login installs the fcloud skill file for the coding agents it finds
(Cursor, Claude Code, Codex — --agents all for every one) so an agent can
drive fcloud for you. fcloud setup --agents none skips that.
Quick start
# 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
/workspacefilesystem, not a held GPU. It costs nothing until used;exec/run/shell/uploadbring it online with its files intact, andfcloud stophalts 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/runwait in the foreground;spawnreturns a process id you thenwait/logs/kill. - job — a run-to-completion session with no saved filesystem; its durable outputs are its volumes and its logs.
- sweep —
fcloud mapfans one command out over many argument bindings as a durable batch you inspect withfcloud 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 login [--no-browser] [--agents auto|all|cursor|claude|codex|none]
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:
fcloud logs <session-id> <process-id> --output all
fcloud logs <session-id> <process-id> --stream stderr --output all
Python SDK
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).
Porting from Modal
fcloud exposes a Modal-compatible surface, so most Modal scripts port with an
import rename:
import fcloud as modal # was: import modal
app = modal.App("demo")
image = modal.Image.debian_slim().pip_install("torch", "numpy")
@app.function(image=image, gpu="H100", timeout=600)
def train(steps: int) -> float:
...
@app.cls(gpu="L4", volumes={"/data": modal.Volume.from_name("weights", create_if_missing=True)})
class Model:
@modal.enter()
def load(self): ...
@modal.method()
def predict(self, x): ...
@app.local_entrypoint()
def main(steps: int = 100):
print(train.remote(steps))
print(Model().predict.remote(1))
Run it with fcloud run demo.py [--steps 500] (the Modal-style demo.py::name
picks an entrypoint or function). Each (gpu, image, volumes) combination gets
one warm session; .remote() pickles the args, runs the function on the host
and returns the pickled result, streaming stdout back live.
Supported: App, @app.function / @app.cls / @app.local_entrypoint,
.remote() / .spawn() / .map(), Image.* (varargs or list),
Volume.from_name, Secret.from_dict / from_dotenv / from_local_environ,
gpu="H100", "A100-80GB:8", etc. cpu=, memory=, retries= and similar
options are accepted and ignored with a warning.
Not supported: web endpoints, Dict / Queue, schedules, sandboxes,
Secret.from_name (no hosted secret store), modal deploy. .map() runs
inputs sequentially on one session; use fcloud map for real fan-out.
Configuration
API key, in order of precedence:
api_key=passed toClient()FCLOUD_API_KEYexported in the shell- Saved token in
~/.fcloud/token(fromfcloud setup/fcloud set_token) FCLOUD_API_KEYin the nearest.envfile (searched upward from the cwd)
API URL, in order of precedence:
url=passed toClient()FCLOUD_URLexported in the shell- Saved URL in
~/.fcloud/url FCLOUD_URLin the nearest.env— only honoured when that same.envis also supplying the API key, so a checked-out repo can't redirect a saved token elsewherehttps://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_CHECKPOINT=off |
Default checkpoint/restore policy for new sessions. off: a preempted session rebuilds cold on any available host (/workspace kept, processes lost) instead of restoring pinned to its checkpoint's region. Per-session: --checkpoint/--no-checkpoint; per-user: fcloud config set checkpoint off; per-project: fcloud.json "checkpoint": false |
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, checkpoint policy); fcloud config stores per-user defaults in
~/.fcloud/config.json. 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
pip install -e ".[dev]"
pytest
ruff check src tests
License
Apache License 2.0 — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fcloud_sdk-0.3.0.tar.gz.
File metadata
- Download URL: fcloud_sdk-0.3.0.tar.gz
- Upload date:
- Size: 421.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48bd07fd7f994065133b4dced4d144d786c058fcc4084e210be345f1e11f4f83
|
|
| MD5 |
602d5e8edea44c98f183d1c7b7ba9039
|
|
| BLAKE2b-256 |
1aba0222c512c2a89fdba37b600e8f0427decc4327e0af6ab0422213f40c6c9d
|
File details
Details for the file fcloud_sdk-0.3.0-py3-none-any.whl.
File metadata
- Download URL: fcloud_sdk-0.3.0-py3-none-any.whl
- Upload date:
- Size: 303.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
218fa257ced15e5bacfc7bf536b1853f34be40c358e49259603988d88c4fefd6
|
|
| MD5 |
f4238909d91a5188e9d6a92584acf77e
|
|
| BLAKE2b-256 |
fa5719cd032a9cd82ea8b14f5446aa4428280689f31775800fb1baed8c715760
|