npx skills add ...
npx skills add nvidia/openshell --skill openshell-cli
Guide agents through using the OpenShell CLI (openshell) for sandbox management, gateway registration, provider configuration and refresh, policy iteration, settings, service exposure, BYOC workflows, and attached-provider inference. Covers basic through advanced multi-step workflows. Trigger keywords - openshell, sandbox create, sandbox exec, sandbox connect, logs, provider create, provider profile, provider refresh, policy set, policy get, settings, service expose, forward, port forward, BYOC, bring your own container, inference, use openshell, run openshell, CLI usage, manage sandbox, manage provider, gateway add, gateway select.
npx skills add nvidia/openshell --skill openshell-cli
Guide agents through using the openshell CLI for sandbox and platform management -- from basic operations to advanced multi-step workflows.
The OpenShell CLI (openshell) is the primary interface for managing sandboxes, providers, policies, settings, exposed services, and gateway registrations. Gateway service lifecycle is handled outside the CLI by packages, systemd, or Helm. This skill teaches agents how to orchestrate CLI commands for common and complex workflows.
Companion skill: For creating or modifying sandbox policy YAML content (network rules, L7 inspection, access presets), use the generate-sandbox-policy skill. This skill covers the CLI commands for the policy lifecycle; generate-sandbox-policy covers policy content authoring.
Self-teaching: The CLI has comprehensive built-in help. When you encounter a command or option not covered in this skill, walk the help tree:
This is your primary fallback. Use it freely -- the CLI's help output is authoritative and always up-to-date.
openshell is on the PATH. Follow the published installation guide when it is not installed.kubectl and Helm access to the target clusterUse openshell --help and nested --help output as the authority for the installed CLI version. Use the published documentation for product concepts and supported workflows:
Use this workflow when the user has a gateway endpoint and wants to get a sandbox running for the first time.
Use an http:// endpoint only for trusted local port-forwarding or a protected private path. For a gateway behind an authenticated reverse proxy, register its HTTPS endpoint with openshell gateway add https://gateway.example.com.
Confirm the gateway is reachable, authentication is valid or not required, and
the output shows a version. Status: Connected only proves the public health
endpoint is reachable; inspect the separate Authentication line before
running protected commands. openshell whoami reports the identity validated
by the gateway, including the subject an administrator uses for workspace
membership. Add --output json for automation.
The simplest way to get a sandbox running:
This creates a sandbox whose canonical main process is /bin/bash -l and
attaches your terminal to that retained process. Add --detach to return after
the sandbox becomes ready without attaching.
An explicit trailing command is foreground even when stdin or stdout is not a
terminal. The CLI streams its stdout and stderr and returns its exact exit
status. Exit code 0 leaves a retained sandbox in Completed; nonzero leaves it
in Error with MainProcessFailed. Use --no-keep to delete either result
after output drains, or --detach for a long-running service. Combine
--detach --no-keep when the gateway should run the service without a host
attachment and delete its sandbox after the service exits.
When supplying --name, use a portable DNS-1123 label: at most 63 lowercase alphanumeric or - characters, beginning and ending with an alphanumeric character. The Kubernetes driver rejects uppercase letters, underscores, dots, and other names that cannot become Kubernetes resource labels.
Provider attachment is explicit. Name each provider with --provider; the
trailing command does not select or attach one. If the named provider does not
exist but a profile with that ID is available, the CLI can create it from local
credentials:
The agent will be prompted interactively if credentials are missing.
Exit the sandbox shell (exit or Ctrl-D), then:
Providers supply credentials and provider-specific configuration to sandboxes. Provider profiles are import-only: a gateway serves exactly what an operator imported, and a new gateway serves an empty catalog. Never rely on a hard-coded type list or on a legacy alias such as gh or claude — --type matches a profile ID exactly. Discover the profiles available on the selected gateway:
The --from-existing flag discovers credentials from local state (e.g., gh auth tokens, Claude config files).
Bare KEY reads the value from the environment variable of that name and avoids placing the secret in shell history. Use KEY=VALUE only when the user explicitly accepts that exposure.
Other credential sources are --from-gcloud-adc for compatible profiles and --runtime-credentials when the gateway or sandbox resolves the required credentials at runtime.
Static provider credentials resolve only for hosts, ports, and paths declared by
the provider profile. Use provider profile export to inspect that boundary
when a placeholder is present but requests receive
credential_endpoint_mismatch. A profileless static provider fails closed
because the gateway cannot construct a binding.
When an inspected request receives request_authority_mismatch, compare its
HTTP authority with the CONNECT tunnel endpoint. The host and effective port
must match. For a tunnel to api.example.com:8443, send
Host: api.example.com:8443; Host: api.example.com omits the non-default
port and is rejected. An absolute-form request target must use the same
authority.
Profile-backed providers always contribute policy unless a gateway-global policy is active. Static credential endpoint binding remains independently enforced.
Use openshell sandbox provider status --help and the attach, detach, and update help to find the installed version's wait options. Add --wait when the next step depends on a provider change taking effect. Without it, a successful command only confirms that the gateway saved the change. Save the returned receipt_id to check that same change later, and inspect the result for every selected sandbox. Credential refresh status confirms that OpenShell obtained credentials; provider status confirms that the sandbox applied them, activated the policy, and updated the environment for new processes. If the status is superseded, explain that a later change replaced the request and inspect that change separately.
If attach, detach, or update reports CONFIG_OPERATION_STORAGE_UNCERTAIN, explain that the change may already be saved and its readiness receipt may be unavailable. Do not blindly retry the mutation. Inspect the provider and sandbox state and reconcile the saved change before deciding on another mutation; the error proves neither rollback nor readiness.
provider update does not take --type. It updates credentials, config, or credential expiry on the existing provider.
Use refresh commands only when the provider profile and gateway support refreshable credentials:
Prefer --secret-material-env KEY[=ENVVAR] for secret refresh material. --material KEY=VALUE is for non-secret material; --secret-material-key marks supplied material keys as secret.
The gateway stores secret refresh material through its active credential driver. With Vault selected, refresh tokens, client secrets, and private keys live in Vault alongside injectable provider credentials; refresh state contains only opaque handles. A credential-backend read or write failure makes refresh fail closed rather than falling back to inline storage. Before OpenShell 0.1.0, the gateway does not migrate legacy inline refresh material or move secrets between credential backends. Reconfigure affected grants after upgrading, and remove or reconfigure credentials while the original backend remains available before changing backends. Do not run mixed gateway versions against the same refresh records.
Gateway-managed refresh credentials use an identity-stable workload handle.
Routine automatic refresh and provider refresh rotate update the access token
behind that handle, so long-running processes do not need to restart. Running
processes must be restarted once when upgrading from revision-scoped
placeholders. A later provider refresh configure call is an explicit
reauthorization boundary: it revokes the previous handle, and processes holding
that handle fail closed until restarted.
While gateway-managed refresh is configured, provider update --credential
cannot replace or delete the refresh-owned primary credential or any co-minted
output. Use provider refresh rotate, reconfigure refresh, or delete refresh
before returning those keys to manual management. Unrelated provider fields
remain updateable.
When OAuth refresh fails, inspect the RECOVERY and FAILURE_CODE columns from
provider refresh status; do not infer the remedy from HTTP status or parse
LAST_ERROR. retry means the worker will try again, reauthorize means the
user must obtain a new OAuth grant and run provider refresh configure,
fix_configuration means an operator must repair the OAuth client, scopes, or
administrator policy, and investigate means the issuer returned an
unrecognized response. The gateway parks reauthorize records until a manual
rotate or reconfiguration. It retries
fix_configuration records hourly so externally repaired configuration can
recover without rapid token-endpoint traffic. The existing access credential
remains usable only until its recorded expiry.
Key flags:
--provider: Attach configured credential providers for API keys, tokens, and other secrets (repeatable)--policy: Custom policy YAML (otherwise uses built-in default or OPENSHELL_SANDBOX_POLICY env var)--gpu [COUNT]: Request the driver's default GPU selection or a specific GPU count--cpu, --memory: Set per-sandbox compute sizing. Docker/Podman apply limits; Kubernetes applies matching requests and limits.--driver-config-json: Pass experimental driver-specific sandbox configuration--template NAME: Create from a named sandbox workload template. Conflicts with inline workload flags such as --from, --gpu, --cpu, --memory, --env, and --driver-config-json.--label KEY=VALUE: Add labels for later selection (repeatable)--env KEY=VALUE: Set non-secret sandbox environment variables (repeatable); use --provider for credentials--tty: Allocate a retained PTY for the canonical main process--approval-mode manual|auto: Control handling of agent-authored policy proposals; manual is the default--upload <PATH>[:<DEST>]: Upload local files into the container working directory or an explicit destination--no-git-ignore: Disable .gitignore filtering for uploads--no-keep: Delete the sandbox after main output and the exit result drain--detach: Start the canonical main process without attaching--forward [BIND_ADDRESS:]PORT: Forward a local port and keep the sandbox alive--editor vscode|cursor: Open a remote editor after creation and keep the sandbox alive--detach adds no attachment grace period. When the canonical process exits,
its terminal phase is reported immediately. A foreground create declares one
expected main-process SSH attachment; cleanup finalizes after that connection
closes naturally. With --detach --no-keep, the gateway owns the detached
process lifecycle and deletes the ephemeral sandbox after terminal reporting
finishes.
Do not combine --upload with a trailing main command. Uploads currently finish
after the canonical process starts; create a scratch sandbox and use
sandbox exec, or build the files into the image.
Create from a reusable workload template when several sandboxes should share image, environment, sizing, or driver-specific configuration:
Direct sandbox create --driver-config-json remains valid for one-off
creates. Put driver config on a template only when it should be reused.
Template --image accepts an OCI image reference. If omitted, the gateway
applies its default sandbox image when creating a sandbox from the template.
Create-time policy, providers, labels, uploads, forwarding, editor launch, and
the initial command stay on sandbox create.
Most commands with an optional sandbox name use the last-used sandbox. Pass an explicit name in automation.
Attaches to the sandbox's existing canonical main process. Disconnecting leaves
that process running; reconnecting targets the same process instance and replays
recent output. Use sandbox exec --tty -- /bin/bash -l for a new shell. Press
Ctrl-P, then Ctrl-Q to disconnect without terminating main. Ctrl-C retains
its normal terminal behavior and interrupts the foreground process. Configure
VS Code Remote-SSH with:
Uploads honor .gitignore by default. Add --no-git-ignore only when ignored files are intentionally in scope.
Uploads preserve symlinks, including dangling symlinks, instead of dereferencing their targets. A symlink source bypasses Git-aware filtering so the link itself is archived.
When the upload destination is omitted, the CLI discovers the remote working directory. Uploading a named directory merges it into an existing directory of the same name, overwriting matching entries without deleting unrelated entries. Downloads accept paths relative to that working directory or absolute paths within it.
sandbox exec starts an independent sibling process, streams output, and exits
with the remote command's exit code. Use sandbox connect to attach to the
canonical main process.
Use --env only for non-secret values. Attach credentials to the sandbox with a
provider instead of passing API keys, tokens, or other secrets to sandbox exec.
Structured attachment output contains provider names, types, and sorted credential and config key names. It never contains credential, handle, or config values.
deletion accepted means cleanup is still pending. Inspect the sandbox until
it disappears before assuming completion. An already-absent sandbox succeeds;
missing workspaces and authorization failures remain errors. Do not blindly
retry by name if another process might have recreated that name.
Use stop to halt compute while retaining the sandbox and its persistent workspace:
Both commands default to the last-used sandbox. Stop stops background
forwards and waits for Stopped; start waits for Ready. Connect, exec,
file transfer, forwarding, and exposed services are unavailable while
stopped or completed. Starting a retained Completed or
Error/MainProcessFailed sandbox launches a fresh canonical-main instance and
invalidates SSH sessions from the previous runtime generation. Delete remains
the operation that removes retained state.
This is the most important multi-step workflow. It enables a tight feedback cycle where sandbox policy is refined based on observed activity.
Key concept: Policies have static fields (immutable after activation: filesystem_policy, landlock, process) and two dynamic fields: network_policies and network_middlewares. Both dynamic fields can be updated without recreating the sandbox when the selected compute driver supports live policy updates. Drivers without the standard supervisor fetch revisions through the sandbox configuration API and report whether they loaded them.
If startup reports ConfigurationInvalid, inspect openshell sandbox get and
repair the complete policy or provider set through the gateway. The workload
has not started on its first activation, so static fields can also be replaced
during this initial repair. A previously activated sandbox retains static-field
restrictions while restart admission is pending or rejected.
Before the gateway's 300-second repair window expires, successful validation
completes startup in place. Effective stored configuration changes and their
first failed load reset that window; repeated failures do not. After
ProvisioningTimedOut, inspect the retained record and cleanup status, repair
configuration, and explicitly run sandbox start once cleanup completes. A CLI
wait timeout is separate from this gateway deadline. Follow the
published policy repair guidance
and confirm current replacement/detach syntax with installed CLI help.
An endpoint with omitted protocol retains explicit-proxy behavior. Explicit
protocol: tcp requests policy DNS and transparent TCP and currently requires
the Docker or Podman runtime; unsupported runtimes reject the policy before starting the
workload rather than activating only part of the network contract.
Sandboxes stay alive by default for iteration. Add --no-keep only when the sandbox should be deleted automatically after the initial session.
In a separate terminal or as the agent:
Look for log lines with action: deny -- these indicate blocked network requests. The logs include:
The --full flag includes the effective policy, including provider-composed entries. Use --base instead when the editable base policy is needed without provider-composed entries. Before resubmitting a --full result, review composed entries and prefer incremental updates or the base policy when appropriate.
Edit current-policy.yaml to allow the blocked actions. For policy content authoring, delegate to the generate-sandbox-policy skill. That skill handles:
read-only, read-write, full)audit vs enforce)network_middlewares, host selection, HTTP request/response and WebSocket bindings, and fail_open or fail_closed behaviornetwork_policies and network_middlewares can be modified at runtime when the selected compute driver supports live policy updates. Use --wait to verify that the active runtime loaded the revision; do not infer enforcement from the gateway accepting the update. If filesystem_policy, landlock, or process need changes, the sandbox must be recreated. Built-in middleware such as openshell/regex needs no gateway registration. An operator-run middleware must already be registered under [[openshell.supervisor.middleware]]; changing that static registration requires a gateway restart.
Middleware can inspect HTTP requests, HTTP responses, or client WebSocket text
messages when the implementation advertises the matching binding. The built-in
openshell/regex supports request bodies and client WebSocket text messages.
Use the generate-sandbox-policy skill to choose attachments and failure policy,
and debug-openshell-cluster to investigate middleware failures.
The gateway validates the complete effective candidate—including attached
provider-profile policy—before it stores a direct update, incremental merge,
approved proposal, provider attachment, or profile update that affects attached
sandboxes. An ambiguity failure returns FAILED_PRECONDITION; the rejected
candidate does not create a policy revision or partially update affected
sandboxes. The same fail-closed response applies when credential_signing
does not have an attached AWS profile whose credential boundary covers the
endpoint, or an explicit binding to an endpointless AWS profile. Fix the
conflicting endpoint selectors or credential source and submit again.
The --wait flag blocks until the sandbox confirms the policy is loaded (polls every second). Exit codes:
Check that the latest revision shows status loaded. If failed, check the error column for details.
Return to Step 2. Continue monitoring logs and refining the policy until all required actions are allowed and no unnecessary permissions exist.
View all revisions to understand how the policy evolved:
Fetch a specific historical revision:
Gateway-global policy commands use --global and require confirmation unless --yes is supplied:
Avoid --yes during interactive work. A global policy locks policy control for all sandboxes on the gateway.
Sandboxes created with --approval-mode manual place every proposal in the review inbox. auto approves only valid effective-policy candidates with an empty prover delta; findings still require review. The CLI binds approval to the candidate's current review token. If live policy, provider, or credential inputs change, approval leaves the chunk pending with a refreshed candidate and requires a fresh review.
Review the proposed scope, candidate hash, prover findings, and application errors before approval. Treat rule approve-all --include-security-flagged as a high-risk bulk action.
Build a custom container image and run it as a sandbox.
The --from flag accepts an existing full image reference such as myregistry.com/img:tag, or a community sandbox name such as ollama. Build local Dockerfiles first with the same container engine as the local gateway, then pass the image tag.
Use docker build -t my-app:latest for Docker gateways. For Podman gateways, use podman build -t localhost/my-app:latest and pass localhost/my-app:latest to --from. For remote gateways, push the image to a registry reachable by the gateway. Bare community names resolve under ghcr.io/nvidia/openshell-community/sandboxes unless OPENSHELL_COMMUNITY_REGISTRY overrides the prefix.
For Docker and Podman gateways, custom images should declare a non-root OCI
USER. Each explicit process.run_as_user or process.run_as_group policy
field wins independently; omitted fields fall back to the image declaration.
An image with no USER fails before readiness unless policy supplies both
fields. Explicit numeric fields may use any UID/GID from 1 through
4294967294; 0 is root and 4294967295 is the invalid identity sentinel.
Warn users that low IDs can inherit permissions from matching accounts, image
files, mounted volumes, or devices.
The service is now reachable at localhost:8080.
Manage or iterate on the sandbox:
Use structured output when automation needs the tracked forward metadata and validated process state:
Each record includes workspace, sandbox, bind_address, port, pid, and
alive. The alive boolean validates the workspace-scoped sandbox and tracked
process identity; it does not probe the forwarded socket.
Create and forward in one command:
The --forward flag starts a background port forward before the command runs.
Support a human working in a sandbox while an agent monitors activity and refines the policy in parallel.
Create the sandbox and keep it alive:
Tell the user to connect in another shell:
Monitor denied activity:
When denied actions appear:
Prefer incremental updates for additive network changes:
openshell policy update work-session --add-endpoint api.github.com:443:read-only:rest:enforce --binary /usr/bin/gh --wait
openshell policy update work-session --rule-name allow_api_github_com_443 --binary /usr/bin/gh --add-allow 'api.github.com:443:POST:/repos/*/issues' --wait
A rule authorizes every binary it lists to reach every endpoint it lists, so
an update that adds a binary or an endpoint to an existing rule must declare
that rule's whole binary and endpoint scope. The gateway rejects an update
that would grant a binary-to-endpoint pair the update never asked for, and
the error names the binaries still missing. To grant one binary access to
only part of a rule's endpoints, send the narrow authorization under its own
--rule-name; it stays on its own rule instead of folding into the broader
one.
--add-allow and --add-deny require --rule-name and the complete binary scope through repeated --binary or explicit --any-binary. Declare every port on the endpoint in the operation, for example api.example.com:443,8443:POST:/admin. Use --endpoint-path to disambiguate endpoints within the selected rule; an explicitly empty path selects an endpoint without a path selector. The gateway rejects missing or mismatched scope before persistence. Inspect the current policy and confirm the intended affected scope; do not automatically fill declarations from current policy just to make a rejection pass.
Use full YAML replacement for broad changes or non-network fields, including
any change that would otherwise require restating a large existing scope:
openshell policy get work-session --full > policy.yaml
Modify the policy with the generate-sandbox-policy skill.
openshell policy set work-session --policy policy.yaml --wait
Verify with openshell policy list work-session.
The user does not need to disconnect. Policy updates are hot-reloaded; --wait blocks until the sandbox confirms the revision or the timeout expires. Delete the sandbox when the session ends:
Inference uses the same provider attachment workflow as other credentialed services. Import or select a profile that authorizes the provider's native endpoint, create the provider, and attach it only to sandboxes that need it:
The application owns the native base URL, model, request shape, and timeout.
Launch a new process after attachment readiness so it inherits the installed provider environment. Use the debug-inference skill for endpoint, policy, credential-binding, or migration failures.
For an ordinary static provider update, wait for the update and launch a new client process to obtain the new reference. Do not claim that readiness updates the environment of an existing process or retargets its old reference. Acknowledged detach revokes retained references and removes them from future process environments.
List, switch, and verify gateways:
Register or remove gateways:
https:// registrations default to edge authentication. Use gateway login and gateway logout to refresh or clear stored authentication. For an OIDC gateway, supply --oidc-issuer and, when needed, --oidc-client-id, --oidc-audience, and --oidc-scopes. If automatic OIDC refresh fails, protected commands stop before sending an RPC and direct the user to run openshell gateway login <name>; openshell status still reports gateway reachability and authentication separately. For remote mTLS gateways, use --remote USER@HOST or an ssh:// endpoint.
For one-off automation, --gateway-endpoint URL connects directly without stored metadata. Limit --gateway-insecure to explicitly trusted development endpoints.
Inspect a Kubernetes deployment:
For Docker, Podman, and VM-backed gateways, inspect the gateway process or container logs and the selected runtime directly.
Manage sandbox-scoped or gateway-global settings:
Global mutations prompt for confirmation. Use --yes only in reviewed automation.
policy_validation_failure_mode is gateway startup configuration, not a
mutable openshell settings key. Set it under [openshell.gateway] in
gateway.toml and restart the gateway. The security-first default is
fail_closed; retain_last_valid is an explicit availability tradeoff. OCSF
configuration events state whether the previous generation is active after a
runtime validation failure.
Use forward for local access and service for a gateway-managed HTTP endpoint:
Use openshell service list --all-workspaces for a Platform Admin view across
workspaces. A sandbox name and --all-workspaces are mutually exclusive.
Prefer loopback binds unless the user explicitly needs LAN-visible local access.
--helpWhen you encounter a command or option not covered in this skill:
openshell --help to see all command groups.openshell <group> --help to see subcommands (e.g., openshell sandbox --help).openshell <group> <cmd> --help for flags and usage (e.g., openshell sandbox create --help).The CLI help is always authoritative. If the help output contradicts this skill, follow the help output -- the CLI may have been updated since this skill was written.
| Skill | When to use |
|---|---|
generate-sandbox-policy | Creating or modifying policy YAML content (network rules, L7 inspection, access presets, endpoint configuration, and network middleware) |
debug-openshell-cluster | Diagnosing gateway deployment, runtime, or health failures |
debug-inference | Diagnosing attached-provider inference, native endpoints, host-backed models, and migration from the retired managed endpoint |