hypercli-sdk 2026.6.26__tar.gz → 2026.7.31__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.

Potentially problematic release.


This version of hypercli-sdk might be problematic. Click here for more details.

Files changed (70) hide show
  1. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/.gitignore +3 -0
  2. hypercli_sdk-2026.7.31/PKG-INFO +331 -0
  3. hypercli_sdk-2026.7.31/README.md +296 -0
  4. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/__init__.py +70 -2
  5. hypercli_sdk-2026.7.31/hypercli/agents.py +3770 -0
  6. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/client.py +6 -1
  7. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/http.py +10 -9
  8. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/keys.py +13 -1
  9. hypercli_sdk-2026.7.31/hypercli/openclaw/__init__.py +67 -0
  10. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/openclaw/gateway.py +779 -56
  11. hypercli_sdk-2026.7.31/hypercli/openclaw/node_proxy.py +838 -0
  12. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/user.py +39 -5
  13. hypercli_sdk-2026.7.31/hypercli/voice.py +181 -0
  14. hypercli_sdk-2026.7.31/hypercli/voice_stream.py +246 -0
  15. hypercli_sdk-2026.7.31/hypercli/workspaces.py +920 -0
  16. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/pyproject.toml +11 -1
  17. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/test_agents.py +68 -1
  18. hypercli_sdk-2026.7.31/tests/integration/test_node_egress_e2e.py +231 -0
  19. hypercli_sdk-2026.7.31/tests/test_agent_files_source.py +247 -0
  20. hypercli_sdk-2026.7.31/tests/test_agent_lifecycle.py +208 -0
  21. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_agents.py +612 -14
  22. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_bootstrap_console_test_key.py +24 -0
  23. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_bootstrap_dev_test_keys.py +24 -0
  24. hypercli_sdk-2026.7.31/tests/test_coding_agents.py +575 -0
  25. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_exec_shell_dryrun.py +39 -2
  26. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_gateway.py +501 -25
  27. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_http.py +24 -1
  28. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_keys.py +32 -1
  29. hypercli_sdk-2026.7.31/tests/test_node_proxy.py +247 -0
  30. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_renders_subscription.py +16 -0
  31. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_voice.py +39 -5
  32. hypercli_sdk-2026.7.31/tests/test_voice_stream.py +293 -0
  33. hypercli_sdk-2026.7.31/tests/test_workspaces.py +910 -0
  34. hypercli_sdk-2026.6.26/PKG-INFO +0 -173
  35. hypercli_sdk-2026.6.26/README.md +0 -142
  36. hypercli_sdk-2026.6.26/hypercli/agents.py +0 -1949
  37. hypercli_sdk-2026.6.26/hypercli/openclaw/__init__.py +0 -25
  38. hypercli_sdk-2026.6.26/hypercli/voice.py +0 -102
  39. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/_compat.py +0 -0
  40. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/agent.py +0 -0
  41. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/billing.py +0 -0
  42. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/config.py +0 -0
  43. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/files.py +0 -0
  44. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/gateway.py +0 -0
  45. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/instances.py +0 -0
  46. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/job/__init__.py +0 -0
  47. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/job/base.py +0 -0
  48. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/job/comfyui.py +0 -0
  49. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/job/gradio.py +0 -0
  50. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/jobs.py +0 -0
  51. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/logs.py +0 -0
  52. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/models.py +0 -0
  53. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/renders.py +4 -4
  54. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/shell.py +0 -0
  55. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/hypercli/x402.py +0 -0
  56. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/conftest.py +0 -0
  57. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/test_auth.py +0 -0
  58. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/test_billing.py +0 -0
  59. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/test_instances.py +0 -0
  60. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/test_jobs_dryrun.py +0 -0
  61. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/test_keys.py +0 -0
  62. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/integration/test_renders.py +0 -0
  63. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_apply_params.py +0 -0
  64. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_claw.py +0 -0
  65. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_config.py +0 -0
  66. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_gateway_retry.py +0 -0
  67. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_graph_to_api.py +0 -0
  68. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_jobs.py +0 -0
  69. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_models.py +0 -0
  70. {hypercli_sdk-2026.6.26 → hypercli_sdk-2026.7.31}/tests/test_status.py +0 -0
