lcloud-cli 0.1.0__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.
Files changed (44) hide show
  1. lcloud_cli-0.1.0/.github/workflows/ci.yml +61 -0
  2. lcloud_cli-0.1.0/.gitignore +34 -0
  3. lcloud_cli-0.1.0/CHANGELOG.md +38 -0
  4. lcloud_cli-0.1.0/CONTRIBUTING.md +44 -0
  5. lcloud_cli-0.1.0/LICENSE +21 -0
  6. lcloud_cli-0.1.0/PKG-INFO +217 -0
  7. lcloud_cli-0.1.0/README.md +184 -0
  8. lcloud_cli-0.1.0/pyproject.toml +87 -0
  9. lcloud_cli-0.1.0/src/lambda_cloud/__init__.py +3 -0
  10. lcloud_cli-0.1.0/src/lambda_cloud/__main__.py +6 -0
  11. lcloud_cli-0.1.0/src/lambda_cloud/api/__init__.py +17 -0
  12. lcloud_cli-0.1.0/src/lambda_cloud/api/client.py +150 -0
  13. lcloud_cli-0.1.0/src/lambda_cloud/api/service.py +242 -0
  14. lcloud_cli-0.1.0/src/lambda_cloud/cli/__init__.py +1 -0
  15. lcloud_cli-0.1.0/src/lambda_cloud/cli/app.py +111 -0
  16. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/__init__.py +1 -0
  17. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/audit.py +37 -0
  18. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/auth.py +69 -0
  19. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/completion.py +37 -0
  20. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/config_cmd.py +45 -0
  21. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/filesystems.py +53 -0
  22. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/firewall.py +157 -0
  23. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/images.py +23 -0
  24. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/instance_types.py +19 -0
  25. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/instances.py +215 -0
  26. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/regions.py +19 -0
  27. lcloud_cli-0.1.0/src/lambda_cloud/cli/commands/ssh_keys.py +99 -0
  28. lcloud_cli-0.1.0/src/lambda_cloud/cli/state.py +66 -0
  29. lcloud_cli-0.1.0/src/lambda_cloud/cli/ui/__init__.py +13 -0
  30. lcloud_cli-0.1.0/src/lambda_cloud/cli/ui/console.py +94 -0
  31. lcloud_cli-0.1.0/src/lambda_cloud/cli/ui/history.py +62 -0
  32. lcloud_cli-0.1.0/src/lambda_cloud/cli/ui/tables.py +258 -0
  33. lcloud_cli-0.1.0/src/lambda_cloud/core/__init__.py +1 -0
  34. lcloud_cli-0.1.0/src/lambda_cloud/core/config.py +125 -0
  35. lcloud_cli-0.1.0/src/lambda_cloud/core/errors.py +58 -0
  36. lcloud_cli-0.1.0/src/lambda_cloud/mngr/__init__.py +5 -0
  37. lcloud_cli-0.1.0/src/lambda_cloud/mngr/models.py +198 -0
  38. lcloud_cli-0.1.0/tests/commands/test_instances.py +188 -0
  39. lcloud_cli-0.1.0/tests/commands/test_ssh_keys.py +109 -0
  40. lcloud_cli-0.1.0/tests/conftest.py +73 -0
  41. lcloud_cli-0.1.0/tests/test_client.py +80 -0
  42. lcloud_cli-0.1.0/tests/test_config.py +64 -0
  43. lcloud_cli-0.1.0/tests/test_service.py +85 -0
  44. lcloud_cli-0.1.0/uv.lock +618 -0
