cloudinary-cli 1.16.1__tar.gz → 1.17.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 (105) hide show
  1. {cloudinary_cli-1.16.1/cloudinary_cli.egg-info → cloudinary_cli-1.17.0}/PKG-INFO +81 -3
  2. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/README.md +79 -1
  3. cloudinary_cli-1.17.0/cloudinary_cli/__init__.py +9 -0
  4. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/cli_group.py +16 -1
  5. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/admin.py +4 -3
  6. cloudinary_cli-1.17.0/cloudinary_cli/core/agent.py +488 -0
  7. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/config.py +15 -1
  8. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/provisioning.py +11 -2
  9. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/search.py +2 -2
  10. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/uploader.py +3 -2
  11. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/utils.py +10 -3
  12. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/defaults.py +14 -1
  13. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/modules/migrate.py +1 -1
  14. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/modules/regen_derived.py +4 -0
  15. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/modules/sync.py +39 -11
  16. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/modules/upload_dir.py +6 -5
  17. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/html/upload_widget +1 -1
  18. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/api_utils.py +21 -7
  19. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/config_listing.py +38 -2
  20. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/config_resolver.py +9 -1
  21. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/config_utils.py +58 -2
  22. cloudinary_cli-1.17.0/cloudinary_cli/utils/env_config.py +48 -0
  23. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/file_utils.py +4 -0
  24. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/utils.py +50 -1
  25. cloudinary_cli-1.17.0/cloudinary_cli/version.py +1 -0
  26. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0/cloudinary_cli.egg-info}/PKG-INFO +81 -3
  27. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli.egg-info/SOURCES.txt +3 -0
  28. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli.egg-info/requires.txt +1 -1
  29. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/requirements.txt +1 -1
  30. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/helper_test.py +51 -21
  31. cloudinary_cli-1.17.0/test/test_cli.py +134 -0
  32. cloudinary_cli-1.17.0/test/test_cli_agent_cloud.py +741 -0
  33. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_api.py +38 -1
  34. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_url.py +1 -0
  35. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_modules/test_cli_make.py +1 -0
  36. cloudinary_cli-1.17.0/test/test_modules/test_cli_regen_derived.py +31 -0
  37. cloudinary_cli-1.17.0/test/test_modules/test_cli_sync.py +420 -0
  38. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_modules/test_cli_upload_dir.py +0 -3
  39. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_utils.py +64 -1
  40. cloudinary_cli-1.16.1/cloudinary_cli/__init__.py +0 -5
  41. cloudinary_cli-1.16.1/cloudinary_cli/core/agent.py +0 -203
  42. cloudinary_cli-1.16.1/cloudinary_cli/version.py +0 -1
  43. cloudinary_cli-1.16.1/test/test_cli.py +0 -49
  44. cloudinary_cli-1.16.1/test/test_modules/test_cli_sync.py +0 -222
  45. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/LICENSE +0 -0
  46. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/MANIFEST.in +0 -0
  47. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/auth/__init__.py +0 -0
  48. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/auth/callback_page.py +0 -0
  49. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/auth/flow.py +0 -0
  50. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/auth/loopback_server.py +0 -0
  51. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/auth/oauth_config.py +0 -0
  52. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/auth/refresh.py +0 -0
  53. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/auth/session.py +0 -0
  54. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/cli.py +0 -0
  55. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/__init__.py +0 -0
  56. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/auth.py +0 -0
  57. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/core/overrides.py +0 -0
  58. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/modules/__init__.py +0 -0
  59. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/modules/clone.py +0 -0
  60. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/modules/make.py +0 -0
  61. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/samples/__init__.py +0 -0
  62. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/html/media_library_widget +0 -0
  63. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/html/product_gallery +0 -0
  64. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/html/video_player +0 -0
  65. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/node/upload +0 -0
  66. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/python/base +0 -0
  67. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/python/explicit +0 -0
  68. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/python/find_all_empty_folders +0 -0
  69. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/python/upload +0 -0
  70. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/templates/ruby/upload +0 -0
  71. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/__init__.py +0 -0
  72. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/json_utils.py +0 -0
  73. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/search_utils.py +0 -0
  74. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli/utils/url_utils.py +0 -0
  75. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli.egg-info/dependency_links.txt +0 -0
  76. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli.egg-info/entry_points.txt +0 -0
  77. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli.egg-info/not-zip-safe +0 -0
  78. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/cloudinary_cli.egg-info/top_level.txt +0 -0
  79. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/setup.cfg +0 -0
  80. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/setup.py +0 -0
  81. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/__init__.py +0 -0
  82. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/conftest.py +0 -0
  83. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/oauth_helpers.py +0 -0
  84. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_auth_flow.py +0 -0
  85. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_auth_loopback.py +0 -0
  86. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_auth_region.py +0 -0
  87. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_auth_session.py +0 -0
  88. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_agent.py +0 -0
  89. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_config.py +0 -0
  90. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_config_oauth.py +0 -0
  91. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_samples.py +0 -0
  92. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_search_api.py +0 -0
  93. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_cli_utils.py +0 -0
  94. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_config_cache.py +0 -0
  95. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_config_concurrency.py +0 -0
  96. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_config_permissions.py +0 -0
  97. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_default_config.py +0 -0
  98. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_file_utils.py +0 -0
  99. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_json_utils.py +0 -0
  100. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_modules/__init__.py +0 -0
  101. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_modules/test_cli_clone.py +0 -0
  102. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_oauth_multiprocess.py +0 -0
  103. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_oauth_retry.py +0 -0
  104. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_oauth_token_seam.py +0 -0
  105. {cloudinary_cli-1.16.1 → cloudinary_cli-1.17.0}/test/test_search_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cloudinary-cli