@@ -20,6 +20,7 @@ ENV/
20
20
  out
21
21
  dist
22
22
  build
23
+ target/
23
24
 
24
25
  # Testing
25
26
  coverage
@@ -28,6 +29,8 @@ coverage
28
29
  .DS_Store
29
30
  .agents/
30
31
  .opencode/
32
+ .github/
33
+ docs/agent-display-names.md
31
34
  *.pem
32
35
 
33
36
  # IDE
@@ -0,0 +1,331 @@
1
+ Metadata-Version: 2.4
2
+ Name: hypercli-sdk
3
+ Version: 2026.7.31
4
+ Summary: Python SDK for HyperCLI - GPU orchestration and HyperAgent API
5
+ Project-URL: Homepage, https://hypercli.com
6
+ Project-URL: Documentation, https://docs.hypercli.com
7
+ Project-URL: Repository, https://github.com/HyperCLI/hypercli
8
+ Author-email: HyperCLI <support@hypercli.com>
9
+ License-Expression: MIT
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.10
17
+ Requires-Dist: httpx>=0.28.1
18
+ Requires-Dist: pynacl>=1.5.0
19
+ Requires-Dist: websockets>=15.0.1
20
+ Provides-Extra: agent
21
+ Requires-Dist: openai>=1.0.0; extra == 'agent'
22
+ Provides-Extra: all
23
+ Requires-Dist: comfyui-workflow-templates-media-image>=0.3.0; extra == 'all'
24
+ Requires-Dist: comfyui-workflow-templates>=0.7.0; extra == 'all'
25
+ Requires-Dist: openai>=1.0.0; extra == 'all'
26
+ Provides-Extra: comfyui
27
+ Requires-Dist: comfyui-workflow-templates-media-image>=0.3.0; extra == 'comfyui'
28
+ Requires-Dist: comfyui-workflow-templates>=0.7.0; extra == 'comfyui'
29
+ Provides-Extra: dev
30
+ Requires-Dist: openai>=1.0.0; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
32
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
33
+ Requires-Dist: ruff>=0.3.0; extra == 'dev'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # HyperCLI SDK
37
+
38
+ Python SDK for [HyperCLI](https://hypercli.com) - GPU orchestration API.
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install hypercli-sdk
44
+ ```
45
+
46
+ ## Setup
47
+
48
+ Set your API key:
49
+
50
+ ```bash
51
+ export HYPER_API_KEY=your_api_key
52
+ ```
53
+
54
+ Or create `~/.hypercli/config`:
55
+ ```
56
+ HYPER_API_KEY=your_api_key
57
+ ```
58
+
59
+ Or pass directly:
60
+ ```python
61
+ client = HyperCLI(api_key="your_api_key")
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ ```python
67
+ from hypercli import HyperCLI
68
+
69
+ client = HyperCLI()
70
+
71
+ # Check balance
72
+ balance = client.billing.balance()
73
+ print(f"Balance: ${balance.total:.2f}")
74
+ print(f"Rewards: ${balance.rewards:.2f}")
75
+
76
+ # List transactions
77
+ for tx in client.billing.transactions(limit=10):
78
+ print(f"{tx.transaction_type}: ${tx.amount_usd:.4f}")
79
+
80
+ # Create a job
81
+ job = client.jobs.create(
82
+ image="nvidia/cuda:12.0",
83
+ command="python train.py",
84
+ gpu_type="l40s",
85
+ gpu_count=1,
86
+ )
87
+ print(f"Job ID: {job.job_id}")
88
+ print(f"State: {job.state}")
89
+
90
+ # List jobs
91
+ for job in client.jobs.list():
92
+ print(f"{job.job_id}: {job.state}")
93
+
94
+ # Get job details
95
+ job = client.jobs.get("job_id")
96
+
97
+ # Get job logs
98
+ logs = client.jobs.logs("job_id")
99
+
100
+ # Get GPU metrics
101
+ metrics = client.jobs.metrics("job_id")
102
+ for gpu in metrics.gpus:
103
+ print(f"GPU {gpu.index}: {gpu.utilization}% util, {gpu.temperature}°C")
104
+
105
+ # Cancel a job
106
+ client.jobs.cancel("job_id")
107
+
108
+ # Extend runtime
109
+ client.jobs.extend("job_id", runtime=7200)
110
+
111
+ # Get user info
112
+ user = client.user.get()
113
+ print(f"User: {user.email}")
114
+ ```
115
+
116
+ ## HyperAgent API
117
+
118
+ Use `client.agent` for discovery and plan metadata, and point the OpenAI SDK at
119
+ the HyperClaw inference base URL for chat completions:
120
+
121
+ ```python
122
+ from hypercli import HyperCLI
123
+ from openai import OpenAI
124
+
125
+ sdk = HyperCLI(api_key="hyper_api_key", agent_api_key="sk-agent")
126
+ plans = sdk.agent.plans()
127
+ activation = sdk.agent.redeem_grant_code("PROMO123")
128
+ renewal = sdk.agent.redeem_grant_code("PROMO123", extend_existing=True)
129
+
130
+ client = OpenAI(
131
+ api_key="your_hyperagent_api_key",
132
+ base_url="https://api.hypercli.com/v1"
133
+ )
134
+
135
+ response = client.chat.completions.create(
136
+ model="deepseek-v3.1",
137
+ messages=[{"role": "user", "content": "Hello!"}]
138
+ )
139
+ ```
140
+
141
+ `redeem_grant_code()` applies a promo/activation code to the current HyperClaw account and returns the created entitlement. Codes create new entitlements by default; pass `extend_existing=True` only for renewal/extension behavior.
142
+
143
+ ## OpenClaw Agents
144
+
145
+ OpenClaw uses the generic deployment launch surface. `registry_url`, `registry_auth`, `sync_root`, and `sync_enabled` are generic deployment options; the OpenClaw helpers only add defaults such as routes, image, and `sync_root=/home/node`.
146
+
147
+ ```python
148
+ agent = client.deployments.create_openclaw(
149
+ name="docs-demo",
150
+ start=True,
151
+ registry_url="git.nedos.co",
152
+ registry_auth={"username": "ci", "password": "token"},
153
+ )
154
+ ```
155
+
156
+ Use `create_openclaw_pro(...)` for the desktop/browser image. It enables noVNC through the protected `desktop-<agent>.hypercli.app` route and sets `OPENCLAW_DESKTOP_ENABLED=1`.
157
+
158
+ `heartbeat` maps directly to upstream OpenClaw config at `config.agents.defaults.heartbeat`. Omit it to keep upstream defaults, or pass values such as `heartbeat={"every": "1h", "target": "last"}`.
159
+
160
+ Automatic memory indexing is off by default. Opt in with `memory_index={"on_session_start": True, "on_search": True, "watch": True, "watch_debounce_ms": 30000, "interval_minutes": 0}`.
161
+
162
+ ## Hosted Coding Agents
163
+
164
+ OpenCode, Codex, Claude Code, Goose, and Kimi Code use canonical Reef images.
165
+ They have no public runtime port: lifecycle, exec, shell, workspace sync, and
166
+ authentication all use the existing authenticated deployment APIs. OpenCode
167
+ and Goose default to HyperCLI's Anthropic-native `kimi-k2.6-anthropic` route.
168
+ Kimi Code keeps Moonshot's upstream device login and service.
169
+
170
+ ```python
171
+ agent = client.deployments.create_opencode(name="opencode")
172
+ codex = client.deployments.create_codex(name="codex")
173
+ claude = client.deployments.create_claude_code(name="claude")
174
+ goose = client.deployments.create_goose(name="goose")
175
+ kimi = client.deployments.create_kimi_code(name="kimi")
176
+
177
+ methods = codex.auth.methods()
178
+ status = codex.auth.status()
179
+
180
+ async with await codex.auth.login("device") as login:
181
+ print(login.verification_url, login.user_code)
182
+ await login.wait()
183
+ ```
184
+
185
+ The login helper opens a short-lived, agent-bound shell WebSocket and runs the
186
+ runtime's native login command inside the Reef pod. It never puts an API key on
187
+ the command line. Runtime credentials and state live under the persistent
188
+ `/home/node` sync root.
189
+
190
+ The images default to a long-lived direct shell/exec container. A Buzz provider
191
+ launches one for a Buzz-managed identity with the typed launch contract:
192
+
193
+ ```python
194
+ from hypercli import BuzzLaunchConfig
195
+
196
+ agent = client.deployments.create_opencode(
197
+ name="buzz-opencode",
198
+ env={"HYPER_API_KEY": inference_key},
199
+ buzz=BuzzLaunchConfig(
200
+ private_key_nsec=agent_nsec,
201
+ relay_url=relay_url,
202
+ auth_tag=owner_signed_auth_tag,
203
+ parallelism=1,
204
+ ),
205
+ )
206
+ ```
207
+
208
+ The SDK selects `/usr/local/bin/buzz-acp`, the runtime-specific child ACP
209
+ command and arguments, the hosted Buzz MCP command, lazy pool creation, relay
210
+ observation, and persistent `/home/node` settings. Buzz-reserved environment
211
+ keys are rendered from the typed object after caller environment values.
212
+ `buzz_enabled=True` remains as a deprecated raw-environment compatibility path.
213
+ Typed and compatibility Buzz launches select the matching `hypercli-buzz`
214
+ image family (`opencode`, `codex`, `claude`, `goose`, or `kimi-code`) by
215
+ default. Ordinary coding-agent helpers without Buzz keep the generic
216
+ `ghcr.io/hypercli/hypercli-<runtime>:latest` default. An explicit `image=`
217
+ continues to override either default.
218
+
219
+ Direct `BuzzLaunchConfig` renders timeout and response-policy values but does
220
+ not duplicate the stock Desktop provider's validation; invalid combinations
221
+ are rejected later by `buzz-acp`. The Desktop provider also maps structured
222
+ Goose model/provider fields to `GOOSE_MODEL`/`GOOSE_PROVIDER`; direct Python
223
+ SDK callers must set any Goose-specific environment themselves.
224
+
225
+ Buzz launches require `size="large"`; ordinary coding-agent helpers preserve a
226
+ caller-provided size or the backend default. Stock Buzz provider agents do not
227
+ start on app launch and the current provider protocol has no stop callback.
228
+ Editing a running agent does not replace its HyperCLI launch environment: stop
229
+ the deployment through the authenticated HyperCLI API and deploy it again from
230
+ Buzz to apply changes. Desktop's best-effort `!shutdown` chat control may exit
231
+ the harness, but it does not stop or release the HyperCLI deployment.
232
+
233
+ Stock Buzz expects ACP NDJSON. It skips non-JSON child stdout, and
234
+ `agent_message_chunk` is activity telemetry rather than a channel reply. There
235
+ is no plaintext fallback; a visible reply requires the agent to invoke the Buzz
236
+ send command/tool. The five-runtime SDK coverage validates request rendering,
237
+ not live launches.
238
+
239
+ The agent nsec and caller environment become raw deployment environment values.
240
+ The HyperClaw backend currently persists them in `Agent.launch_config`, and
241
+ authenticated deployment read, environment, or exec surfaces may expose them.
242
+ The default `RUST_LOG` filter disables `acp::stream` content logging; overriding
243
+ it can expose generated text in container logs.
244
+
245
+ ## OpenClaw Node Egress
246
+
247
+ The Python SDK includes an experimental reference implementation for user-owned
248
+ node egress in `hypercli.openclaw.node_proxy`. It uses the existing OpenClaw
249
+ node model:
250
+
251
+ - a node connects to the gateway with `role="node"`
252
+ - the node declares explicit `egress.*` command names during the connect
253
+ handshake
254
+ - an operator/client calls `GatewayClient.node_invoke(node_id, command, params)`
255
+ - the gateway sends one `node.invoke.request` and waits for one
256
+ `node.invoke.result`
257
+
258
+ This is not raw sockets over the gateway. It is node RPC with chunked payloads
259
+ and gateway policy approval.
260
+
261
+ Node side:
262
+
263
+ ```python
264
+ from hypercli.openclaw import NodeEgressServer
265
+
266
+ node = NodeEgressServer(
267
+ "wss://my-agent.hypercli.app",
268
+ "home-linux-egress",
269
+ gateway_token="...",
270
+ )
271
+
272
+ await node.connect()
273
+ ```
274
+
275
+ Operator side:
276
+
277
+ ```python
278
+ from hypercli.openclaw import EGRESS_COMMANDS, NodeEgressClient
279
+
280
+ egress = NodeEgressClient(gateway, node_id="home-linux-egress")
281
+ res = await egress.http_fetch("https://example.com/")
282
+ ```
283
+
284
+ Commands:
285
+
286
+ - `egress.http.fetch`: bounded HTTP(S) fetch, response body returned as base64
287
+ chunks
288
+ - `egress.tcp.open/read/write/close`: experimental TCP tunnel primitives used
289
+ by `LoopbackNodeProxy` for HTTP `CONNECT`
290
+
291
+ Security defaults:
292
+
293
+ - local proxy binds to `127.0.0.1` by default
294
+ - node id is explicit; no automatic node selection
295
+ - RFC1918/private, loopback, link-local, multicast, reserved, and metadata IPs
296
+ are blocked by default unless explicitly allowed on the node
297
+ - chunks are small and bounded; responses are not returned as one unbounded
298
+ base64 blob
299
+
300
+ Pairing and policy:
301
+
302
+ - the node must be device-paired
303
+ - the node command surface must be approved
304
+ - custom `egress.*` commands may need `gateway.nodes.allowCommands`
305
+
306
+ Python/Linux is first because it is easiest to test in CI and the Python SDK
307
+ already ships `NodeServer`. The portable contract is the command surface and
308
+ payload shape, not the Python implementation. macOS Backseat Driver already
309
+ proves the native node-host precedent; Android should eventually gain Kotlin
310
+ `NodeRuntime` parity; the TS SDK can mirror operator/client types if useful.
311
+
312
+ `LoopbackNodeProxy` can relay absolute-form HTTP requests and has experimental
313
+ `CONNECT` support over polling/chunked `node.invoke`. Treat CONNECT as a
314
+ feasibility prototype, not production-grade streaming.
315
+
316
+ ## Error Handling
317
+
318
+ ```python
319
+ from hypercli import HyperCLI, APIError
320
+
321
+ client = HyperCLI()
322
+
323
+ try:
324
+ job = client.jobs.get("invalid_id")
325
+ except APIError as e:
326
+ print(f"Error {e.status_code}: {e.detail}")
327
+ ```
328
+
329
+ ## License
330
+
331
+ MIT
@@ -0,0 +1,296 @@
1
+ # HyperCLI SDK
2
+
3
+ Python SDK for [HyperCLI](https://hypercli.com) - GPU orchestration API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install hypercli-sdk
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ Set your API key:
14
+
15
+ ```bash
16
+ export HYPER_API_KEY=your_api_key
17
+ ```
18
+
19
+ Or create `~/.hypercli/config`:
20
+ ```
21
+ HYPER_API_KEY=your_api_key
22
+ ```
23
+
24
+ Or pass directly:
25
+ ```python
26
+ client = HyperCLI(api_key="your_api_key")
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ```python
32
+ from hypercli import HyperCLI
33
+
34
+ client = HyperCLI()
35
+
36
+ # Check balance
37
+ balance = client.billing.balance()
38
+ print(f"Balance: ${balance.total:.2f}")
39
+ print(f"Rewards: ${balance.rewards:.2f}")
40
+
41
+ # List transactions
42
+ for tx in client.billing.transactions(limit=10):
43
+ print(f"{tx.transaction_type}: ${tx.amount_usd:.4f}")
44
+
45
+ # Create a job
46
+ job = client.jobs.create(
47
+ image="nvidia/cuda:12.0",
48
+ command="python train.py",
49
+ gpu_type="l40s",
50
+ gpu_count=1,
51
+ )
52
+ print(f"Job ID: {job.job_id}")
53
+ print(f"State: {job.state}")
54
+
55
+ # List jobs
56
+ for job in client.jobs.list():
57
+ print(f"{job.job_id}: {job.state}")
58
+
59
+ # Get job details
60
+ job = client.jobs.get("job_id")
61
+
62
+ # Get job logs
63
+ logs = client.jobs.logs("job_id")
64
+
65
+ # Get GPU metrics
66
+ metrics = client.jobs.metrics("job_id")
67
+ for gpu in metrics.gpus:
68
+ print(f"GPU {gpu.index}: {gpu.utilization}% util, {gpu.temperature}°C")
69
+
70
+ # Cancel a job
71
+ client.jobs.cancel("job_id")
72
+
73
+ # Extend runtime
74
+ client.jobs.extend("job_id", runtime=7200)
75
+
76
+ # Get user info
77
+ user = client.user.get()
78
+ print(f"User: {user.email}")
79
+ ```
80
+
81
+ ## HyperAgent API
82
+
83
+ Use `client.agent` for discovery and plan metadata, and point the OpenAI SDK at
84
+ the HyperClaw inference base URL for chat completions:
85
+
86
+ ```python
87
+ from hypercli import HyperCLI
88
+ from openai import OpenAI
89
+
90
+ sdk = HyperCLI(api_key="hyper_api_key", agent_api_key="sk-agent")
91
+ plans = sdk.agent.plans()
92
+ activation = sdk.agent.redeem_grant_code("PROMO123")
93
+ renewal = sdk.agent.redeem_grant_code("PROMO123", extend_existing=True)
94
+
95
+ client = OpenAI(
96
+ api_key="your_hyperagent_api_key",
97
+ base_url="https://api.hypercli.com/v1"
98
+ )
99
+
100
+ response = client.chat.completions.create(
101
+ model="deepseek-v3.1",
102
+ messages=[{"role": "user", "content": "Hello!"}]
103
+ )
104
+ ```
105
+
106
+ `redeem_grant_code()` applies a promo/activation code to the current HyperClaw account and returns the created entitlement. Codes create new entitlements by default; pass `extend_existing=True` only for renewal/extension behavior.
107
+
108
+ ## OpenClaw Agents
109
+
110
+ OpenClaw uses the generic deployment launch surface. `registry_url`, `registry_auth`, `sync_root`, and `sync_enabled` are generic deployment options; the OpenClaw helpers only add defaults such as routes, image, and `sync_root=/home/node`.
111
+
112
+ ```python
113
+ agent = client.deployments.create_openclaw(
114
+ name="docs-demo",
115
+ start=True,
116
+ registry_url="git.nedos.co",
117
+ registry_auth={"username": "ci", "password": "token"},
118
+ )
119
+ ```
120
+
121
+ Use `create_openclaw_pro(...)` for the desktop/browser image. It enables noVNC through the protected `desktop-<agent>.hypercli.app` route and sets `OPENCLAW_DESKTOP_ENABLED=1`.
122
+
123
+ `heartbeat` maps directly to upstream OpenClaw config at `config.agents.defaults.heartbeat`. Omit it to keep upstream defaults, or pass values such as `heartbeat={"every": "1h", "target": "last"}`.
124
+
125
+ Automatic memory indexing is off by default. Opt in with `memory_index={"on_session_start": True, "on_search": True, "watch": True, "watch_debounce_ms": 30000, "interval_minutes": 0}`.
126
+
127
+ ## Hosted Coding Agents
128
+
129
+ OpenCode, Codex, Claude Code, Goose, and Kimi Code use canonical Reef images.
130
+ They have no public runtime port: lifecycle, exec, shell, workspace sync, and
131
+ authentication all use the existing authenticated deployment APIs. OpenCode
132
+ and Goose default to HyperCLI's Anthropic-native `kimi-k2.6-anthropic` route.
133
+ Kimi Code keeps Moonshot's upstream device login and service.
134
+
135
+ ```python
136
+ agent = client.deployments.create_opencode(name="opencode")
137
+ codex = client.deployments.create_codex(name="codex")
138
+ claude = client.deployments.create_claude_code(name="claude")
139
+ goose = client.deployments.create_goose(name="goose")
140
+ kimi = client.deployments.create_kimi_code(name="kimi")
141
+
142
+ methods = codex.auth.methods()
143
+ status = codex.auth.status()
144
+
145
+ async with await codex.auth.login("device") as login:
146
+ print(login.verification_url, login.user_code)
147
+ await login.wait()
148
+ ```
149
+
150
+ The login helper opens a short-lived, agent-bound shell WebSocket and runs the
151
+ runtime's native login command inside the Reef pod. It never puts an API key on
152
+ the command line. Runtime credentials and state live under the persistent
153
+ `/home/node` sync root.
154
+
155
+ The images default to a long-lived direct shell/exec container. A Buzz provider
156
+ launches one for a Buzz-managed identity with the typed launch contract:
157
+
158
+ ```python
159
+ from hypercli import BuzzLaunchConfig
160
+
161
+ agent = client.deployments.create_opencode(
162
+ name="buzz-opencode",
163
+ env={"HYPER_API_KEY": inference_key},
164
+ buzz=BuzzLaunchConfig(
165
+ private_key_nsec=agent_nsec,
166
+ relay_url=relay_url,
167
+ auth_tag=owner_signed_auth_tag,
168
+ parallelism=1,
169
+ ),
170
+ )
171
+ ```
172
+
173
+ The SDK selects `/usr/local/bin/buzz-acp`, the runtime-specific child ACP
174
+ command and arguments, the hosted Buzz MCP command, lazy pool creation, relay
175
+ observation, and persistent `/home/node` settings. Buzz-reserved environment
176
+ keys are rendered from the typed object after caller environment values.
177
+ `buzz_enabled=True` remains as a deprecated raw-environment compatibility path.
178
+ Typed and compatibility Buzz launches select the matching `hypercli-buzz`
179
+ image family (`opencode`, `codex`, `claude`, `goose`, or `kimi-code`) by
180
+ default. Ordinary coding-agent helpers without Buzz keep the generic
181
+ `ghcr.io/hypercli/hypercli-<runtime>:latest` default. An explicit `image=`
182
+ continues to override either default.
183
+
184
+ Direct `BuzzLaunchConfig` renders timeout and response-policy values but does
185
+ not duplicate the stock Desktop provider's validation; invalid combinations
186
+ are rejected later by `buzz-acp`. The Desktop provider also maps structured
187
+ Goose model/provider fields to `GOOSE_MODEL`/`GOOSE_PROVIDER`; direct Python
188
+ SDK callers must set any Goose-specific environment themselves.
189
+
190
+ Buzz launches require `size="large"`; ordinary coding-agent helpers preserve a
191
+ caller-provided size or the backend default. Stock Buzz provider agents do not
192
+ start on app launch and the current provider protocol has no stop callback.
193
+ Editing a running agent does not replace its HyperCLI launch environment: stop
194
+ the deployment through the authenticated HyperCLI API and deploy it again from
195
+ Buzz to apply changes. Desktop's best-effort `!shutdown` chat control may exit
196
+ the harness, but it does not stop or release the HyperCLI deployment.
197
+
198
+ Stock Buzz expects ACP NDJSON. It skips non-JSON child stdout, and
199
+ `agent_message_chunk` is activity telemetry rather than a channel reply. There
200
+ is no plaintext fallback; a visible reply requires the agent to invoke the Buzz
201
+ send command/tool. The five-runtime SDK coverage validates request rendering,
202
+ not live launches.
203
+
204
+ The agent nsec and caller environment become raw deployment environment values.
205
+ The HyperClaw backend currently persists them in `Agent.launch_config`, and
206
+ authenticated deployment read, environment, or exec surfaces may expose them.
207
+ The default `RUST_LOG` filter disables `acp::stream` content logging; overriding
208
+ it can expose generated text in container logs.
209
+
210
+ ## OpenClaw Node Egress
211
+
212
+ The Python SDK includes an experimental reference implementation for user-owned
213
+ node egress in `hypercli.openclaw.node_proxy`. It uses the existing OpenClaw
214
+ node model:
215
+
216
+ - a node connects to the gateway with `role="node"`
217
+ - the node declares explicit `egress.*` command names during the connect
218
+ handshake
219
+ - an operator/client calls `GatewayClient.node_invoke(node_id, command, params)`
220
+ - the gateway sends one `node.invoke.request` and waits for one
221
+ `node.invoke.result`
222
+
223
+ This is not raw sockets over the gateway. It is node RPC with chunked payloads
224
+ and gateway policy approval.
225
+
226
+ Node side:
227
+
228
+ ```python
229
+ from hypercli.openclaw import NodeEgressServer
230
+
231
+ node = NodeEgressServer(
232
+ "wss://my-agent.hypercli.app",
233
+ "home-linux-egress",
234
+ gateway_token="...",
235
+ )
236
+
237
+ await node.connect()
238
+ ```
239
+
240
+ Operator side:
241
+
242
+ ```python
243
+ from hypercli.openclaw import EGRESS_COMMANDS, NodeEgressClient
244
+
245
+ egress = NodeEgressClient(gateway, node_id="home-linux-egress")
246
+ res = await egress.http_fetch("https://example.com/")
247
+ ```
248
+
249
+ Commands:
250
+
251
+ - `egress.http.fetch`: bounded HTTP(S) fetch, response body returned as base64
252
+ chunks
253
+ - `egress.tcp.open/read/write/close`: experimental TCP tunnel primitives used
254
+ by `LoopbackNodeProxy` for HTTP `CONNECT`
255
+
256
+ Security defaults:
257
+
258
+ - local proxy binds to `127.0.0.1` by default
259
+ - node id is explicit; no automatic node selection
260
+ - RFC1918/private, loopback, link-local, multicast, reserved, and metadata IPs
261
+ are blocked by default unless explicitly allowed on the node
262
+ - chunks are small and bounded; responses are not returned as one unbounded
263
+ base64 blob
264
+
265
+ Pairing and policy:
266
+
267
+ - the node must be device-paired
268
+ - the node command surface must be approved
269
+ - custom `egress.*` commands may need `gateway.nodes.allowCommands`
270
+
271
+ Python/Linux is first because it is easiest to test in CI and the Python SDK
272
+ already ships `NodeServer`. The portable contract is the command surface and
273
+ payload shape, not the Python implementation. macOS Backseat Driver already
274
+ proves the native node-host precedent; Android should eventually gain Kotlin
275
+ `NodeRuntime` parity; the TS SDK can mirror operator/client types if useful.
276
+
277
+ `LoopbackNodeProxy` can relay absolute-form HTTP requests and has experimental
278
+ `CONNECT` support over polling/chunked `node.invoke`. Treat CONNECT as a
279
+ feasibility prototype, not production-grade streaming.
280
+
281
+ ## Error Handling
282
+
283
+ ```python
284
+ from hypercli import HyperCLI, APIError
285
+
286
+ client = HyperCLI()
287
+
288
+ try:
289
+ job = client.jobs.get("invalid_id")
290
+ except APIError as e:
291
+ print(f"Error {e.status_code}: {e.detail}")
292
+ ```
293
+
294
+ ## License
295
+
296
+ MIT