@@ -0,0 +1,61 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ lint:
17
+ name: lint (ruff)
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v5
22
+ - name: Run ruff check
23
+ run: uvx ruff@0.15.4 check src tests
24
+ - name: Check formatting
25
+ run: uvx ruff@0.15.4 format --check src tests
26
+
27
+ test:
28
+ name: test (python ${{ matrix.python-version }})
29
+ runs-on: ubuntu-latest
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: astral-sh/setup-uv@v5
37
+ - name: Set up Python ${{ matrix.python-version }}
38
+ uses: actions/setup-python@v5
39
+ with:
40
+ python-version: ${{ matrix.python-version }}
41
+ - name: Install dependencies
42
+ run: uv pip install --system -e '.[dev]'
43
+ - name: Run pytest
44
+ run: pytest --cov --cov-report=term-missing
45
+
46
+ build:
47
+ name: build package
48
+ runs-on: ubuntu-latest
49
+ needs: [lint, test]
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+ - uses: astral-sh/setup-uv@v5
53
+ - name: Build distributions
54
+ run: uv build
55
+ - name: Check distribution metadata
56
+ run: uvx twine check 'dist/*'
57
+ - uses: actions/upload-artifact@v4
58
+ with:
59
+ name: dist
60
+ path: dist/
61
+ if-no-files-found: error
@@ -0,0 +1,34 @@
1
+ # Byte-compiled / optimized
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ .eggs/
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+
16
+ # Test / coverage reports
17
+ .pytest_cache/
18
+ .coverage
19
+ .coverage.*
20
+ htmlcov/
21
+ coverage.xml
22
+
23
+ # Ruff / mypy caches
24
+ .ruff_cache/
25
+ .mypy_cache/
26
+
27
+ # Local config / secrets
28
+ .env
29
+ *.pem
30
+ config.json
31
+ *.key
32
+
33
+ # OS
34
+ .DS_Store
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-08-20
11
+
12
+ Initial release of the community Lambda Cloud CLI.
13
+
14
+ ### Added
15
+
16
+ - Authentication flow: `login`, `logout`, `whoami`, `config show`
17
+ (API key from flag > `LAMBDA_API_KEY` > config file with 0600 permissions).
18
+ - `instances`: list, get, launch (tags, filesystems, image, user-data,
19
+ firewall rulesets), restart, terminate (with confirmation), rename.
20
+ - `types list`: instance types with specs, hourly price and live capacity.
21
+ - `ssh-keys`: list, add (upload existing key or generate a pair — private key
22
+ written with 0600 permissions), delete.
23
+ - `filesystems`: list, create, delete.
24
+ - `images list` with `--region` / `--family` filters.
25
+ - `regions list`.
26
+ - `firewall rulesets` (list/get/create/update/delete) and
27
+ `firewall global` (get/update) with local rule validation.
28
+ - `audit list` with pagination support (`--all`).
29
+ - Global options: `--output table|json`, `--api-key`, `--verbose`,
30
+ `--version`, `--show-completion`.
31
+ - HTTP client honouring the documented API rate limits (1 req/s), retrying
32
+ `429` responses with `Retry-After`, and surfacing the API's structured
33
+ error codes.
34
+ - Test suite (pytest + respx) and CI (ruff, pytest on Python 3.10–3.13,
35
+ package build).
36
+
37
+ [Unreleased]: https://github.com/mrprokl/lambda-cloud-cli/compare/v0.1.0...HEAD
38
+ [0.1.0]: https://github.com/mrprokl/lambda-cloud-cli/releases/tag/v0.1.0
@@ -0,0 +1,44 @@
1
+ # Contributing to lambda-cloud-cli
2
+
3
+ Thanks for helping the community! Here is the short version:
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ git clone https://github.com/mrprokl/lambda-cloud-cli.git
9
+ cd lambda-cloud-cli
10
+ uv venv
11
+ uv pip install -e '.[dev]'
12
+ ```
13
+
14
+ ## Checks to run before opening a PR
15
+
16
+ ```bash
17
+ uv run ruff format src tests
18
+ uv run ruff check --fix src tests
19
+ uv run pytest --cov
20
+ ```
21
+
22
+ ## Guidelines
23
+
24
+ - **No secrets in the repo, ever.** The test suite never performs real
25
+ network calls: mock the API with [`respx`](https://lundberg.github.io/respx/).
26
+ - Keep the layered architecture; dependencies flow strictly downward:
27
+
28
+ ```
29
+ cli/commands → cli/ui → api (client/service) → core / mngr
30
+ ```
31
+
32
+ New endpoint? Add the function to `api/service.py`, the table to
33
+ `cli/ui/tables.py`, the command to `cli/commands/`, and tests under `tests/`.
34
+ - Keep models tolerant to API additions (`extra="ignore"` in
35
+ `mngr/models.py`).
36
+ - Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/):
37
+ `feat:`, `fix:`, `docs:`, `chore:`, `refactor:`, `test:`.
38
+ - Public API and behaviors are documented in the README: keep it in sync.
39
+
40
+ ## Reporting issues
41
+
42
+ Include: the command you ran, the output (use `--output json` when useful),
43
+ your Python version (`python --version`) and the CLI version
44
+ (`lambda-cloud --version`). Never paste your API key.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Thomas Gomez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,217 @@
1
+ Metadata-Version: 2.5
2
+ Name: lcloud-cli
3
+ Version: 0.1.0
4
+ Summary: Unofficial community command-line interface for the Lambda Cloud API
5
+ Project-URL: Homepage, https://github.com/mrprokl/lambda-cloud-cli
6
+ Project-URL: Repository, https://github.com/mrprokl/lambda-cloud-cli
7
+ Project-URL: Issues, https://github.com/mrprokl/lambda-cloud-cli/issues
8
+ Project-URL: Changelog, https://github.com/mrprokl/lambda-cloud-cli/blob/main/CHANGELOG.md
9
+ Project-URL: Documentation, https://docs.lambda.ai/public-cloud/
10
+ Author: Thomas Gomez
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: cli,cloud,gpu,lambda,lambda-labs
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: System :: Systems Administration
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: httpx>=0.27
25
+ Requires-Dist: pydantic>=2
26
+ Requires-Dist: rich>=13
27
+ Requires-Dist: typer>=0.12
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
30
+ Requires-Dist: pytest>=8; extra == 'dev'
31
+ Requires-Dist: respx>=0.21; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # lambda-cloud-cli
35
+
36
+ [![CI](https://github.com/mrprokl/lambda-cloud-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/mrprokl/lambda-cloud-cli/actions/workflows/ci.yml)
37
+ [![PyPI](https://img.shields.io/pypi/v/lcloud-cli)](https://pypi.org/project/lcloud-cli/)
38
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
39
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)
40
+
41
+ Unofficial community command-line interface for the
42
+ [Lambda Cloud](https://cloud.lambda.ai) API.
43
+
44
+ > **Disclaimer**: this project is **not** affiliated with, endorsed by, or
45
+ > supported by Lambda, Inc. It is built against the
46
+ > [public Lambda Cloud API](https://docs.lambda.ai/public-cloud/).
47
+
48
+ ## Installation
49
+
50
+ Requires Python 3.10+.
51
+
52
+ ```bash
53
+ # Option 1 — uv (recommended)
54
+ uv tool install lcloud-cli
55
+
56
+ # Option 2 — pipx
57
+ pipx install lcloud-cli
58
+
59
+ # Option 3 — plain pip
60
+ pip install lcloud-cli
61
+
62
+ # Option 4 — straight from GitHub (bleeding edge)
63
+ uv tool install git+https://github.com/mrprokl/lambda-cloud-cli
64
+ ```
65
+
66
+ From source, for development:
67
+
68
+ ```bash
69
+ git clone https://github.com/mrprokl/lambda-cloud-cli.git
70
+ cd lambda-cloud-cli
71
+ uv venv
72
+ uv pip install -e '.[dev]'
73
+ ```
74
+
75
+ ## Quickstart
76
+
77
+ ```bash
78
+ # 1. Authenticate (get your key at https://cloud.lambda.ai/api-keys)
79
+ lambda-cloud login
80
+
81
+ # 2. See what's available
82
+ lambda-cloud regions list
83
+ lambda-cloud types list
84
+ lambda-cloud images list
85
+
86
+ # 3. Launch a GPU instance
87
+ lambda-cloud instances launch \
88
+ --type gpu_1x_a10 \
89
+ --region us-west-1 \
90
+ --ssh-key my-key
91
+
92
+ # 4. Watch it boot
93
+ lambda-cloud instances list
94
+ lambda-cloud instances get <instance-id>
95
+
96
+ # 5. Clean up
97
+ lambda-cloud instances terminate <instance-id>
98
+ ```
99
+
100
+ Output is human-friendly tables by default; add `--output json` (or `-o json`)
101
+ to any command for scripting:
102
+
103
+ ```bash
104
+ lambda-cloud -o json instances list | jq '.[].ip'
105
+ ```
106
+
107
+ ## Authentication
108
+
109
+ The API key is resolved in this order:
110
+
111
+ 1. `--api-key` flag
112
+ 2. `LAMBDA_API_KEY` environment variable
113
+ 3. Config file written by `lambda-cloud login`
114
+ (`$XDG_CONFIG_HOME/lambda-cloud/config.json`, default
115
+ `~/.config/lambda-cloud/config.json`, mode `0600`)
116
+
117
+ ```bash
118
+ lambda-cloud login # interactive prompt, key is validated
119
+ lambda-cloud login --api-key X # non-interactive
120
+ lambda-cloud whoami # which key is in use? is it valid?
121
+ lambda-cloud logout # remove stored key
122
+ lambda-cloud config show # inspect configuration & defaults
123
+ ```
124
+
125
+ ## Commands
126
+
127
+ | Command | Description |
128
+ | --- | --- |
129
+ | `instances list` | List running instances |
130
+ | `instances get <id>` | Instance details |
131
+ | `instances launch` | Launch an on-demand instance |
132
+ | `instances restart <id>...` | Restart instances |
133
+ | `instances terminate <id>...` | Terminate instances (destructive!) |
134
+ | `instances rename <id> --name X` | Rename an instance |
135
+ | `types list` | Instance types, specs, prices, regional capacity |
136
+ | `ssh-keys list` / `add` / `delete` | Manage SSH keys (can generate a pair) |
137
+ | `filesystems list` / `create` / `delete` | Manage shared filesystems |
138
+ | `images list [--region R] [--family F]` | List machine images |
139
+ | `regions list` | List regions |
140
+ | `firewall rulesets ...` | CRUD on regional firewall rulesets |
141
+ | `firewall global get` / `update` | Global firewall ruleset |
142
+ | `audit list [--all]` | Account audit events (paginated) |
143
+ | `config show` | Show CLI configuration |
144
+ | `login` / `logout` / `whoami` | Credential management |
145
+
146
+ ### Launching instances
147
+
148
+ ```bash
149
+ lambda-cloud instances launch \
150
+ --type gpu_8x_h100_sxm5 \
151
+ --region us-south-1 \
152
+ --ssh-key my-key \
153
+ --name training-run \
154
+ --filesystem shared-data \
155
+ --tag env=prod --tag team=ml \
156
+ --image-family lambda-stack \
157
+ --user-data ./cloud-init.yaml
158
+ ```
159
+
160
+ ### Firewall rules files
161
+
162
+ `firewall rulesets create --rules-file rules.json` expects a JSON list:
163
+
164
+ ```json
165
+ [
166
+ {"protocol": "tcp", "port_range": [22, 22], "source_network": "0.0.0.0/0", "description": "SSH"},
167
+ {"protocol": "tcp", "port_range": [8888, 8888], "source_network": "203.0.113.0/24", "description": "Jupyter"},
168
+ {"protocol": "icmp", "source_network": "0.0.0.0/0", "description": "Ping"}
169
+ ]
170
+ ```
171
+
172
+ Rules are validated locally before submission: `icmp` must not define
173
+ `port_range`, every other protocol must.
174
+
175
+ ## Environment variables
176
+
177
+ | Variable | Purpose |
178
+ | --- | --- |
179
+ | `LAMBDA_API_KEY` | API key (overrides stored config) |
180
+ | `LAMBDA_CLOUD_CONFIG_DIR` | Override the config directory |
181
+ | `LAMBDA_CLOUD_API_URL` | Override the API base URL (useful for testing) |
182
+ | `LAMBDA_CLOUD_MIN_INTERVAL` | Min seconds between API calls (default `1.05`, per documented rate limit) |
183
+
184
+ ## Rate limits
185
+
186
+ Per the API documentation: 1 request/second in general, and 1 request per
187
+ 12 seconds on `instance-operations/launch`. The client throttles requests
188
+ client-side and retries `429` responses honouring `Retry-After`.
189
+
190
+ ## Development
191
+
192
+ ```bash
193
+ uv venv
194
+ uv pip install -e '.[dev]'
195
+ uv run ruff check src tests
196
+ uv run pytest
197
+ ```
198
+
199
+ Layout follows a strict layered architecture:
200
+
201
+ ```
202
+ src/lambda_cloud/
203
+ ├── cli/ # interface: commands, state, ui (console/tables/formatters)
204
+ ├── api/ # http client + service layer (request shaping, validation)
205
+ ├── core/ # foundations: config, errors
206
+ └── mngr/ # pydantic resource models
207
+ ```
208
+
209
+ Dependencies flow strictly downward: `cli → api → core/mngr`.
210
+
211
+ ## Contributing
212
+
213
+ Issues and pull requests are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
214
+
215
+ ## License
216
+
217
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,184 @@
1
+ # lambda-cloud-cli
2
+
3
+ [![CI](https://github.com/mrprokl/lambda-cloud-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/mrprokl/lambda-cloud-cli/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/lcloud-cli)](https://pypi.org/project/lcloud-cli/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
+ [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](pyproject.toml)
7
+
8
+ Unofficial community command-line interface for the
9
+ [Lambda Cloud](https://cloud.lambda.ai) API.
10
+
11
+ > **Disclaimer**: this project is **not** affiliated with, endorsed by, or
12
+ > supported by Lambda, Inc. It is built against the
13
+ > [public Lambda Cloud API](https://docs.lambda.ai/public-cloud/).
14
+
15
+ ## Installation
16
+
17
+ Requires Python 3.10+.
18
+
19
+ ```bash
20
+ # Option 1 — uv (recommended)
21
+ uv tool install lcloud-cli
22
+
23
+ # Option 2 — pipx
24
+ pipx install lcloud-cli
25
+
26
+ # Option 3 — plain pip
27
+ pip install lcloud-cli
28
+
29
+ # Option 4 — straight from GitHub (bleeding edge)
30
+ uv tool install git+https://github.com/mrprokl/lambda-cloud-cli
31
+ ```
32
+
33
+ From source, for development:
34
+
35
+ ```bash
36
+ git clone https://github.com/mrprokl/lambda-cloud-cli.git
37
+ cd lambda-cloud-cli
38
+ uv venv
39
+ uv pip install -e '.[dev]'
40
+ ```
41
+
42
+ ## Quickstart
43
+
44
+ ```bash
45
+ # 1. Authenticate (get your key at https://cloud.lambda.ai/api-keys)
46
+ lambda-cloud login
47
+
48
+ # 2. See what's available
49
+ lambda-cloud regions list
50
+ lambda-cloud types list
51
+ lambda-cloud images list
52
+
53
+ # 3. Launch a GPU instance
54
+ lambda-cloud instances launch \
55
+ --type gpu_1x_a10 \
56
+ --region us-west-1 \
57
+ --ssh-key my-key
58
+
59
+ # 4. Watch it boot
60
+ lambda-cloud instances list
61
+ lambda-cloud instances get <instance-id>
62
+
63
+ # 5. Clean up
64
+ lambda-cloud instances terminate <instance-id>
65
+ ```
66
+
67
+ Output is human-friendly tables by default; add `--output json` (or `-o json`)
68
+ to any command for scripting:
69
+
70
+ ```bash
71
+ lambda-cloud -o json instances list | jq '.[].ip'
72
+ ```
73
+
74
+ ## Authentication
75
+
76
+ The API key is resolved in this order:
77
+
78
+ 1. `--api-key` flag
79
+ 2. `LAMBDA_API_KEY` environment variable
80
+ 3. Config file written by `lambda-cloud login`
81
+ (`$XDG_CONFIG_HOME/lambda-cloud/config.json`, default
82
+ `~/.config/lambda-cloud/config.json`, mode `0600`)
83
+
84
+ ```bash
85
+ lambda-cloud login # interactive prompt, key is validated
86
+ lambda-cloud login --api-key X # non-interactive
87
+ lambda-cloud whoami # which key is in use? is it valid?
88
+ lambda-cloud logout # remove stored key
89
+ lambda-cloud config show # inspect configuration & defaults
90
+ ```
91
+
92
+ ## Commands
93
+
94
+ | Command | Description |
95
+ | --- | --- |
96
+ | `instances list` | List running instances |
97
+ | `instances get <id>` | Instance details |
98
+ | `instances launch` | Launch an on-demand instance |
99
+ | `instances restart <id>...` | Restart instances |
100
+ | `instances terminate <id>...` | Terminate instances (destructive!) |
101
+ | `instances rename <id> --name X` | Rename an instance |
102
+ | `types list` | Instance types, specs, prices, regional capacity |
103
+ | `ssh-keys list` / `add` / `delete` | Manage SSH keys (can generate a pair) |
104
+ | `filesystems list` / `create` / `delete` | Manage shared filesystems |
105
+ | `images list [--region R] [--family F]` | List machine images |
106
+ | `regions list` | List regions |
107
+ | `firewall rulesets ...` | CRUD on regional firewall rulesets |
108
+ | `firewall global get` / `update` | Global firewall ruleset |
109
+ | `audit list [--all]` | Account audit events (paginated) |
110
+ | `config show` | Show CLI configuration |
111
+ | `login` / `logout` / `whoami` | Credential management |
112
+
113
+ ### Launching instances
114
+
115
+ ```bash
116
+ lambda-cloud instances launch \
117
+ --type gpu_8x_h100_sxm5 \
118
+ --region us-south-1 \
119
+ --ssh-key my-key \
120
+ --name training-run \
121
+ --filesystem shared-data \
122
+ --tag env=prod --tag team=ml \
123
+ --image-family lambda-stack \
124
+ --user-data ./cloud-init.yaml
125
+ ```
126
+
127
+ ### Firewall rules files
128
+
129
+ `firewall rulesets create --rules-file rules.json` expects a JSON list:
130
+
131
+ ```json
132
+ [
133
+ {"protocol": "tcp", "port_range": [22, 22], "source_network": "0.0.0.0/0", "description": "SSH"},
134
+ {"protocol": "tcp", "port_range": [8888, 8888], "source_network": "203.0.113.0/24", "description": "Jupyter"},
135
+ {"protocol": "icmp", "source_network": "0.0.0.0/0", "description": "Ping"}
136
+ ]
137
+ ```
138
+
139
+ Rules are validated locally before submission: `icmp` must not define
140
+ `port_range`, every other protocol must.
141
+
142
+ ## Environment variables
143
+
144
+ | Variable | Purpose |
145
+ | --- | --- |
146
+ | `LAMBDA_API_KEY` | API key (overrides stored config) |
147
+ | `LAMBDA_CLOUD_CONFIG_DIR` | Override the config directory |
148
+ | `LAMBDA_CLOUD_API_URL` | Override the API base URL (useful for testing) |
149
+ | `LAMBDA_CLOUD_MIN_INTERVAL` | Min seconds between API calls (default `1.05`, per documented rate limit) |
150
+
151
+ ## Rate limits
152
+
153
+ Per the API documentation: 1 request/second in general, and 1 request per
154
+ 12 seconds on `instance-operations/launch`. The client throttles requests
155
+ client-side and retries `429` responses honouring `Retry-After`.
156
+
157
+ ## Development
158
+
159
+ ```bash
160
+ uv venv
161
+ uv pip install -e '.[dev]'
162
+ uv run ruff check src tests
163
+ uv run pytest
164
+ ```
165
+
166
+ Layout follows a strict layered architecture:
167
+
168
+ ```
169
+ src/lambda_cloud/
170
+ ├── cli/ # interface: commands, state, ui (console/tables/formatters)
171
+ ├── api/ # http client + service layer (request shaping, validation)
172
+ ├── core/ # foundations: config, errors
173
+ └── mngr/ # pydantic resource models
174
+ ```
175
+
176
+ Dependencies flow strictly downward: `cli → api → core/mngr`.
177
+
178
+ ## Contributing
179
+
180
+ Issues and pull requests are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
181
+
182
+ ## License
183
+
184
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,87 @@
1
+ [project]
2
+ name = "lcloud-cli"
3
+ version = "0.1.0"
4
+ description = "Unofficial community command-line interface for the Lambda Cloud API"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = { text = "MIT" }
8
+ authors = [{ name = "Thomas Gomez" }]
9
+ keywords = ["lambda", "lambda-labs", "cloud", "gpu", "cli"]
10
+ classifiers = [
11
+ "Environment :: Console",
12
+ "Intended Audience :: Developers",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: System :: Systems Administration",
20
+ ]
21
+ dependencies = [
22
+ "httpx>=0.27",
23
+ "typer>=0.12",
24
+ "rich>=13",
25
+ "pydantic>=2",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pytest>=8",
31
+ "respx>=0.21",
32
+ "pytest-cov>=5",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/mrprokl/lambda-cloud-cli"
37
+ Repository = "https://github.com/mrprokl/lambda-cloud-cli"
38
+ Issues = "https://github.com/mrprokl/lambda-cloud-cli/issues"
39
+ Changelog = "https://github.com/mrprokl/lambda-cloud-cli/blob/main/CHANGELOG.md"
40
+ Documentation = "https://docs.lambda.ai/public-cloud/"
41
+
42
+ [project.scripts]
43
+ lambda-cloud = "lambda_cloud.cli.app:main"
44
+
45
+ [build-system]
46
+ requires = ["hatchling"]
47
+ build-backend = "hatchling.build"
48
+
49
+ [tool.hatch.build.targets.wheel]
50
+ packages = ["src/lambda_cloud"]
51
+
52
+ [tool.ruff]
53
+ target-version = "py310"
54
+ line-length = 100
55
+ src = ["src", "tests"]
56
+
57
+ [tool.ruff.lint]
58
+ select = [
59
+ "E", # pycodestyle errors
60
+ "W", # pycodestyle warnings
61
+ "F", # pyflakes
62
+ "I", # isort
63
+ "B", # flake8-bugbear
64
+ "UP", # pyupgrade
65
+ "SIM", # flake8-simplify
66
+ "T20", # no print() outside of Typer/rich wrappers
67
+ ]
68
+
69
+ [tool.ruff.lint.per-file-ignores]
70
+ # typer.Option()/typer.Argument() in argument defaults is the idiomatic Typer API.
71
+ "src/lambda_cloud/cli/**" = ["B008"]
72
+ "tests/**" = ["B011", "B017"]
73
+
74
+ [tool.ruff.lint.isort]
75
+ known-first-party = ["lambda_cloud"]
76
+
77
+ [tool.pytest.ini_options]
78
+ testpaths = ["tests"]
79
+ addopts = "-q"
80
+ pythonpath = ["."]
81
+
82
+ [tool.coverage.run]
83
+ source = ["src/lambda_cloud"]
84
+ branch = true
85
+
86
+ [tool.coverage.report]
87
+ exclude_also = ["if TYPE_CHECKING:", "raise typer.Exit"]
@@ -0,0 +1,3 @@
1
+ """Unofficial community CLI for the Lambda Cloud API."""
2
+
3
+ __version__ = "0.1.0"