Repository navigation
feat(examples): add a Fabric load client for GPU autoscaling runs - #14192
Merged
Merged
Conversation
load.sh sends prompts to every agent that apply -o json reports, at most CONCURRENCY at a time, and reports each request's latency and errors. Hermes sandboxes get chat completions at their api service URL with the interface token read once through openshell sandbox exec; other sandboxes get fabric-agent-ctl invoke through openshell sandbox exec with the reported runtime ID. two-runtimes.yaml declares a Hermes and an OpenClaw sandbox on the chart's two releases, with the oidc profile and Hermes's API published through a BEARER_PASSTHROUGH service exposure. Co-authored-by: maggiezha <[email protected]>
Collaborator
Author
Authoring session — opening
|
Contributor
cv
enabled auto-merge (squash)
November 4, 2026 12:55
This was referenced Nov 4, 2026
cv
added a commit
that referenced
this pull request
Nov 11, 2026
…ms (#14413) The release notes now list every user-visible change on `v1` since the `v0.1.0-rc9` tag, including the breaking ones, and four example pages drop claims that later changes made false. ## Problem `docs/about/release-notes.md` listed three breaking changes and none of the features, fixes, and onboarding changes that reached `v1` after `v0.1.0-rc9`; it didn't name the configuration shapes the parser now rejects or the intent record version `v0.1.0-rc9` writes. Some example claims went stale: - `examples/spark/README.md` said the pinned OpenShell has the Podman TLS initialization blocker, NVIDIA/OpenShell#3427; its fix merged before OpenShell 0.1.0, and `v1` pins 0.1.7. - `examples/station/README.md` and `examples/gtc-dc/README.md` required exactly one visible GPU on the host; since #13929, `container.gpuDevices` lets a service on a host with more GPUs request one. - `examples/hcl/travel-team` said Fabric's Deep Agents adapter can't turn reasoning off, NVIDIA/NeMo-Fabric#433; NVIDIA/NeMo-Fabric#439 fixed that, and the pinned catalog's Deep Agents `reasoning_effort` accepts `none`. - The travel team cited #13313 for the booking key its service doesn't receive, but #13313 closed when `openshell_api` landed. ## Change - `docs/about/release-notes.md` gains "Changes Since v0.1.0-rc9", grouped by area, from the commits in `v0.1.0-rc9..origin/v1`; where a later commit changed an earlier one, the entry describes the current code, and changes added and removed after the tag aren't listed: - Agents and interfaces: #14037, #14038, #14269, #13981, #14024, #14186, #14052, #14385, #13971, #13858, #13947, #14039, #14042, #14044, #14343. - Inference: #13929, #14391, #14396, #14398, #14400, #13963, #13912, #13964, #14388, #14390, #14397. - Gateways and Kubernetes: #13909, #13970, #13922 (an existing namespace, refused at plan by #13756, is now bound; cluster-wide reads dropped), #14014, #14169, #13921. - Plan, apply, and diagnostics: #14224, #13756, #14141, #14133, #14135, #13775, #13744, #13701. - Onboarding: #13693, #13695, #13741, #13757, #13851, #13978, #14228, #14233, #14334, #14336. - Examples and builds: #14166, #14184, #14188, #14191, #14192, #14200, #13889, #14267, #14312, #14315, #14355, b30e9b4, #13781, #13813, #14246, and the pins in `versions.json` and `image/fabric/Dockerfile`. - Its breaking changes since the tag: - the intent record moving from 15, which `v0.1.0-rc9` writes, through 16 (#14266), 17 (#14343), 18 (#13929), 19 (#14391) and 20 (#14394); - name-keyed `sandboxes` and `inferenceProviders` (#13703, #13705); - a recipe `compatibility.gpu` outside every hardware profile (#13912); - model tuning the adapter doesn't accept (#14111), and Hermes's `max_tokens` losing its default (#14296); - `skills.paths` resolution (#14296); - endpoint and `networkCIDR` validation (#13847, #14081); - the HCL `gateway_values` attribute (#14014), and Kubernetes ownership receipts from before #13922 and #14014. The two earlier items stay, under their own heading. - `examples/spark/README.md` replaces the closed OpenShell#3427 blocker with the Podman and remote-model limits in `docs/resources/limits.md`. - `examples/station/README.md` and `examples/gtc-dc/README.md` require one GPU visible in the model container, and point to `container.gpuDevices` for a host with more. - `examples/hcl/travel-team/README.md` and `WALKTHROUGH.md` drop the NeMo-Fabric#433 limitation, and the travel team's booking-key statements link #14417 instead of #13313. Not listed, because both changes landed after the tag: Deep Agents Code (#14043, #14250), `compatibility.gpuCount` (#14391, #14394), and the "Creating infrastructure state" progress step (#14169, #14248). Checked and left unchanged: the root `README.md`, `crates/nemoclaw-onboarding/README.md`, `crates/nemoclaw-cli/assets/README.md`, `internal-docs/README.md`, the other example READMEs, and every example YAML header comment. The GPU autoscaling README and `load.sh` read the JSON fields `OperationResult` serializes, and NVIDIA/OpenShell#4287 is fixed only after the pinned 0.1.7. The two pre-tag release-note items still match the schema and SDK. `docs/README.md` is left to #14412, which retires the stale field reference snapshot it describes. Not verified: whether Hermes sends the booking key's placeholder to MCP servers; #14417 tracks the live check. ## Beyond CI Each relative link and anchor in the changed files resolves to an existing file and heading.
cv
pushed a commit
that referenced
this pull request
Nov 13, 2026
…14427) For Kubernetes users: `examples/kubernetes/hosted-nvidia.tf` now applies with its default workspace, the Kubernetes guide lists the NetworkPolicy enforcement that OpenShell requires, and the new `examples/kubernetes/managed-oidc.yaml` is a complete document for a managed gateway with the `oidc` profile and a registry pull Secret. ## Problem - `hosted-nvidia.tf`, which `examples/gtc-dc/kubernetes-amd64.tf` links to, defaults `workspace` to `gtc-dc-kubernetes-cloud`, 23 characters. The pinned OpenShell refuses a workspace name over 19 characters (`MAX_ROUTABLE_NAME_LEN`), and only when apply creates the workspace, after the gateway is installed. The run recorded on #14315 hit this. The HCL plan scenario passed, because plan doesn't create the workspace. - The guide's prerequisites didn't say that OpenShell requires a network plugin that enforces NetworkPolicy. OpenShell's NetworkPolicies are what keep a sandbox's workload pod off the network. Kubernetes accepts them without such a plugin, so nothing reports one that's missing. - No example used the `oidc` profile on its own, or `imagePullSecrets`. The only OIDC example, `gpu-autoscaling/two-runtimes.yaml`, depends on the GPU chart. The guide also didn't say: - that the gateway token needs the admin role; - how to create the `caConfigMap`; - how the OpenShell CLI signs in where no browser can open; - which role lets the CLI reach the deployment's workspace. ## Change - **`hosted-nvidia.tf`:** - Default `workspace` to `gtc-dc-k8s-cloud`. - Add a `validation` block with OpenShell's name rule: at most 19 characters, a DNS label, and no `--`. - `gtc-dc-kubernetes-amd64-hcl.tftest.hcl` plans the old default and expects that validation to fail. - `examples/gtc-dc/README.md` states the limit. - **Prerequisites (`kubernetes.md`):** add a network plugin that enforces ingress and egress NetworkPolicy, linked to OpenShell's requirement. Say that nothing reports a plugin that ignores NetworkPolicy. Add it to the threat model's "Relies on" column. - **`examples/kubernetes/managed-oidc.yaml`:** - An OpenClaw and a Hermes agent on the isolated network tier, sharing hosted NVIDIA inference. - The `oidc` profile with `caConfigMap` and a token, and `imagePullSecrets`. - The OIDC and registry sections of the guide link it. - **OIDC section:** - Add the `kubectl create configmap` command for `caConfigMap`. - The token needs the role `admin_role` names; without it, plan fails with `observation permission denied`. - When `scopes_claim` is set, the token also needs the same scopes as an external gateway's token. - **"Reach the Gateway from the OpenShell CLI":** - Add the client-credentials sign-in (`OPENSHELL_OIDC_CLIENT_SECRET`), with `openshell gateway login` to sign in again, because the pinned CLI doesn't renew that token (NVIDIA/OpenShell#4287). - Cite #14192's kind run of it beside #14131. - A token with the role `admin_role` names reaches the deployment's workspace. A token with only the role `user_role` names needs a platform admin to add its subject to the workspace first, and with only that role `openshell status` reports `authorization denied`. Left out: - An OpenShift copy of the OIDC example, because #13828 plans to fold the OpenShift examples into the Kubernetes ones. - Agent interfaces in the example, which no run here checked. - A `managed-oidc.yaml` row in `examples/kubernetes/README.md`, which #14428 adds; whichever of the two merges second adds the row. - Correcting the guide where it says the gateway requires its client certificate. The pinned gateway asks for one but doesn't require it: in the run below, a call with only an OIDC token succeeded, and the CLI worked with only the gateway's CA in its `mtls` directory. That fix touches text outside this change. ## Beyond CI - **`managed-oidc.yaml` on k3s:** applied on single-node k3s v1.37.1+k3s1 with Agent Sandbox 1.0.3, the `local-path` StorageClass, and k3s's NetworkPolicy controller. - Setup: - Images built from c5bf74d and pushed to a loopback registry. - Hosted NVIDIA inference. - The e2e test issuer in another namespace, with its CA in the `issuer-ca` ConfigMap. - The example with only its UID, context, namespace, issuer settings and image digests changed. - Results: - Plan and apply succeeded, and both agents replied through the gateway. - `registry-credentials` was on the gateway, supervisor and sandbox pods. - A second plan found no changes. - Destroy succeeded and kept the namespace, the gateway's volume and its Secrets. - **Token without the admin role:** on the same deployment, a token re-signed with only the user role made plan fail with `observation permission denied`. - **`hosted-nvidia.tf` on k3s, with its new default workspace:** the same cluster and images, with OpenTofu and the providers from a bundle built at c5bf74d. - Setup: the two claims prepared and labelled as `examples/gtc-dc/README.md` says. Only the provider versions, UID, context, namespace and images were set; `workspace` kept its default. - Init, validate, plan and apply succeeded, and OpenShell created the workspace `gtc-dc-k8s-cloud`. - OpenClaw and Hermes each replied `READY` through `fabric-agent-ctl invoke`, and each had its claim's `workspace/` and `artifacts/` mounted and writable. - A second plan found no changes. - The README's targeted destroy removed the gateway and both agents, and kept the storage resource and both claims. - **OpenShell CLI sign-in on a three-node cluster:** k3d v5.9.0 with k3s v1.37.1+k3s1 and Agent Sandbox 1.0.3, with Keycloak 26.4 in the cluster as the issuer and three confidential clients. The gateway was #14428's `published-nodeport.yaml`, which uses the same `oidc` profile; NemoClaw's own token came from one of the clients. - The guide's steps with the pinned CLI 0.1.7: the client certificate copied from `<release>-client-tls`, `SSL_CERT_FILE` set to the issuer's CA, then `openshell gateway add` with `OPENSHELL_OIDC_CLIENT_SECRET`. The CLI printed `Authenticated via client credentials`, and `openshell status` reported `Connected` and `Authenticated (OIDC)`. - This worked both through the port forward to the gateway pod and at the published endpoint. - With the admin role, `openshell sandbox list` listed the agent, and `openshell sandbox exec … fabric-agent-ctl invoke` got `READY`. - With only the user role, `openshell status` reported `Authenticated (OIDC; authorization denied)`, and sandbox commands failed with `not a member of workspace`. After `openshell workspace member add … --role user`, the same client listed and invoked the agent, and a NemoClaw plan still found no changes. - **Not run:** - The browser sign-in: no browser here. #14131 records one. - A cluster whose network plugin doesn't enforce NetworkPolicy. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Hai Nguyen <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Failure
The GPU autoscaling example has no way to load the chart's GPUs through the agents, which is what makes its autoscaler scale.
#14009 had load clients, but they sent each prompt with
kubectl execinto the sandbox pods, around the gateway's authentication, and read pod names and runtime IDs from NemoClaw'sterraform.tfstate.With the
developmentprofile that example uses, nobody but NemoClaw can authenticate to the gateway, so no supported client could reach the agents.Decision
Follows #14191 (merged), on which this was stacked.
examples/kubernetes/gpu-autoscaling/load.sh, a Bash script with the OpenShell CLI,curlandjq. It readsnemoclaw apply -o jsonand sendsPROMPTSprompts across the agents, at mostCONCURRENCYat a time throughxargs -P, then prints how many it sent and how many replied, the median, 95th-percentile and longest latency overall and per sandbox, up to 10 failures, and one reply per sandbox. It exits nonzero if any request failed. Each sandbox takes one of the two paths that need no state files orkubectl exec:apiinterface and anapiservice URL for the sandbox: OpenAI chat completions toserviceUrls.SANDBOX.api, through the gateway's port forward and with its client certificate. The script reads the interface token once, withopenshell sandbox exec … catand the reportedtokenPath, into a private temporary file.fabric-agent-ctl invokefor any other sandbox, such as OpenClaw or Deep Agents, throughopenshell sandbox execwithagents.SANDBOX.runtimeId(feat(sdk): report each agent's runtime ID in plan and apply results #14186).two-runtimes.yaml: a Hermes sandbox on the chart's vLLM release and an OpenClaw sandbox on its Ollama release, the two thatinstall-two-runtimes.shinstalls (docs(examples): run two GPU runtimes and read runtime IDs from apply #14191). It uses theoidcprofile, and declares Hermes'sapiinterface with aserviceExposuresentry usingBEARER_PASSTHROUGH, because OpenShell's defaultSTRIPdrops the token Hermes checks. Its Envoy Service names are the ones Envoy Gateway v1.8.3 created for those Gateways on kind; it shortens a Gateway's name to 48 characters before the hash.README.md: Drive Load Through the Agents, with the apply and run commands, the variables, and the limits: the gateway's one CPU forsandbox exec, Fabric's one invocation at a time per runtime, Hermes's 10 concurrent runs per sandbox, what a service URL skips, and that the CLI doesn't renew a client-credentials token (bug(cli): client-credentials gateway login stops working when the access token expires OpenShell#4287).From #14009's
e2e-fabric-load-test.pyand client scripts, this keeps the prompts, the per-request timeout, the success check onresult.statusandresult.output.response, and per-sandbox counts. It leaves out the HPA polling and the stop-at-ceiling logic, which belong to the chart andkubectl get hpa --watch; the OpenClaw tool pinning, which edited Fabric's generated configuration inside the sandbox; and the timeline and CSV output.Validation
cargo cionc6a581a9cf: all selected steps passed in 135 s; test ran 1,827 tests and lifecycle 101.cargo test -p nemoclaw-onboarding two_runtimesran the new file's onboarding journey.shellcheck0.11 (koalaman/shellcheck:stable) onload.sh: no findings.kindest/node:v1.37.0, Agent Sandbox 1.0.3, linux/arm64, no GPU), with resources I created and removed afterwards:Model: the chart from nemoclaw-community
cb46db83abinstalled withhelm, with Ollama andqwen3:0.6bon CPU, no GPU request or node selector, no ServiceMonitor or HPA, arm64 digests for Ollama 0.40.11 andnode:22-bookworm-slim, behind Envoy Gateway v1.8.3. Both sandboxes used its one Envoy Service, withmodel: qwen3:0.6b.Issuer: Keycloak 26.4 in the cluster, at
https://<kind node IP>:30443/realms/openshellwith a test CA, so that the gateway pod and the host see the same issuer URL, with a confidential client whose service account has the admin role in arolesclaim and audienceopenshell. The kind HCL cases' issuer serves only discovery and keys, with no token endpoint, so the OpenShell CLI can't sign in through it.Deployment:
two-runtimes.yamlwith the context, issuer, endpoints, model and image digests replaced, andopenclawandhermesbuilt for linux/arm64 and pushed to a registry on the kind network.nemoclaw apply -o jsonwith the bundle from this branch succeeded, and reportedserviceUrls.user-0000.apiashttps://nc-…--user-0000--api.openshell.localhost:8080/, both runtime IDs underagents, and the Hermes token path underinterfaces.CLI: the port forward and client certificate from
docs/kubernetes.md, thenopenshell gateway add … --oidc-client-idwithOPENSHELL_OIDC_CLIENT_SECRET(OpenShell 0.1.6):Authenticated via client credentials;openshell statusshowedAuthenticated (OIDC).Load:
PROMPTS=12 CONCURRENCY=4 load.sh apply.json:An earlier run of 8 prompts also got 8 replies. OpenClaw's replies don't answer the prompts, likely because of
qwen3:0.6bwith OpenClaw's tools; each invocation still reportedsucceededwith a response.Failures: with
TIMEOUT=5, both requests were reported as failed (curl: (28) Operation timed outandtimed out after 5 s), and the script exited 1.fabric-agent-ctl invokecommand as OpenClaw's.cargo ci live-kindandlive-docker; the change adds no image or Kubernetes code.