fcloud-sdk 0.1.3__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fcloud_sdk-0.2.1/CHANGELOG.md +222 -0
- {fcloud_sdk-0.1.3/src/fcloud_sdk.egg-info → fcloud_sdk-0.2.1}/PKG-INFO +23 -8
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/README.md +22 -7
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/SKILL.md +129 -13
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/pyproject.toml +2 -2
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/SKILL.md +129 -13
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/__init__.py +4 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/__main__.py +2 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/_direct_bridge.py +23 -1
- fcloud_sdk-0.2.1/src/fcloud/autoresearch/SETUP.md +67 -0
- fcloud_sdk-0.2.1/src/fcloud/autoresearch/program.template.md +159 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/__init__.py +2 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/attach.py +43 -9
- fcloud_sdk-0.2.1/src/fcloud/cli/autoresearch.py +36 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/common.py +63 -7
- fcloud_sdk-0.2.1/src/fcloud/cli/config_cmd.py +130 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/context.py +50 -9
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/exec_cmd.py +42 -9
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/help.py +8 -1
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/interactive.py +30 -7
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/job.py +88 -10
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/main.py +52 -3
- fcloud_sdk-0.2.1/src/fcloud/cli/output.py +45 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/processes.py +223 -26
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/run.py +42 -11
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/sessions.py +246 -39
- fcloud_sdk-0.2.1/src/fcloud/cli/setup.py +100 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/sweep.py +432 -25
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/sweep_harvest.py +13 -3
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/sweep_watch.py +81 -20
- fcloud_sdk-0.2.1/src/fcloud/cli/usage.py +67 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/volume.py +5 -1
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/wait.py +7 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli_args.py +16 -3
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/client.py +58 -13
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/config.py +90 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/errors.py +35 -0
- fcloud_sdk-0.2.1/src/fcloud/login.py +236 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/session.py +15 -3
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/setup_cmd.py +18 -3
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/shell.py +9 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/sweeps.py +54 -3
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/types.py +6 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/v2_connect.py +87 -10
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/volumes.py +23 -3
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1/src/fcloud_sdk.egg-info}/PKG-INFO +23 -8
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud_sdk.egg-info/SOURCES.txt +24 -0
- fcloud_sdk-0.2.1/tests/test_autoresearch.py +21 -0
- fcloud_sdk-0.2.1/tests/test_checkpoint_option.py +208 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_client.py +10 -9
- fcloud_sdk-0.2.1/tests/test_config_cmd.py +75 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_direct_bridge.py +23 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_exec_attach_retry.py +24 -2
- fcloud_sdk-0.2.1/tests/test_first_run_login.py +80 -0
- fcloud_sdk-0.2.1/tests/test_job_ls.py +99 -0
- fcloud_sdk-0.2.1/tests/test_kill_records_first.py +236 -0
- fcloud_sdk-0.2.1/tests/test_login.py +202 -0
- fcloud_sdk-0.2.1/tests/test_logs_unknown_pid.py +84 -0
- fcloud_sdk-0.2.1/tests/test_map_dag.py +40 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_map_default_image.py +3 -0
- fcloud_sdk-0.2.1/tests/test_map_window_flags.py +40 -0
- fcloud_sdk-0.2.1/tests/test_no_resume_gate.py +51 -0
- fcloud_sdk-0.2.1/tests/test_resume_volume_validation.py +86 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_run_wait_flags.py +2 -2
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_secret_resolution.py +2 -2
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_sessions_live_statuses.py +17 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_shell_volumes.py +1 -1
- fcloud_sdk-0.2.1/tests/test_spend.py +203 -0
- fcloud_sdk-0.2.1/tests/test_stop_refused_classification.py +95 -0
- fcloud_sdk-0.2.1/tests/test_sweep_boost.py +53 -0
- fcloud_sdk-0.2.1/tests/test_sweep_harvest.py +211 -0
- fcloud_sdk-0.2.1/tests/test_sweep_lifecycle_ux.py +523 -0
- fcloud_sdk-0.2.1/tests/test_sweep_retry_and_kill_truth.py +90 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_v2_connect.py +86 -2
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_volume_cli_hardening.py +9 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_volume_download_delete.py +16 -1
- fcloud_sdk-0.2.1/tests/test_volume_preflight.py +61 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_wait.py +26 -0
- fcloud_sdk-0.1.3/CHANGELOG.md +0 -106
- fcloud_sdk-0.1.3/src/fcloud/cli/output.py +0 -17
- fcloud_sdk-0.1.3/src/fcloud/cli/setup.py +0 -44
- fcloud_sdk-0.1.3/tests/test_sweep_lifecycle_ux.py +0 -145
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/CONTRIBUTING.md +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/LICENSE +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/MANIFEST.in +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/NOTICE +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/setup.cfg +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/_legacy_env.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/console.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/files.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/hardware.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/migration.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/mount.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/registry.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/cli/ssh.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/client_projects.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/client_sessions.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/client_volumes.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/direct.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/fileset.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/image.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/job.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/providers/__init__.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/providers/requests_http.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/py.typed +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/tunnel.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/version.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud/volume_wait.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud_sdk.egg-info/dependency_links.txt +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud_sdk.egg-info/entry_points.txt +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud_sdk.egg-info/requires.txt +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/fcloud_sdk.egg-info/top_level.txt +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/src/foom/__init__.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/conftest.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_cli_args.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_cli_dispatch.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_cli_guards.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_cli_help.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_client_contracts_c.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_client_host_frames_contract.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_client_http_contract.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_client_telemetry.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_config.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_default_image.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_direct_fake_host.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_dotenv_precedence.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_download_volume_hint.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_emit_pid.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_fileset.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_job.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_legacy_shim.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_progress_narration.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_provider_env_default.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_queued_reason_render.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_rate_limit_ride.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_rebuild_respawn.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_ride_cap.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_run_migration.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_run_volume_collision.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_session_truth.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_sessions_point_lookup.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_setup_cmd.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_shell_env.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_shell_interrupt.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_skus.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_sweep_cost_optin.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_sweep_status_view.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_sweeps_binding.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_tunnel.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_types.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_upload_s3_path.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_volume_resolution.py +0 -0
- {fcloud_sdk-0.1.3 → fcloud_sdk-0.2.1}/tests/test_volume_wait.py +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `fcloud` Python SDK and CLI are recorded here.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
|
|
5
|
+
versions follow [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.2.1] - 2026-09-14
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `fcloud login`: sign in through the browser (device authorization). Shows a
|
|
13
|
+
short code, opens the approval page, and saves a key minted for this
|
|
14
|
+
machine (named `cli:<hostname>`); then installs the fcloud skill for the
|
|
15
|
+
coding agents present on the machine (`--agents auto`, the default; also
|
|
16
|
+
`all`, a list, or `none`). `--no-browser` prints the URL and code instead
|
|
17
|
+
of opening a browser. A fresh install's first command starts the same
|
|
18
|
+
login, and `fcloud setup` with no key delegates to it.
|
|
19
|
+
- Spend visibility: `fcloud sessions` shows `$/HR` (the rate billed on the
|
|
20
|
+
session's open usage interval while a host is held, 0 when cold), `SPENT`
|
|
21
|
+
(compute charged so far) and `AGE` (time on its current host) per row plus
|
|
22
|
+
a "Spending now" footer; `--json` rows carry `usd_per_hour`, `spent_usd`
|
|
23
|
+
and `host_age_seconds` (SDK: `Client.session_cost`). New `fcloud usage [--since DUR|TS] [--until TS]`
|
|
24
|
+
reports what the account was charged over a window (default 30 days) by
|
|
25
|
+
resource and session (SDK: `Client.billing_usage`).
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- `fcloud job ls` shows each job's COMMAND and EXIT code (from its process
|
|
29
|
+
index; `--json` rows carry `command` and `exit_code`), so rows are
|
|
30
|
+
tellable apart and failures visible without opening each job.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- `fcloud logs <sid> <pid>` with a pid the dispatcher has no record of now
|
|
34
|
+
exits 1 (`process_not_found`) like `wait` and `kill`, instead of printing
|
|
35
|
+
an empty stream with exit 0 (and `status: ""` in `--json`) that a poller
|
|
36
|
+
read as a finished, silent process. A just-spawned pid gets a few seconds
|
|
37
|
+
to reach the durable index before it is called unknown.
|
|
38
|
+
- `fcloud wait` with a `--timeout` shorter than the unknown-pid grace window
|
|
39
|
+
exits 1 for an unknown pid, not 75 (retry), so scripted callers stop
|
|
40
|
+
retrying a typo forever.
|
|
41
|
+
- Cold starts of `run`/`exec`/`job run` no longer dump every host status
|
|
42
|
+
frame (`⟵ session_status: building (phase_change) setup_timing ...`);
|
|
43
|
+
the fresh-allocation and reconnect paths now use the same quiet printer
|
|
44
|
+
as warm attaches.
|
|
45
|
+
- `fcloud sweep harvest` no longer pulls the session's virtual `_logs/`
|
|
46
|
+
directory (`_logs/processes.json`) for a results glob like `*.json`; name
|
|
47
|
+
`_logs/` in the glob to fetch logs.
|
|
48
|
+
- `fcloud sessions` sizes the HOST and SKU columns to the data (27-char AWS
|
|
49
|
+
host ids overflowed the fixed width on every row).
|
|
50
|
+
- `fcloud volume list` shows each volume's last update time.
|
|
51
|
+
- SKILL.md documents `fcloud sessions --limit N`.
|
|
52
|
+
|
|
53
|
+
## [0.2.0] - 2026-09-08
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
- Per-session checkpoint/restore opt-out: `--no-checkpoint` on
|
|
57
|
+
`create`/`exec`/`run`/`shell` (SDK: `checkpoint=False` on
|
|
58
|
+
`Project.session`/`cold_session`, `Client.create_session`/
|
|
59
|
+
`create_cold_session`). A preempted opt-out session is rebuilt cold on any
|
|
60
|
+
available host (`/workspace` kept, running processes lost) instead of being
|
|
61
|
+
checkpointed and restored pinned to the region its checkpoint lives in.
|
|
62
|
+
Defaults resolve `--checkpoint`/`--no-checkpoint` → `FCLOUD_CHECKPOINT` →
|
|
63
|
+
`fcloud.json` `"checkpoint"` → the new `fcloud config set checkpoint on|off`
|
|
64
|
+
user default (`~/.fcloud/config.json`) → server default (on).
|
|
65
|
+
`SessionInfo.checkpoint` and `fcloud sessions --json` expose the policy; the
|
|
66
|
+
create fails loudly against a dispatcher too old to honour the opt-out.
|
|
67
|
+
- `--no-resume` on `exec`/`run`/`shell`: refuse to wake a cold (stopped)
|
|
68
|
+
session instead of transparently re-provisioning its hardware. The refusal
|
|
69
|
+
exits 1 with a typed `session_cold` error naming the session and the SKU a
|
|
70
|
+
resume would have provisioned. SDK: `Client.attach_session(...,
|
|
71
|
+
resume=False)` raises the new `fcloud.SessionColdError`.
|
|
72
|
+
- Pipelines: `fcloud map --after SWEEP[,SWEEP]` (SDK: `client.map(...,
|
|
73
|
+
after=handle_or_name, after_strict=…)`) holds a sweep in the new
|
|
74
|
+
`waiting` state until the named sweeps finish, then launches it — the
|
|
75
|
+
barrier is durable server-side, so a generate → train → eval chain
|
|
76
|
+
submits up front and the client can disconnect. An upstream failure
|
|
77
|
+
fails the downstream sweep (`upstream_failed:<name>`; re-arm with
|
|
78
|
+
`fcloud sweep retry <name> --all`); a partially-succeeded upstream
|
|
79
|
+
counts as finished unless `--after-strict`.
|
|
80
|
+
- `--volume NAME[:MOUNT][:ro]` (also fcloud.json `"read_only": true` or
|
|
81
|
+
the `name:/mount:ro` string form) attaches a volume read-only: the
|
|
82
|
+
session sees it, but its writes are discarded at close (no commit).
|
|
83
|
+
- `fcloud autoresearch init`: scaffolds a karpathy/autoresearch-style keep/discard
|
|
84
|
+
research loop (agent setup guide + `program.md` template) that runs experiments
|
|
85
|
+
on a persistent fcloud session.
|
|
86
|
+
The loop uploads `results.tsv` to the session each experiment; the dashboard's
|
|
87
|
+
session page then shows an Autoresearch tab (metric chart + results table).
|
|
88
|
+
- Skip-the-line boost: `fcloud sweep boost <name>` / pressing `s` in
|
|
89
|
+
`fcloud sweep status --watch` (offered while blocked on capacity) moves a
|
|
90
|
+
sweep to the fast claim lane; queued tasks re-lane immediately
|
|
91
|
+
(`SweepHandle.boost()` in the SDK). Freed machines alternate fast/free.
|
|
92
|
+
- `fcloud sweep status` explains WHY a sweep is waiting: a `why:` line under
|
|
93
|
+
`blocked on capacity` names the line (`3 session(s) ahead in the gpu_1x_l4
|
|
94
|
+
queue (1 fast-lane)`) and/or the platform (`a new machine is being
|
|
95
|
+
provisioned`, `no capacity ... (stockout)`, `cloud quota exhausted`, ...),
|
|
96
|
+
from the new `blocked.sku/queued_reason/queued_ahead/fast_ahead` status
|
|
97
|
+
fields; a `state: waiting` (pipeline) sweep names the upstream sweeps it
|
|
98
|
+
holds for. Older dispatchers omit the fields and status reads as before.
|
|
99
|
+
- Async sweep scheduling: `fcloud map --not-before WHEN` (park until), `--by WHEN`
|
|
100
|
+
(deadline; opportunistic idle-fill until `deadline - --runtime - pad`, then
|
|
101
|
+
normal launch) and `--runtime DUR` (per-task estimate, default 1h).
|
|
102
|
+
`fcloud sweep status` shows the window phase; a missed deadline marks the
|
|
103
|
+
sweep `deadline_missed` (webhook `job.deadline_missed`) but never cancels it.
|
|
104
|
+
- First-run login prompt: with no API key configured, the CLI offers to open
|
|
105
|
+
the dashboard login and store the key instead of failing with a bare error.
|
|
106
|
+
- CLI errors carry typed error codes and the request id; the client never
|
|
107
|
+
provisions hardware for a request the server would reject.
|
|
108
|
+
|
|
109
|
+
### Changed
|
|
110
|
+
- Resuming a cold session now always prints one stderr line (`session <sid>
|
|
111
|
+
is cold — resuming (provisions <sku>); pass --no-resume to refuse`), even
|
|
112
|
+
when stderr is not a TTY or `FCLOUD_QUIET` is set — waking billed hardware
|
|
113
|
+
is a spend event, and non-TTY runs used to do it silently.
|
|
114
|
+
- Failed map task attempts now retry with a growing delay (45s × attempt,
|
|
115
|
+
capped at 10m) instead of relaunching immediately; preemption requeues
|
|
116
|
+
remain immediate and still don't consume the retry budget.
|
|
117
|
+
|
|
118
|
+
### Fixed
|
|
119
|
+
- `fcloud map --volume name:/path` sent the custom mount path under a key
|
|
120
|
+
the server ignores, silently mounting the volume at its default path.
|
|
121
|
+
Custom mount paths now apply to sweep task sessions.
|
|
122
|
+
|
|
123
|
+
## [0.1.3] - 2026-08-27
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
- `fcloud setup` installs the agent skill for all agents by default (Enter or
|
|
127
|
+
non-interactive stdin = `all`); `--agents none` opts out.
|
|
128
|
+
|
|
129
|
+
## [0.1.2] - 2026-08-27
|
|
130
|
+
|
|
131
|
+
### Changed
|
|
132
|
+
- README wording.
|
|
133
|
+
|
|
134
|
+
## [0.1.1] - 2026-08-27
|
|
135
|
+
|
|
136
|
+
### Changed
|
|
137
|
+
- README: sign up on the website and paste your API key; the editable
|
|
138
|
+
checkout install instructions are gone.
|
|
139
|
+
|
|
140
|
+
## [0.1.0] - 2026-08-27
|
|
141
|
+
|
|
142
|
+
### Changed
|
|
143
|
+
- Renamed: the package is `fcloud-sdk`, the import is `fcloud`, the CLI is
|
|
144
|
+
`fcloud`, env vars are `FCLOUD_*`, config lives in `~/.fcloud`, project
|
|
145
|
+
files are `fcloud.json`, new keys are `fcloud_sk_…`, and the client sends
|
|
146
|
+
`X-Fcloud-Client*` headers. Everything old keeps working: `import foom`,
|
|
147
|
+
the `foom` command, `FOOM_*`, `~/.foom`, `foom.json`, `foom_sk_` keys and
|
|
148
|
+
`foom.FoomError`. Map tasks now receive `FCLOUD_TASK_ID` /
|
|
149
|
+
`FCLOUD_WORLD_SIZE` / `FCLOUD_JOB` (the `FOOM_*` names are gone).
|
|
150
|
+
|
|
151
|
+
### Added
|
|
152
|
+
- `foom sweep harvest <name> <remote-glob> <local-dir>` — download every
|
|
153
|
+
task's matching outputs in one command. Sessions are resolved from the
|
|
154
|
+
sweep and local paths are task-keyed (`<local-dir>/task-<index>/<path>`,
|
|
155
|
+
or `--flat`), replacing the per-sweep script that parsed status JSON for
|
|
156
|
+
session ids and ran N `foom download` calls. `--all-states` includes
|
|
157
|
+
failed and canceled tasks.
|
|
158
|
+
- `foom sweep status --watch [--interval S]` — the human live view,
|
|
159
|
+
repainted in place until the sweep is terminal. Appends instead of
|
|
160
|
+
repainting when stdout is not a terminal.
|
|
161
|
+
- `foom stop --wait [--timeout SECONDS]` — block until the workspace
|
|
162
|
+
manifest is durable, instead of polling `foom sessions` for `state=cold`.
|
|
163
|
+
`foom map --from <sid>` needs that manifest; the default timeout is 300s
|
|
164
|
+
and the command exits 1 if the wait expires (the stop itself stands).
|
|
165
|
+
- The `foom sweep status --json` document is now a documented, versioned
|
|
166
|
+
contract (`schema_version: 1`) — see `docs/sweep-status-schema.md`.
|
|
167
|
+
Additive changes keep the version; a removal or rename bumps it.
|
|
168
|
+
- Every request now carries `X-Foom-Client` / `X-Foom-Client-Version`, and a
|
|
169
|
+
client below the deployment's supported floor is rejected with HTTP 426 and
|
|
170
|
+
the new `foom.ClientTooOldError`, which names the upgrade command. This
|
|
171
|
+
replaces the previous failure mode for a stale client, an S3
|
|
172
|
+
`SignatureDoesNotMatch` on every >5 MiB upload that read as a credential
|
|
173
|
+
problem.
|
|
174
|
+
|
|
175
|
+
### Changed
|
|
176
|
+
- `foom upload` now names the files that take the pre-signed cloud-storage
|
|
177
|
+
path (>5 MiB) rather than only the total, and names them again in the error
|
|
178
|
+
when that path fails — so a broken large-file upload is attributable to a
|
|
179
|
+
file, not to the command. `Session.upload()` returns them as `s3_files`
|
|
180
|
+
alongside `inline_files` and `s3_threshold_bytes`.
|
|
181
|
+
|
|
182
|
+
## [0.1.0] — first public release
|
|
183
|
+
|
|
184
|
+
### Added
|
|
185
|
+
- `foom` CLI: sessions, exec/run/shell/ssh/tunnel, background processes
|
|
186
|
+
(spawn/wait/logs/kill), file transfer (upload/download/ls/mount), volumes,
|
|
187
|
+
run-to-completion jobs, and `foom map` sweeps.
|
|
188
|
+
- Python SDK: `Client`, `Project`, `Session`, `Job`, `SweepHandle`, `Image`.
|
|
189
|
+
- `foom setup` installs the agent skill (`SKILL.md`) for Cursor, Claude Code
|
|
190
|
+
and Codex.
|
|
191
|
+
- `foom --version` and `foom.__version__`.
|
|
192
|
+
- Directory uploads skip hidden entries, dependency/cache directories and
|
|
193
|
+
symlinked files by default; `--include-hidden` / `--follow-symlinks` (CLI)
|
|
194
|
+
and `include_hidden=` / `follow_symlinks=` (SDK) opt back in.
|
|
195
|
+
- `FOOM_TELEMETRY=0` disables the best-effort CLI crash report.
|
|
196
|
+
|
|
197
|
+
### Removed
|
|
198
|
+
Relative to the pre-release internal SDK (nothing here was ever on PyPI):
|
|
199
|
+
- Public names `MigrationInfo`, `MigrationStatus`, `SyncProgress`, the
|
|
200
|
+
`FcloudError` and `JobHandle` aliases (`FoomError` / `SweepHandle` remain),
|
|
201
|
+
and the `Session.migrate()` / `Client.watch()` / `Client.list_session_files()`
|
|
202
|
+
/ `Client.download_file()` helpers — the operator-initiated migration
|
|
203
|
+
surface is not part of the public client.
|
|
204
|
+
- `Image.add_local_file()`, `Image.add_local_dir()`, `Image.copy()`,
|
|
205
|
+
`Image.workdir()` — use `Session.upload()` / `foom upload` for local files
|
|
206
|
+
and the `workdir=` argument on exec.
|
|
207
|
+
- Legacy `~/.fcloud/token`, `~/.fcloud/url` and `fcloud.json` lookups
|
|
208
|
+
(`~/.foom/*` and `foom.json` are the supported forms). `FCLOUD_API_KEY` /
|
|
209
|
+
`FCLOUD_URL` are still accepted as aliases of `FOOM_API_KEY` / `FOOM_URL`.
|
|
210
|
+
- Internal modules `foom.upload`, `foom.stream`, `foom.jobs`, `foom.client_ext`
|
|
211
|
+
and the `s3_uploader` / `websockets_transport` providers, with the
|
|
212
|
+
`websockets` dependency they pulled in.
|
|
213
|
+
- `DirectClient.run_streaming()` (no callers). `DirectClient.execute()` is
|
|
214
|
+
kept — internal harnesses use it.
|
|
215
|
+
|
|
216
|
+
### Security
|
|
217
|
+
- Only `FOOM_*` keys from a project `.env` are imported into the process
|
|
218
|
+
environment; other keys stay reachable by name via `--secret KEY`.
|
|
219
|
+
- A plaintext (`ws://`) host address is refused when the API was reached over
|
|
220
|
+
`https://`; a plaintext API URL to a non-local host warns.
|
|
221
|
+
- `foom ssh` quotes its ProxyCommand and validates the session id before using
|
|
222
|
+
it in filesystem paths.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fcloud-sdk
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Python SDK and CLI for the fcloud GPU compute platform
|
|
5
5
|
Author: fcloud
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -43,23 +43,35 @@ Requires Python 3.10+.
|
|
|
43
43
|
|
|
44
44
|
## Install
|
|
45
45
|
|
|
46
|
+
```bash
|
|
47
|
+
curl -fsSL https://fcloud-home.vercel.app/install.sh | sh
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That installs the CLI from PyPI (via `uv` or `pipx`), signs you in through
|
|
51
|
+
the browser, and installs the fcloud skill for coding agents on your machine.
|
|
52
|
+
With your own Python:
|
|
53
|
+
|
|
46
54
|
```bash
|
|
47
55
|
pip install fcloud-sdk
|
|
56
|
+
fcloud login
|
|
48
57
|
```
|
|
49
58
|
|
|
50
59
|
## Setup
|
|
51
60
|
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
`fcloud login` opens https://fcloud-home.vercel.app to sign in (Google or
|
|
62
|
+
email) and add a card, then saves a key minted for this machine. Running any
|
|
63
|
+
`fcloud` command on a fresh install starts the same login.
|
|
54
64
|
|
|
55
65
|
```bash
|
|
56
|
-
fcloud
|
|
66
|
+
fcloud login [--no-browser] [--agents auto|all|cursor|claude|codex|none]
|
|
67
|
+
fcloud set_token <key> # already have a key (CI, agents, a second machine)
|
|
68
|
+
fcloud setup # save a key you already have; install agent skills
|
|
57
69
|
fcloud health # verify connectivity
|
|
58
70
|
```
|
|
59
71
|
|
|
60
|
-
`fcloud
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
`fcloud login` installs the fcloud skill file for the coding agents it finds
|
|
73
|
+
(Cursor, Claude Code, Codex — `--agents all` for every one) so an agent can
|
|
74
|
+
drive fcloud for you. `fcloud setup --agents none` skips that.
|
|
63
75
|
|
|
64
76
|
## Quick start
|
|
65
77
|
|
|
@@ -139,6 +151,7 @@ Batch
|
|
|
139
151
|
fcloud sweeps / fcloud sweep <status|logs|retry|cancel|wait> <name>
|
|
140
152
|
|
|
141
153
|
Setup
|
|
154
|
+
fcloud login [--no-browser] [--agents auto|all|cursor|claude|codex|none]
|
|
142
155
|
fcloud setup [--token KEY] [--agents all|cursor|claude|codex|none]
|
|
143
156
|
fcloud set_token <api-key>
|
|
144
157
|
fcloud --version
|
|
@@ -201,11 +214,13 @@ Other environment switches:
|
|
|
201
214
|
| `FCLOUD_QUIET=1` | Suppress "still waiting" progress lines while a host is provisioned |
|
|
202
215
|
| `FCLOUD_QUEUE_TIMEOUT=<seconds>` | How long to wait for capacity before giving up (default 1200) |
|
|
203
216
|
| `FCLOUD_MIGRATE_RESTART=never` | Don't automatically re-run a command after a host rebuild (default `auto`) |
|
|
217
|
+
| `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` |
|
|
204
218
|
| `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 |
|
|
205
219
|
| `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 |
|
|
206
220
|
|
|
207
221
|
A `fcloud.json` at the project root can set defaults (image build steps, default
|
|
208
|
-
volumes
|
|
222
|
+
volumes, checkpoint policy); `fcloud config` stores per-user defaults in
|
|
223
|
+
`~/.fcloud/config.json`. Note that fcloud will run the build steps it finds there, so treat a
|
|
209
224
|
cloned repo's `fcloud.json` the way you would its Dockerfile.
|
|
210
225
|
|
|
211
226
|
## Agent skill
|
|
@@ -9,23 +9,35 @@ Requires Python 3.10+.
|
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
|
+
```bash
|
|
13
|
+
curl -fsSL https://fcloud-home.vercel.app/install.sh | sh
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
That installs the CLI from PyPI (via `uv` or `pipx`), signs you in through
|
|
17
|
+
the browser, and installs the fcloud skill for coding agents on your machine.
|
|
18
|
+
With your own Python:
|
|
19
|
+
|
|
12
20
|
```bash
|
|
13
21
|
pip install fcloud-sdk
|
|
22
|
+
fcloud login
|
|
14
23
|
```
|
|
15
24
|
|
|
16
25
|
## Setup
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
`fcloud login` opens https://fcloud-home.vercel.app to sign in (Google or
|
|
28
|
+
email) and add a card, then saves a key minted for this machine. Running any
|
|
29
|
+
`fcloud` command on a fresh install starts the same login.
|
|
20
30
|
|
|
21
31
|
```bash
|
|
22
|
-
fcloud
|
|
32
|
+
fcloud login [--no-browser] [--agents auto|all|cursor|claude|codex|none]
|
|
33
|
+
fcloud set_token <key> # already have a key (CI, agents, a second machine)
|
|
34
|
+
fcloud setup # save a key you already have; install agent skills
|
|
23
35
|
fcloud health # verify connectivity
|
|
24
36
|
```
|
|
25
37
|
|
|
26
|
-
`fcloud
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
`fcloud login` installs the fcloud skill file for the coding agents it finds
|
|
39
|
+
(Cursor, Claude Code, Codex — `--agents all` for every one) so an agent can
|
|
40
|
+
drive fcloud for you. `fcloud setup --agents none` skips that.
|
|
29
41
|
|
|
30
42
|
## Quick start
|
|
31
43
|
|
|
@@ -105,6 +117,7 @@ Batch
|
|
|
105
117
|
fcloud sweeps / fcloud sweep <status|logs|retry|cancel|wait> <name>
|
|
106
118
|
|
|
107
119
|
Setup
|
|
120
|
+
fcloud login [--no-browser] [--agents auto|all|cursor|claude|codex|none]
|
|
108
121
|
fcloud setup [--token KEY] [--agents all|cursor|claude|codex|none]
|
|
109
122
|
fcloud set_token <api-key>
|
|
110
123
|
fcloud --version
|
|
@@ -167,11 +180,13 @@ Other environment switches:
|
|
|
167
180
|
| `FCLOUD_QUIET=1` | Suppress "still waiting" progress lines while a host is provisioned |
|
|
168
181
|
| `FCLOUD_QUEUE_TIMEOUT=<seconds>` | How long to wait for capacity before giving up (default 1200) |
|
|
169
182
|
| `FCLOUD_MIGRATE_RESTART=never` | Don't automatically re-run a command after a host rebuild (default `auto`) |
|
|
183
|
+
| `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` |
|
|
170
184
|
| `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 |
|
|
171
185
|
| `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 |
|
|
172
186
|
|
|
173
187
|
A `fcloud.json` at the project root can set defaults (image build steps, default
|
|
174
|
-
volumes
|
|
188
|
+
volumes, checkpoint policy); `fcloud config` stores per-user defaults in
|
|
189
|
+
`~/.fcloud/config.json`. Note that fcloud will run the build steps it finds there, so treat a
|
|
175
190
|
cloned repo's `fcloud.json` the way you would its Dockerfile.
|
|
176
191
|
|
|
177
192
|
## Agent skill
|
|
@@ -25,6 +25,9 @@ fcloud set_token <api_key> # one-time; saves to ~/.fcloud/token
|
|
|
25
25
|
fcloud health # verify connectivity
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
(A human sets up with `fcloud login`, which signs in through the browser and
|
|
29
|
+
mints a key for the machine; agents use `set_token` with a key they were given.)
|
|
30
|
+
|
|
28
31
|
Token resolution order:
|
|
29
32
|
|
|
30
33
|
1. `api_key=` parameter to `Client()`
|
|
@@ -303,7 +306,8 @@ filesystem later; a **job** for batch/CI-style runs with declared outputs.
|
|
|
303
306
|
| Command | Description |
|
|
304
307
|
| ----------------------------- | ---------------------------------------------------- |
|
|
305
308
|
| `fcloud create [--sku SKU]` | Create a session (cold — $0, no host, until first used) |
|
|
306
|
-
| `fcloud sessions [--all]`
|
|
309
|
+
| `fcloud sessions [--all] [--limit N]` | List sessions with `$/HR` (billed rate), `SPENT` (compute so far) and `AGE` (time on its host) per row and a spending-now total (`--all --json` can be large; bound it with `--limit`) |
|
|
310
|
+
| `fcloud usage [--since 24h]` | What the account has been charged over a window (default 30 days), by resource and session |
|
|
307
311
|
| `fcloud stop <session-id> [--wait]` | Stop a session now: halt GPU spend (files kept). `--wait` blocks until the workspace manifest is durable |
|
|
308
312
|
|
|
309
313
|
|
|
@@ -336,6 +340,39 @@ once**, keep one client attached per box for its whole run — e.g. N parallel
|
|
|
336
340
|
creating N sessions and attending to them one at a time, which lets the idle
|
|
337
341
|
ones lose their hosts.
|
|
338
342
|
|
|
343
|
+
### Checkpoint/restore on preemption (and how to turn it off)
|
|
344
|
+
|
|
345
|
+
Sessions run on spot capacity. By default, when a host is reclaimed fcloud
|
|
346
|
+
**checkpoints** the live sandbox (GPU state included) and **restores** it on a
|
|
347
|
+
fresh box, so running processes continue. The restore is pinned to the region
|
|
348
|
+
the checkpoint lives in (cross-region transfer of a multi-GB image is not free),
|
|
349
|
+
so a restore can wait in `awaiting_restore_capacity` until that region has spot
|
|
350
|
+
capacity again.
|
|
351
|
+
|
|
352
|
+
If you would rather get **any** available host quickly and re-run your command
|
|
353
|
+
yourself, turn checkpoint/restore off for the session. A preempted
|
|
354
|
+
`--no-checkpoint` session is rebuilt cold on any host in any region:
|
|
355
|
+
`/workspace` is preserved (synced before the box dies), running processes are
|
|
356
|
+
lost, and the session carries `state_loss_reason=spot_preempt_checkpoint_disabled`
|
|
357
|
+
in `fcloud sessions --json`. `fcloud run`/`exec` re-run the command after a
|
|
358
|
+
rebuild (`FCLOUD_MIGRATE_RESTART`), so a resumable script (one that reloads its
|
|
359
|
+
own checkpoints from `/workspace` or a volume) is the natural pairing.
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
fcloud run train.py --sku gpu_1x_h100 --no-checkpoint # this session only
|
|
363
|
+
fcloud create --sku gpu_1x_l4 --no-checkpoint # for the session's life
|
|
364
|
+
fcloud config set checkpoint off # my default, every project
|
|
365
|
+
fcloud config get checkpoint # -> off
|
|
366
|
+
fcloud config unset checkpoint # back to on
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Precedence, strongest first: `--checkpoint`/`--no-checkpoint` (or SDK
|
|
370
|
+
`checkpoint=True/False`) → `FCLOUD_CHECKPOINT=on|off` → `fcloud.json`
|
|
371
|
+
`"checkpoint": false` → `fcloud config set checkpoint` → server default (on).
|
|
372
|
+
The policy is fixed when the session is **created**; `--on <sid>` keeps the
|
|
373
|
+
session's existing policy. Jobs (`fcloud job`, `fcloud map`) never checkpoint.
|
|
374
|
+
`fcloud sessions` marks opted-out sessions `[no-checkpoint]`.
|
|
375
|
+
|
|
339
376
|
### File Transfer
|
|
340
377
|
|
|
341
378
|
| Command | Description | Needs active session? |
|
|
@@ -470,9 +507,12 @@ detach or session close.
|
|
|
470
507
|
Volumes are attached
|
|
471
508
|
**after** the session is online, so a volume-mounted command queues and
|
|
472
509
|
provisions a host like any other session, and `--volume` also works against an
|
|
473
|
-
already-running session (`--on <sid>`).
|
|
474
|
-
|
|
475
|
-
|
|
510
|
+
already-running session (`--on <sid>`). Any number of sessions may attach the
|
|
511
|
+
same volume concurrently — commits merge per path, last writer wins per file
|
|
512
|
+
(so key parallel writers' outputs by distinct paths). Only `delete` and
|
|
513
|
+
`import` conflict while a volume is attached; browsing works any time. Append
|
|
514
|
+
`:ro` (`--volume data:/vol:ro`) to attach read-only: the session sees the
|
|
515
|
+
volume but its writes are discarded at close (no commit).
|
|
476
516
|
|
|
477
517
|
Declare volumes once in `fcloud.json` to skip `--volume` on every command (see
|
|
478
518
|
[Project Config](#project-config-fcloudjson)):
|
|
@@ -678,6 +718,18 @@ without it the cap is **8**, and submitting more tasks than that runs them
|
|
|
678
718
|
in waves. Submit says so out loud, and the cap is changeable on a live
|
|
679
719
|
sweep: `fcloud sweep set <name> --max-parallel N`.
|
|
680
720
|
|
|
721
|
+
**Scheduling (async).** `--not-before WHEN` parks the sweep until then;
|
|
722
|
+
`--by WHEN` sets a deadline: the platform runs tasks opportunistically on
|
|
723
|
+
already-idle hosts (no capacity is provisioned early) and switches to
|
|
724
|
+
normal launching at `deadline - --runtime - a provisioning pad`, so the
|
|
725
|
+
sweep finishes by the deadline without paying for eager scale-up.
|
|
726
|
+
`--runtime DUR` is the per-task runtime estimate (default 1h). WHEN is a
|
|
727
|
+
duration from now (`30m`, `8h`, `2d`) or an ISO time (`2026-09-01T02:00`,
|
|
728
|
+
local). A missed deadline never cancels the sweep — status shows
|
|
729
|
+
`deadline_missed` and the webhook fires `job.deadline_missed`. While
|
|
730
|
+
waiting, `fcloud sweep status` prints the window phase and when launches
|
|
731
|
+
begin.
|
|
732
|
+
|
|
681
733
|
**Canary.** Task 0 runs first and gates the rest: a broken sweep costs one
|
|
682
734
|
task, not N. `fcloud map` blocks until the canary passes, then detaches (Ctrl-C
|
|
683
735
|
detaches the watch — it does NOT cancel). `--no-canary` / `--no-wait` opt out.
|
|
@@ -687,11 +739,53 @@ the rest — cheaper than `--no-canary`, which risks N bad tasks to save one.
|
|
|
687
739
|
Failures don't consume the retry budget when caused by spot preemption — the
|
|
688
740
|
task just requeues.
|
|
689
741
|
|
|
742
|
+
**Skip the line.** When tasks are blocked on capacity, `fcloud sweep boost
|
|
743
|
+
<name>` (or pressing `s` in `sweep status --watch`, offered only while a
|
|
744
|
+
line exists) moves the sweep to the fast claim lane: queued tasks skip
|
|
745
|
+
ahead of free-lane work, and freed machines alternate fast/free so nobody
|
|
746
|
+
is starved. SDK: `handle.boost()`. Unpriced for now.
|
|
747
|
+
|
|
690
748
|
**Waiting for capacity is not failure.** A task with no host yet keeps its
|
|
691
749
|
queued session, charges no retry, and is reported as blocked:
|
|
692
|
-
`fcloud sweep status` prints `blocked on capacity: N task(s), oldest 6m12s
|
|
693
|
-
|
|
694
|
-
|
|
750
|
+
`fcloud sweep status` prints `blocked on capacity: N task(s), oldest 6m12s`
|
|
751
|
+
followed by a `why:` line saying what the wait actually is — a line
|
|
752
|
+
(`3 session(s) ahead in the gpu_1x_l4 queue (1 fast-lane)`), the platform
|
|
753
|
+
(`a new machine is being provisioned`, `waiting for a busy machine to free
|
|
754
|
+
up`), or bad news worth acting on (`no capacity ... (stockout) — consider
|
|
755
|
+
another SKU`, `cloud quota exhausted`). Use it to decide: a line or a
|
|
756
|
+
provision resolves itself (or `boost` past the free lane); a stockout or
|
|
757
|
+
quota wall means pick another SKU or cancel. A `state: waiting` sweep is a
|
|
758
|
+
pipeline hold, and status names the upstream sweeps it waits on.
|
|
759
|
+
|
|
760
|
+
**Retry backoff.** A charged failure re-queues with a growing delay (45s ×
|
|
761
|
+
attempt, capped at 10m) so a deterministic crasher doesn't burn its budget
|
|
762
|
+
in seconds; preemption/lost-host requeues re-run immediately and never
|
|
763
|
+
consume the budget.
|
|
764
|
+
|
|
765
|
+
**Pipelines (`--after`).** `--after SWEEP[,SWEEP]` holds a sweep in
|
|
766
|
+
`waiting` until the named sweeps finish, then launches it — a durable
|
|
767
|
+
server-side barrier, so a whole generate → train → eval pipeline submits up
|
|
768
|
+
front and the client can disconnect:
|
|
769
|
+
|
|
770
|
+
```bash
|
|
771
|
+
fcloud map --name gen --volume run42:/vol \
|
|
772
|
+
-- python3 gen.py --out /vol/data/shard-{i}.jsonl ::: {0..63}
|
|
773
|
+
fcloud map --name train --sku gpu_8x_h100 --volume run42:/vol --after gen \
|
|
774
|
+
-- python3 train.py --data /vol/data --ckpt /vol/ckpt
|
|
775
|
+
fcloud map --name eval --volume run42:/vol --after train \
|
|
776
|
+
-- python3 eval.py --ckpt /vol/ckpt --suite {} ::: mmlu,gsm8k,mbpp
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
Data flows between stages through the shared volume: map tasks write
|
|
780
|
+
disjoint task-keyed paths, the next stage mounts the same volume and sees
|
|
781
|
+
the union (the gate waits for the upstream's volume commits to land before
|
|
782
|
+
releasing). An upstream failure fails the downstream sweep with
|
|
783
|
+
`upstream_failed:<name>` instead of running it on missing inputs; after
|
|
784
|
+
fixing and re-running the upstream, `fcloud sweep retry <name> --all`
|
|
785
|
+
re-arms the downstream. A `succeeded_partial` upstream counts as finished
|
|
786
|
+
unless `--after-strict`. Edges bind at submit, so upstreams must be
|
|
787
|
+
submitted first (which also makes cycles impossible). SDK:
|
|
788
|
+
`client.map(..., after=gen_handle)` (or a name, or a list; `after_strict=True`).
|
|
695
789
|
|
|
696
790
|
**Tracking & recovery:**
|
|
697
791
|
```bash
|
|
@@ -699,15 +793,16 @@ fcloud sweeps # all sweeps: state + done/run/fail count
|
|
|
699
793
|
fcloud sweep status <name> # counts + failures clustered by error, with exemplar task
|
|
700
794
|
fcloud sweep status <name> --watch # same, repainted until terminal (--interval S)
|
|
701
795
|
fcloud sweep harvest <name> '*.json' ./out # every task's outputs → out/task-<i>/…
|
|
702
|
-
fcloud sweep logs <name> [--task N]
|
|
796
|
+
fcloud sweep logs <name> [--task N] [--attempt K] # durable output (defaults to the exemplar failure, falling back to earlier attempts; --attempt 1 = most recent attempt, explicitly)
|
|
703
797
|
fcloud sweep set <name> --max-parallel N # change the fan-out cap on a live sweep
|
|
704
|
-
fcloud sweep retry <name> [--all] # re-run
|
|
798
|
+
fcloud sweep retry <name> [--all] # re-run failed tasks (fix code first: resubmit is idempotent); --all adds canceled + WEDGED in-flight tasks (lost host / dead placement) and never restarts healthy running work
|
|
705
799
|
fcloud sweep cancel <name> [--remaining] # stop; --remaining keeps running tasks (partial success)
|
|
706
|
-
fcloud sweep wait <name>
|
|
800
|
+
fcloud sweep wait <name> [--poll S] [--timeout S] # block until terminal; exit 0 = success, 124 = still running at timeout
|
|
707
801
|
```
|
|
708
|
-
`--webhook URL`
|
|
709
|
-
|
|
710
|
-
|
|
802
|
+
`--webhook URL` POSTs the status document on canary pass/fail and
|
|
803
|
+
completion — agents should submit with `--no-wait --json` and wake on the
|
|
804
|
+
webhook instead of polling. There is no account-default webhook: without
|
|
805
|
+
`--webhook`, nothing is POSTed.
|
|
711
806
|
|
|
712
807
|
**The status JSON is a versioned public contract** (`schema_version: 1`),
|
|
713
808
|
specified in `docs/sweep-status-schema.md`: `counts` is an open map keyed by
|
|
@@ -1086,6 +1181,7 @@ flags merge with (and re-map by name) the `volumes` defaults.
|
|
|
1086
1181
|
| ------------ | ------------------------------------------ |
|
|
1087
1182
|
| `sku` | Default hardware SKU for `exec` and `run` |
|
|
1088
1183
|
| `volumes` | Volumes auto-attached to every `exec`/`run` session. Each entry is `"name"`, `"name:/mount"`, or `{"name": ..., "mount": ...}` |
|
|
1184
|
+
| `checkpoint` | `false` turns checkpoint/restore off for sessions created from this project (preemption rebuilds cold on any host). Default `true`. See *Checkpoint/restore on preemption* |
|
|
1089
1185
|
| `image.base` | Base image (default: `python:3.11-slim`) |
|
|
1090
1186
|
| `image.apt` | Packages to `apt-get install` |
|
|
1091
1187
|
| `image.pip` | Packages to `pip install` |
|
|
@@ -1123,6 +1219,8 @@ host (files restored from cloud storage) the next time you use it. You never run
|
|
|
1123
1219
|
**Warmth**: `fcloud sessions` reports a session's state — `hot` (running, spending),
|
|
1124
1220
|
`warm` (idle host held, spending), `stopping` (finishing teardown), `cold`
|
|
1125
1221
|
(stopped, $0, resumes on use), or `preparing` (coming online).
|
|
1222
|
+
The `$/HR` column is the rate billed on the session's open usage interval while a
|
|
1223
|
+
host is held (0 when cold); `SPENT` is compute charged so far; the footer sums `$/HR`. `fcloud usage` reports what was actually charged.
|
|
1126
1224
|
|
|
1127
1225
|
**Image**: Declarative container spec. Layers are cached by content hash. First run
|
|
1128
1226
|
on a host triggers a build (30–120s); subsequent runs with the same image are instant.
|
|
@@ -1166,6 +1264,24 @@ CLI commands or explicitly via `client.project("name", image=...)`.
|
|
|
1166
1264
|
remains pinned after a hard kill, recover with `fcloud stop <sid>` and then use the
|
|
1167
1265
|
session again.
|
|
1168
1266
|
|
|
1267
|
+
## Autonomous research loops (autoresearch)
|
|
1268
|
+
|
|
1269
|
+
To run an overnight keep/discard experiment loop on the user's code — after
|
|
1270
|
+
[karpathy/autoresearch](https://github.com/karpathy/autoresearch), with the GPU on
|
|
1271
|
+
fcloud instead of under the desk:
|
|
1272
|
+
|
|
1273
|
+
```bash
|
|
1274
|
+
fcloud autoresearch init # writes autoresearch/SETUP.md + program.template.md
|
|
1275
|
+
```
|
|
1276
|
+
|
|
1277
|
+
Then read `autoresearch/SETUP.md` and follow it. It walks you through deciding the
|
|
1278
|
+
metric, the one mutable file vs the frozen eval, and the fixed time budget with the
|
|
1279
|
+
user; you write `program.md`, run the baseline on a persistent session, and hand
|
|
1280
|
+
off to the loop, which only ever re-uploads the mutable file and greps the metric.
|
|
1281
|
+
Progress is visible on the session's page in the fcloud dashboard (Autoresearch
|
|
1282
|
+
tab: metric chart + results table) once the loop's `results.tsv` upload syncs;
|
|
1283
|
+
point the user there when the loop starts.
|
|
1284
|
+
|
|
1169
1285
|
## Anti-Patterns
|
|
1170
1286
|
|
|
1171
1287
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "fcloud-sdk"
|
|
7
|
-
version = "0.1
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Python SDK and CLI for the fcloud GPU compute platform"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -45,7 +45,7 @@ where = ["src"]
|
|
|
45
45
|
# editable copy at the package root) so `fcloud setup` can find it via
|
|
46
46
|
# importlib.resources under any install scheme, including `pip install --user`.
|
|
47
47
|
[tool.setuptools.package-data]
|
|
48
|
-
fcloud = ["py.typed", "SKILL.md"]
|
|
48
|
+
fcloud = ["py.typed", "SKILL.md", "autoresearch/*.md"]
|
|
49
49
|
|
|
50
50
|
[project.optional-dependencies]
|
|
51
51
|
dev = [
|