3
- Version: 1.16.1
3
+ Version: 1.17.0
4
4
  Summary: A command line interface for Cloudinary with full API support
5
5
  Home-page: https://github.com/cloudinary/cloudinary-cli
6
6
  Author: Cloudinary, Brian Luk
@@ -13,7 +13,7 @@ Classifier: Operating System :: OS Independent
13
13
  Requires-Python: >=3.8.0
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
- Requires-Dist: cloudinary>=1.45.0
16
+ Requires-Dist: cloudinary>=1.46.3
17
17
  Requires-Dist: pygments
18
18
  Requires-Dist: jinja2
19
19
  Requires-Dist: click
@@ -35,11 +35,24 @@ The Cloudinary CLI (Command Line Interface) enables you to interact with Cloudin
35
35
 
36
36
  It is fully documented at [https://cloudinary.com/documentation/cloudinary_cli](https://cloudinary.com/documentation/cloudinary_cli).
37
37
 
38
+ **Built for AI agents too.** [`cld agent cloud create`](#agent-cloud) provisions a working Cloudinary cloud in a single command — no signup, no verification email, no credentials to ask a human for — so an agent can start uploading and transforming right away, then hand the human a claim URL to keep it.
39
+
38
40
  ## Requirements
39
- Your own Cloudinary account. If you don't already have one, sign up at [https://cloudinary.com/users/register/free](https://cloudinary.com/users/register/free).
40
41
 
41
42
  Python 3.8 or later. You can install Python from [https://www.python.org/](https://www.python.org/). Note that the Python Package Installer (pip) is installed with it.
42
43
 
44
+ A Cloudinary account. There are two ways to get one:
45
+
46
+ **Are you an AI agent?** Run [`cld agent cloud create`](#agent-cloud) — no signup, no verification email, no human in the loop. You get a working cloud name, API key and secret in one command, and can upload and transform immediately:
47
+
48
+ ```
49
+ cld agent cloud create
50
+ ```
51
+
52
+ The cloud is temporary: media delivery is limited to the IP that created it, and it expires in about 24 hours unless a human claims it. Hand them the claim URL from the output — or run [`cld agent cloud claim`](#agent-cloud) — and it becomes a permanent account, keeping the same credentials and everything already uploaded.
53
+
54
+ **Are you a human?** Sign up at [https://cloudinary.com/users/register/free](https://cloudinary.com/users/register/free), then see [Configuration](#configuration) below. If you'd rather an agent set it up for you, [`cld agent signup`](#agent-signup) creates a Free-plan account in your name and emails you to verify it.
55
+
43
56
  ## Installation
44
57
 
45
58
  The CLI is published on PyPI as [`cloudinary-cli`](https://pypi.org/project/cloudinary-cli/). The package name (`cloudinary-cli`) is what you install; the command it provides is **`cld`** (it also installs a `cloudinary` alias). Pick the method that fits your setup. If you just want a working `cld` command and aren't sure, use **pipx** or **uv** — they install the CLI in its own isolated environment, so it won't conflict with other Python packages and you don't need to manage a virtual environment yourself.
@@ -169,6 +182,7 @@ cld search --help # Shows usage for the Search API.
169
182
  cld admin # Lists Admin API methods.
170
183
  cld uploader # Lists Upload API methods.
171
184
  cld agent signup # For AI agents: creates a Cloudinary account on behalf of a human.
185
+ cld agent cloud # For AI agents: creates a temporary cloud that works immediately.
172
186
  ```
173
187
 
174
188
  ## Docker Usage
@@ -364,6 +378,70 @@ Options:
364
378
  * `--sdk-framework <name>` — the Cloudinary SDK framework the agent intends to use.
365
379
  * `--json` — output the full raw JSON response (the agent contract) instead of the human-readable summary.
366
380
 
381
+ ### `agent cloud`
382
+
383
+ **For AI agents acting on behalf of a human.** Creates and claims *Claimable Clouds*: temporary clouds whose credentials work immediately, with no signup and no verification email. No existing configuration is required.
384
+
385
+ Media delivery is restricted to an IP allow-list, and the cloud is **disabled after about 24 hours** — along with everything uploaded to it — unless a human claims it. Claiming makes it permanent, keeps the credentials and assets, and lifts the IP restriction.
386
+
387
+ #### `agent cloud create`
388
+
389
+ ```
390
+ cld agent cloud create [command options] [email]
391
+ ```
392
+
393
+ Example:
394
+
395
+ ```
396
+ cld agent cloud create you@example.com --claim
397
+ ```
398
+
399
+ The cloud is saved as a named configuration along with its claim URL, which **the server returns exactly once and cannot be looked up again**. A cloud saved without it — or created outside the CLI — cannot be claimed via `agent cloud claim`.
400
+
401
+ The optional `email` only pre-fills the claim page. It is never verified and no mail is sent to it at creation, but it must be a real unused address: the server rejects addresses already taken and disposable domains.
402
+
403
+ Options:
404
+
405
+ * `--ip <address>` — an additional IP permitted to deliver media, repeatable. Omit to let the server use the address the request comes from; the literal `requester_ip` means that same address.
406
+ * `--name <name>` — name for the saved configuration (default: the returned cloud name).
407
+ * `--set-default` — set the saved configuration as the default.
408
+ * `--no-save` — show the credentials but do not save them as a configuration. The claim URL is then only in the output, so store it yourself.
409
+ * `--claim` — open the claim page as soon as the cloud is created.
410
+ * `--agent-framework <name>`, `--agent-llm-model <name>`, `--agent-goal <text>`, `--sdk-framework <name>` — attribution for the agent creating the cloud.
411
+ * `--json` — output the full raw JSON response (the agent contract) instead of the human-readable summary.
412
+
413
+ Delivery IPs are sent to the server as given; it validates them and returns the allow-list it actually stored. Read `delivery_ips` back from the response rather than assuming the list you sent was kept — behind a proxy or VPN your own address may be dropped, and the server refuses to create a cloud with no publicly routable address in the list.
414
+
415
+ Because the allow-list covers media delivery only, the Upload and Admin APIs are unaffected. Uploads succeeding while a delivery URL returns `x-cld-error: ACL deny` is the expected symptom of the restriction, not a broken cloud or bad credentials. It is therefore not a confidentiality control.
416
+
417
+ #### `agent cloud claim`
418
+
419
+ ```
420
+ cld agent cloud claim [command options] [name]
421
+ ```
422
+
423
+ Example:
424
+
425
+ ```
426
+ cld agent cloud claim mycloud --print
427
+ ```
428
+
429
+ Opens the claim page for a saved Claimable Cloud. Run without a name to pick from the saved clouds that have not expired.
430
+
431
+ Claiming is a **human action completed in a browser**: they enter an email address there, then click the link sent to it. This command only opens or prints the page — it cannot claim anything itself, and nothing reports whether a claim succeeded.
432
+
433
+ Options:
434
+
435
+ * `--print` (or `--no-open`) — print the claim URL instead of opening a browser. Required for headless and agent use; also implied by `--json`. The CLI prints rather than opens whenever stdout is not a terminal.
436
+ * `--json` — output `{cloud_name, claim_url, expires_at}` as JSON.
437
+
438
+ Saved Claimable Clouds are flagged in `cld config -ls` and `cld config -s <name>` with an expiry countdown, so you can see what is still claimable:
439
+
440
+ ```
441
+ NAME CLOUD TYPE DEFAULT ACTIVE STATUS
442
+ mycloud abcd1234 api_key unclaimed, expires in 8h
443
+ ```
444
+
367
445
  ## Additional configurations
368
446
 
369
447
  A configuration is a reference to a specified Cloudinary account or cloud name via its environment variable. You set the default configuration during setup and installation. Using different configurations allows you to access different Cloudinary cloud names, such as sub-accounts of your main Cloudinary account, or any additional Cloudinary accounts you may have.
@@ -9,11 +9,24 @@ The Cloudinary CLI (Command Line Interface) enables you to interact with Cloudin
9
9
 
10
10
  It is fully documented at [https://cloudinary.com/documentation/cloudinary_cli](https://cloudinary.com/documentation/cloudinary_cli).
11
11
 
12
+ **Built for AI agents too.** [`cld agent cloud create`](#agent-cloud) provisions a working Cloudinary cloud in a single command — no signup, no verification email, no credentials to ask a human for — so an agent can start uploading and transforming right away, then hand the human a claim URL to keep it.
13
+
12
14
  ## Requirements
13
- Your own Cloudinary account. If you don't already have one, sign up at [https://cloudinary.com/users/register/free](https://cloudinary.com/users/register/free).
14
15
 
15
16
  Python 3.8 or later. You can install Python from [https://www.python.org/](https://www.python.org/). Note that the Python Package Installer (pip) is installed with it.
16
17
 
18
+ A Cloudinary account. There are two ways to get one:
19
+
20
+ **Are you an AI agent?** Run [`cld agent cloud create`](#agent-cloud) — no signup, no verification email, no human in the loop. You get a working cloud name, API key and secret in one command, and can upload and transform immediately:
21
+
22
+ ```
23
+ cld agent cloud create
24
+ ```
25
+
26
+ The cloud is temporary: media delivery is limited to the IP that created it, and it expires in about 24 hours unless a human claims it. Hand them the claim URL from the output — or run [`cld agent cloud claim`](#agent-cloud) — and it becomes a permanent account, keeping the same credentials and everything already uploaded.
27
+
28
+ **Are you a human?** Sign up at [https://cloudinary.com/users/register/free](https://cloudinary.com/users/register/free), then see [Configuration](#configuration) below. If you'd rather an agent set it up for you, [`cld agent signup`](#agent-signup) creates a Free-plan account in your name and emails you to verify it.
29
+
17
30
  ## Installation
18
31
 
19
32
  The CLI is published on PyPI as [`cloudinary-cli`](https://pypi.org/project/cloudinary-cli/). The package name (`cloudinary-cli`) is what you install; the command it provides is **`cld`** (it also installs a `cloudinary` alias). Pick the method that fits your setup. If you just want a working `cld` command and aren't sure, use **pipx** or **uv** — they install the CLI in its own isolated environment, so it won't conflict with other Python packages and you don't need to manage a virtual environment yourself.
@@ -143,6 +156,7 @@ cld search --help # Shows usage for the Search API.
143
156
  cld admin # Lists Admin API methods.
144
157
  cld uploader # Lists Upload API methods.
145
158
  cld agent signup # For AI agents: creates a Cloudinary account on behalf of a human.
159
+ cld agent cloud # For AI agents: creates a temporary cloud that works immediately.
146
160
  ```
147
161
 
148
162
  ## Docker Usage
@@ -338,6 +352,70 @@ Options:
338
352
  * `--sdk-framework <name>` — the Cloudinary SDK framework the agent intends to use.
339
353
  * `--json` — output the full raw JSON response (the agent contract) instead of the human-readable summary.
340
354
 
355
+ ### `agent cloud`
356
+
357
+ **For AI agents acting on behalf of a human.** Creates and claims *Claimable Clouds*: temporary clouds whose credentials work immediately, with no signup and no verification email. No existing configuration is required.
358
+
359
+ Media delivery is restricted to an IP allow-list, and the cloud is **disabled after about 24 hours** — along with everything uploaded to it — unless a human claims it. Claiming makes it permanent, keeps the credentials and assets, and lifts the IP restriction.
360
+
361
+ #### `agent cloud create`
362
+
363
+ ```
364
+ cld agent cloud create [command options] [email]
365
+ ```
366
+
367
+ Example:
368
+
369
+ ```
370
+ cld agent cloud create you@example.com --claim
371
+ ```
372
+
373
+ The cloud is saved as a named configuration along with its claim URL, which **the server returns exactly once and cannot be looked up again**. A cloud saved without it — or created outside the CLI — cannot be claimed via `agent cloud claim`.
374
+
375
+ The optional `email` only pre-fills the claim page. It is never verified and no mail is sent to it at creation, but it must be a real unused address: the server rejects addresses already taken and disposable domains.
376
+
377
+ Options:
378
+
379
+ * `--ip <address>` — an additional IP permitted to deliver media, repeatable. Omit to let the server use the address the request comes from; the literal `requester_ip` means that same address.
380
+ * `--name <name>` — name for the saved configuration (default: the returned cloud name).
381
+ * `--set-default` — set the saved configuration as the default.
382
+ * `--no-save` — show the credentials but do not save them as a configuration. The claim URL is then only in the output, so store it yourself.
383
+ * `--claim` — open the claim page as soon as the cloud is created.
384
+ * `--agent-framework <name>`, `--agent-llm-model <name>`, `--agent-goal <text>`, `--sdk-framework <name>` — attribution for the agent creating the cloud.
385
+ * `--json` — output the full raw JSON response (the agent contract) instead of the human-readable summary.
386
+
387
+ Delivery IPs are sent to the server as given; it validates them and returns the allow-list it actually stored. Read `delivery_ips` back from the response rather than assuming the list you sent was kept — behind a proxy or VPN your own address may be dropped, and the server refuses to create a cloud with no publicly routable address in the list.
388
+
389
+ Because the allow-list covers media delivery only, the Upload and Admin APIs are unaffected. Uploads succeeding while a delivery URL returns `x-cld-error: ACL deny` is the expected symptom of the restriction, not a broken cloud or bad credentials. It is therefore not a confidentiality control.
390
+
391
+ #### `agent cloud claim`
392
+
393
+ ```
394
+ cld agent cloud claim [command options] [name]
395
+ ```
396
+
397
+ Example:
398
+
399
+ ```
400
+ cld agent cloud claim mycloud --print
401
+ ```
402
+
403
+ Opens the claim page for a saved Claimable Cloud. Run without a name to pick from the saved clouds that have not expired.
404
+
405
+ Claiming is a **human action completed in a browser**: they enter an email address there, then click the link sent to it. This command only opens or prints the page — it cannot claim anything itself, and nothing reports whether a claim succeeded.
406
+
407
+ Options:
408
+
409
+ * `--print` (or `--no-open`) — print the claim URL instead of opening a browser. Required for headless and agent use; also implied by `--json`. The CLI prints rather than opens whenever stdout is not a terminal.
410
+ * `--json` — output `{cloud_name, claim_url, expires_at}` as JSON.
411
+
412
+ Saved Claimable Clouds are flagged in `cld config -ls` and `cld config -s <name>` with an expiry countdown, so you can see what is still claimable:
413
+
414
+ ```
415
+ NAME CLOUD TYPE DEFAULT ACTIVE STATUS
416
+ mycloud abcd1234 api_key unclaimed, expires in 8h
417
+ ```
418
+
341
419
  ## Additional configurations
342
420
 
343
421
  A configuration is a reference to a specified Cloudinary account or cloud name via its environment variable. You set the default configuration during setup and installation. Using different configurations allows you to access different Cloudinary cloud names, such as sub-accounts of your main Cloudinary account, or any additional Cloudinary accounts you may have.
@@ -0,0 +1,9 @@
1
+ from cloudinary_cli.version import __version__
2
+ from cloudinary_cli.utils.env_config import import_sdk
3
+
4
+ # Must run before any other `import cloudinary`, so that an invalid CLOUDINARY_URL does not stop the CLI.
5
+ import_sdk()
6
+
7
+ import cloudinary
8
+
9
+ cloudinary.USER_PLATFORM = f"CloudinaryCLI/{__version__}"
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env python3
2
+ import difflib
2
3
  import platform
3
4
  import shutil
4
5
 
@@ -13,7 +14,21 @@ from cloudinary_cli.version import __version__ as cli_version
13
14
  CONTEXT_SETTINGS = dict(max_content_width=shutil.get_terminal_size()[0], terminal_width=shutil.get_terminal_size()[0])
14
15
 
15
16
 
16
- @click.group(context_settings=CONTEXT_SETTINGS, invoke_without_command=True)
17
+ class SuggestingGroup(click.Group):
18
+ """Suggests similar command names when the command name is not known."""
19
+
20
+ def resolve_command(self, ctx, args):
21
+ try:
22
+ return super().resolve_command(ctx, args)
23
+ except click.UsageError as e:
24
+ names = [name for name in self.list_commands(ctx) if not self.get_command(ctx, name).hidden]
25
+ matches = difflib.get_close_matches(args[0], names) if args else []
26
+ if matches:
27
+ e.message += f"\nDid you mean: {', '.join(matches)}?"
28
+ raise
29
+
30
+
31
+ @click.group(cls=SuggestingGroup, context_settings=CONTEXT_SETTINGS, invoke_without_command=True)
17
32
  @click.help_option()
18
33
  @click.version_option(cli_version, prog_name="Cloudinary CLI",
19
34
  message=f"%(prog)s, version %(version)s\n"
@@ -16,11 +16,12 @@ Format: cld <cli options> admin <command options> <method> <method parameters>
16
16
  \t cld admin resources max_results=10 -o tags sample
17
17
  """)
18
18
  @argument("params", nargs=-1)
19
- @option("-o", "--optional_parameter", multiple=True, nargs=2, help="Pass optional parameters as raw strings.")
19
+ @option("-o", "--optional_parameter", multiple=True, nargs=2,
20
+ help="Pass an optional parameter as a string, with no parsing. e.g. -o tags a,b")
20
21
  @option("-O", "--optional_parameter_parsed", multiple=True, nargs=2,
21
- help="Pass optional parameters as interpreted strings.")
22
+ help="Pass an optional parameter and parse its value as JSON or a boolean. e.g. -O context '{\"alt\": \"cat\"}'")
22
23
  @option("-A", "--auto_paginate", is_flag=True, help="Will auto paginate Admin API calls.", default=False)
23
- @option("-ff", "--filter_fields", multiple=True, help="Filter fields to return when using auto pagination.")
24
+ @option("-ff", "--filter_fields", multiple=True, help="Filter fields to return. Requires -A/--auto_paginate.")
24
25
  @option("-F", "--force", is_flag=True,
25
26
  help="Skip confirmations for auto pagination and destructive bulk API methods.")
26
27
  @option("-ls", "--ls", is_flag=True, help="List all available methods in the Admin API.")