mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-26 06:52:57 +08:00
1 line
54 KiB
JSON
1 line
54 KiB
JSON
{"id":"tutorials/index","title":"Tutorials","url":"tutorials/index.html","last_modified":"2026-03-31T19:42:51.299632+00:00","book":{"title":"NVIDIA OpenShell Developer Guide","version":"latest"},"product":{"name":"OpenShell","version":"latest"},"description":"Step-by-step walkthroughs for OpenShell, from first sandbox to production-ready policies.","tags":["Tutorial","Sandbox","Policy"],"topics":["Generative AI","Cybersecurity"],"content_type":"index","content":"Tutorials Hands-on walkthroughs that teach OpenShell concepts by building real configurations. Each tutorial builds on the previous one, starting with core sandbox mechanics and progressing to production workflows. First Network Policy Create a sandbox, observe default-deny networking, apply a read-only L7 policy, and inspect audit logs. No AI agent required. Tutorial first-network-policy GitHub Push Access Launch Claude Code in a sandbox, diagnose a policy denial, and iterate on a custom GitHub policy from outside the sandbox. Tutorial github-sandbox Inference with Ollama Route inference through Ollama using cloud-hosted or local models, and verify it from a sandbox. Tutorial inference-ollama Local Inference with LM Studio Route inference to a local LM Studio server via the OpenAI or Anthropic compatible APIs. Tutorial local-inference-lmstudio","format":"text","summary":"Hands-on walkthroughs that teach OpenShell concepts by building real configurations. Each tutorial builds on the previous one, starting with core sandbox mechanics and progressing to production workflows.","headings":[{"text":"Tutorials","level":1}],"children":[{"id":"tutorials/first-network-policy","title":"Write Your First Sandbox Network Policy","url":"tutorials/first-network-policy.html","book":{"title":"NVIDIA OpenShell Developer Guide","version":"latest"},"product":{"name":"OpenShell","version":"latest"},"description":"See how OpenShell network policies work by creating a sandbox, observing default-deny in action, and applying a fine-grained L7 read-only rule.","tags":["Tutorial","Policy","Network Policy","Sandbox","Security"],"topics":["Generative AI","Cybersecurity"],"content_type":"tutorial","learning_level":"technical_beginner","audience":["engineer"],"content":"Write Your First Sandbox Network Policy This tutorial shows how OpenShell’s network policy system works in under five minutes. You create a sandbox, watch a request get blocked by the default-deny policy, apply a fine-grained L7 rule, and verify that reads are allowed while writes are blocked, all without restarting anything. After completing this tutorial, you understand: How default-deny networking blocks all outbound traffic from a sandbox. How to apply a network policy that grants read-only access to a specific API. How L7 enforcement distinguishes between HTTP methods such as GET and POST on the same endpoint. How to inspect deny logs for a complete audit trail. Prerequisites A working OpenShell installation. Complete the /get-started/quickstart before proceeding. Docker Desktop running on your machine. To run every step of this tutorial, you can also use the automated demo script at the examples/sandbox-policy-quickstart directory in the NVIDIA OpenShell repository. It runs the full walkthrough in under a minute but without any user interaction. $ bash examples/sandbox-policy-quickstart/demo.sh\nCreate a Sandbox Start by creating a sandbox with no network policies. This gives you a clean environment to observe default-deny behavior. $ openshell sandbox create --name demo --keep --no-auto-providers\nkeep keeps the sandbox running after you exit so you can reconnect later. --no-auto-providers skips the provider setup prompt since this tutorial uses curl instead of an AI agent. You land in an interactive shell inside the sandbox: sandbox@demo\nTry to Reach the GitHub API With no network policy in place, every outbound connection is blocked. Test this by making a simple API call from inside the sandbox: $ curl -s https://api.github.com/zen\nhttps://api.github.com/zen is a lightweight, unauthenticated GitHub REST endpoint that returns a random aphorism on each call. It requires no tokens or parameters, which makes it a convenient smoke-test target for verifying outbound HTTPS connectivity. The request fails. By default, all outbound network traffic is denied. The sandbox proxy intercepted the HTTPS CONNECT request to api.github.com:443 and rejected it because no network policy authorizes curl to reach that host. curl: (56) Received HTTP code 403 from proxy after CONNECT\nExit the sandbox. The --keep flag keeps it running: $ exit\nCheck the Deny Log Every denied connection produces a structured log entry. Query the sandbox logs from your host to confirm the denial and inspect the reason. $ openshell logs demo --since 5m\nYou see a line like: action=deny dst_host=api.github.com dst_port=443 binary=/usr/bin/curl deny_reason=\"no matching network policy\nEvery denied connection is logged with the destination, the binary that attempted it, and the reason. Nothing gets out silently. Apply a Read-Only GitHub API Policy To allow the sandbox to reach the GitHub API, define a network policy that grants read-only access. The policy specifies which host, port, binary, and HTTP methods are permitted. Create a file called github-readonly.yaml with the following content: version: 1\nfilesystem_policy\ninclude_workdir: true\nread_only: [/usr, /lib, /proc, /dev/urandom, /app, /etc, /var/log\nread_write: [/sandbox, /tmp, /dev/null\nlandlock\ncompatibility: best_effort\nprocess\nrun_as_user: sandbox\nrun_as_group: sandbox\nnetwork_policies\ngithub_api\nname: github-api-readonly\nendpoints\nhost: api.github.com\nport: 443\nprotocol: rest\nenforcement: enforce\naccess: read-only\nbinaries\n{ path: /usr/bin/curl\nThe filesystem_policy , landlock , and process sections preserve the default sandbox settings. This is required because policy set replaces the entire policy. The network_policies section is the key part: curl may make GET, HEAD, and OPTIONS requests to api.github.com over HTTPS. Everything else is denied. The proxy auto-detects TLS on HTTPS endpoints and terminates it to inspect each HTTP request and enforce the read-only access preset at the method level. Apply it: $ openshell policy set demo --policy github-readonly.yaml --wait\nwait blocks until the sandbox confirms the new policy is loaded. No restart required. Policies are hot-reloaded. This tutorial uses curl and read-only access to keep things simple. When building policies for real workloads: To scope the policy to an agent, replace the binaries section with your agent’s binary, such as /usr/local/bin/claude , instead of curl . To grant write access, change access: read-only to read-write or add explicit rules for specific paths. Refer to the /reference/policy-schema . To allow additional endpoints, stack multiple policies in the same file for PyPI, npm, or your internal APIs. Refer to /sandboxes/policies for examples. Verify If GET Requests Are Allowed The policy is now active. Reconnect to the sandbox and retry the same request to confirm that read access works. $ openshell sandbox connect demo\nRetry the same request: $ curl -s https://api.github.com/zen\nAnything added dilutes everything else\nIt works. The read-only preset allows GET requests through. Try a Write The read-only preset allows GET but blocks mutating methods like POST, PUT, and DELETE. Test this by sending a POST request to the GitHub API while still inside the sandbox: $ curl -s -X POST https://api.github.com/repos/octocat/hello-world/issues\nH \"Content-Type: application/json\"\nd '{\"title\":\"oops\nerror\":\"policy_denied\",\"policy\":\"github-api-readonly\",\"detail\":\"POST /repos/octocat/hello-world/issues not permitted by policy\nThe CONNECT request succeeded because api.github.com is allowed, but the L7 proxy inspected the HTTP method and returned 403 . POST is not in the read-only preset. An agent with this policy can read code from GitHub but cannot create issues, push commits, or modify anything. Exit the sandbox: $ exit\nCheck the L7 Deny Log L7 denials are logged separately from connection-level denials. The log entry includes the exact HTTP method and path that the proxy rejected. $ openshell logs demo --level warn --since 5m\nl7_decision=deny dst_host=api.github.com l7_action=POST l7_target=/repos/octocat/hello-world/issues l7_deny_reason=\"POST /repos/octocat/hello-world/issues not permitted by policy\nThe log captures the exact HTTP method, path, and deny reason. In production, pipe these logs to your SIEM for a complete audit trail of every request your agent makes. To log violations without blocking requests, set enforcement: audit instead of enforcement: enforce in the policy. This is useful for building a policy iteratively: deploy in audit mode, review the logs, and switch to enforce when the rules are correct. Clean Up Delete the sandbox to free resources. This stops all processes and purges any injected credentials. $ openshell sandbox delete demo\nTo run this entire walkthrough non-interactively, use the automated demo script: $ bash examples/sandbox-policy-quickstart/demo.sh\nNext Steps To walk through a full policy iteration with Claude Code, including diagnosing denials and applying fixes from outside the sandbox, refer to /tutorials/github-sandbox","format":"text","content_length":7068,"word_count":1021,"summary":"This tutorial shows how OpenShell’s network policy system works in under five minutes. You create a sandbox, watch a request get blocked by the default-deny policy, apply a fine-grained L7 rule, and verify that reads are allowed while writes are blocked, all without restarting anything.","headings":[{"text":"Write Your First Sandbox Network Policy","level":1,"id":"write-your-first-sandbox-network-policy"},{"text":"Prerequisites","level":2,"id":"prerequisites"},{"text":"Create a Sandbox","level":2,"id":"create-a-sandbox"},{"text":"Try to Reach the GitHub API","level":2,"id":"try-to-reach-the-github-api"},{"text":"Check the Deny Log","level":2,"id":"check-the-deny-log"},{"text":"Apply a Read-Only GitHub API Policy","level":2,"id":"apply-a-read-only-github-api-policy"},{"text":"Verify If GET Requests Are Allowed","level":2,"id":"verify-if-get-requests-are-allowed"},{"text":"Try a Write","level":2,"id":"try-a-write"},{"text":"Check the L7 Deny Log","level":2,"id":"check-the-l7-deny-log"},{"text":"Clean Up","level":2,"id":"clean-up"},{"text":"Next Steps","level":2,"id":"next-steps"}],"headings_text":"Write Your First Sandbox Network Policy Prerequisites Create a Sandbox Try to Reach the GitHub API Check the Deny Log Apply a Read-Only GitHub API Policy Verify If GET Requests Are Allowed Try a Write Check the L7 Deny Log Clean Up Next Steps","keywords":["access","action","after","allowed","anything","api","apis","apply","binary","check","claude","clean","code","com","compatibility","complete","content","create","curl","delete","deny","deny_reason","desktop","detail","docker","dst_host","dst_port","enforcement","every","everything","exit","first","github","github-api-readonly","host","https","include_workdir","iteratively","l7_action","l7_decision","l7_deny_reason","l7_target","like","log","name","network","next","nothing","only","oops\nerror"],"code_blocks":[{"content":"$ bash examples/sandbox-policy-quickstart/demo.sh","language":"text"},{"content":"$ openshell sandbox create --name demo --keep --no-auto-providers","language":"text"},{"content":"sandbox@demo:~$","language":"text"},{"content":"$ curl -s https://api.github.com/zen","language":"text"},{"content":"curl: (56) Received HTTP code 403 from proxy after CONNECT","language":"text"},{"content":"$ exit","language":"text"},{"content":"$ openshell logs demo --since 5m","language":"text"},{"content":"action=deny dst_host=api.github.com dst_port=443 binary=/usr/bin/curl deny_reason=\"no matching network policy\"","language":"text"},{"content":"version: 1\n\nfilesystem_policy:\n include_workdir: true\n read_only: [/usr, /lib, /proc, /dev/urandom, /app, /etc, /var/log]\n read_write: [/sandbox, /tmp, /dev/null]\nlandlock:\n compatibility: best_effort\nprocess:\n run_as_user: sandbox\n run_as_group: sandbox\n\nnetwork_policies:\n github_api:\n name: github-api-readonly\n endpoints:\n - host: api.github.com\n port: 443\n protocol: rest\n enforcement: enforce\n access: read-only\n binaries:\n - { path: /usr/bin/curl }","language":"text"},{"content":"$ openshell policy set demo --policy github-readonly.yaml --wait","language":"text"},{"content":"$ openshell sandbox connect demo","language":"text"},{"content":"$ curl -s https://api.github.com/zen","language":"text"},{"content":"Anything added dilutes everything else.","language":"text"},{"content":"$ curl -s -X POST https://api.github.com/repos/octocat/hello-world/issues \\\n -H \"Content-Type: application/json\" \\\n -d '{\"title\":\"oops\"}'","language":"text"},{"content":"{\"error\":\"policy_denied\",\"policy\":\"github-api-readonly\",\"detail\":\"POST /repos/octocat/hello-world/issues not permitted by policy\"}","language":"text"},{"content":"$ exit","language":"text"},{"content":"$ openshell logs demo --level warn --since 5m","language":"text"},{"content":"l7_decision=deny dst_host=api.github.com l7_action=POST l7_target=/repos/octocat/hello-world/issues l7_deny_reason=\"POST /repos/octocat/hello-world/issues not permitted by policy\"","language":"text"},{"content":"$ openshell sandbox delete demo","language":"text"},{"content":"$ bash examples/sandbox-policy-quickstart/demo.sh","language":"text"}],"links":[{"text":"Sandbox Policy Quickstart","type":"external","url":"https://github.com/NVIDIA/OpenShell/blob/main/examples/sandbox-policy-quickstart","original_text":"examples/sandbox-policy-quickstart"}],"images":[],"doc_type":"tutorial","section_path":["Tutorials","First Network Policy"]},{"id":"tutorials/github-sandbox","title":"Grant GitHub Push Access to a Sandboxed Agent","url":"tutorials/github-sandbox.html","book":{"title":"NVIDIA OpenShell Developer Guide","version":"latest"},"product":{"name":"OpenShell","version":"latest"},"description":"Learn the iterative policy workflow by launching a sandbox, diagnosing a GitHub access denial, and applying a custom policy to fix it.","tags":["Tutorial","GitHub","Sandbox","Policy","Claude Code"],"topics":["Generative AI","Cybersecurity"],"content_type":"tutorial","learning_level":"technical_intermediate","audience":["engineer"],"content":"Grant GitHub Push Access to a Sandboxed Agent This tutorial walks through an iterative sandbox policy workflow. You launch a sandbox, ask Claude Code to push code to GitHub, and observe the default network policy denying the request\nYou then diagnose the denial from your machine and from inside the sandbox, apply a policy update, and verify that the policy update to the sandbox takes effect. After completing this tutorial, you will have: A running sandbox with Claude Code that can push to a GitHub repository. A custom network policy that grants GitHub access for a specific repository. Experience with the policy iteration workflow: fail, diagnose, update, verify. This tutorial shows example prompts and responses from Claude Code. The exact wording you see might vary between sessions. Use the examples as a guide for the type of interaction, not as expected output. Prerequisites This tutorial requires the following: A working OpenShell installation. Complete the Quickstart before proceeding. A GitHub personal access token (PAT) with repo scope. Generate one from the GitHub personal access token settings page by selecting Generate new token (classic) and enabling the repo scope. An Anthropic account with access to Claude Code. OpenShell provides the sandbox runtime, not the agent. You must authenticate with your own account. A GitHub repository you own to use as the push target. A scratch repository is sufficient. You can create one with a README if needed. This tutorial uses two terminals to demonstrate the iterative policy workflow: Terminal 1 : The sandbox terminal. You create the sandbox in this terminal by running openshell sandbox create and interact with Claude Code inside it. Terminal 2 : A terminal outside the sandbox on your machine. You use this terminal for viewing the sandbox logs with openshell term and applying an updated policy with openshell policy set . Each section below indicates which terminal to use. Set Up a Sandbox with Your GitHub Token Depending on whether you start a new sandbox or use an existing sandbox, choose the appropriate tab and follow the instructions. Starting a new sandbox In terminal 2, create a new sandbox with Claude Code. The default policy is applied automatically, which allows read-only access to GitHub. Create a credential provider that injects your GitHub token into the sandbox automatically. The provider reads GITHUB_TOKEN from your host environment and sets it as an environment variable inside the sandbox: $ GITHUB_TOKEN=<your-token\nopenshell provider create --name my-github --type github --from-existing\nopenshell sandbox create --provider my-github -- claude\nopenshell sandbox create keeps the sandbox running after Claude Code exits, so you can apply policy updates later without recreating the environment. Add --no-keep if you want the sandbox deleted automatically instead. Claude Code starts inside the sandbox. It prints an authentication link. Open it in your browser, sign in to your Anthropic account, and return to the terminal. When prompted, trust the /sandbox workspace to allow Claude Code to read and write files. Using an existing sandbox In terminal 1, connect to a sandbox that is already running and set your GitHub token as an environment variable: $ openshell sandbox connect <sandbox-name\nexport GITHUB_TOKEN=<your-token\nTo find the name of running sandboxes, run openshell sandbox list in terminal 2. Push Code to GitHub In terminal 1, ask Claude Code to write a simple script and push it to your repository. Replace <org> with your GitHub organization or username and <repo> with your repository name. Prompt Write a hello_world.py script and push it to https://github.com/<org>/<repo> . Claude recognizes that it needs GitHub credentials. It asks how you want to authenticate. Provide your GitHub personal access token by pasting it into the conversation. Claude configures authentication and attempts the push. The push fails. Claude reports an error, but the failure is not an authentication problem. The default sandbox policy permits read-only access to GitHub and blocks write operations, so the proxy denies the push before the request reaches the GitHub server. Diagnose the Denial In this section, you diagnose the denial from your machine and from inside the sandbox. View the Logs from Your Machine In terminal 2, launch the OpenShell terminal: $ openshell term\nThe dashboard shows sandbox status and a live stream of policy decisions. Look for entries with l7_decision=deny . Select a deny entry to see the full detail: l7_action: PUT\nl7_target: /repos/<org>/<repo>/contents/hello_world.py\nl7_decision: deny\ndst_host: api.github.com\ndst_port: 443\nl7_protocol: rest\npolicy: github_rest_api\nl7_deny_reason: PUT /repos/<org>/<repo>/contents/hello_world.py not permitted by policy\nThe log shows that the sandbox proxy intercepted an outbound PUT request to api.github.com and denied it. The github_rest_api policy allows read operations (GET) but blocks write operations (PUT, POST, DELETE) to the GitHub API. A similar denial appears for github.com if Claude attempted a git push over HTTPS. Ask Claude Code to Check the Sandbox Logs In terminal 1, ask Claude Code to check the sandbox logs for denied requests: Prompt Check the sandbox logs for any denied network requests. What is blocking the push? Claude reads the deny entries and identifies the root cause. It explains that the failure is a sandbox network policy restriction, not a token permissions issue. For example, the following is a possible response: Response The sandbox runs a proxy that enforces policies on outbound traffic\nThe github_rest_api policy allows GET requests (used to read the file\nbut blocks PUT/write requests to GitHub. This is a sandbox-level restriction\nnot a token issue. No matter what token you provide, pushes through the API\nwill be blocked until the policy is updated. Both perspectives confirm the same thing: the proxy is doing its job. The default policy is designed to be restrictive. To allow GitHub pushes, you need to update the network policy. Copy the deny reason from Claude’s response. You paste it into an agent running on your machine in the next step. Update the Policy from Your Machine In terminal 2, paste the deny reason from the previous step into your coding agent on your machine, such as Claude Code or Cursor, and ask it to recommend a policy update. The deny reason gives the agent the context it needs to generate the correct policy rules. After pasting the following prompt sample, properly provide the GitHub organization and repository names of the repository you are pushing to. Prompt Based on the following deny reasons, recommend a sandbox policy update that allows GitHub pushes to https://github.com/<org>/<repo> , and save to /tmp/sandbox-policy-update.yaml : The filesystem_policy , landlock , and process sections are static. They are read once at sandbox creation and cannot be changed by a hot-reload. They are included here for completeness so the file is self-contained, but only the network_policies section takes effect when you apply this to a running sandbox. The following steps outline the expected process done by the agent: Inspects the deny reasons. Writes an updated policy that adds github_git and github_api blocks that grant write access to your repository. Saves the policy to /tmp/sandbox-policy-update.yaml . Review the Generated Policy Refer to the following policy example to compare with the generated policy before applying it. Confirm that the policy grants only the access you expect. In this case, git push operations and GitHub REST API access scoped to a single repository. Full reference policy The following YAML shows a complete policy that extends the default policy with GitHub access for a single repository. Replace <org> with your GitHub organization or username and <repo> with your repository name. The filesystem_policy , landlock , and process sections are static. They are read once at sandbox creation and cannot be changed by a hot-reload. They are included here for completeness so the file is self-contained, but only the network_policies section takes effect when you apply this to a running sandbox. version: 1\n── Static (locked at sandbox creation)\nfilesystem_policy\ninclude_workdir: true\nread_only\n/usr\n/lib\n/proc\n/dev/urandom\n/app\n/etc\n/var/log\nread_write\n/sandbox\n/tmp\n/dev/null\nlandlock\ncompatibility: best_effort\nprocess\nrun_as_user: sandbox\nrun_as_group: sandbox\n── Dynamic (hot-reloadable)\nnetwork_policies\nClaude Code ↔ Anthropic API\nclaude_code\nname: claude-code\nendpoints\n{ host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full\n{ host: statsig.anthropic.com, port: 443\n{ host: sentry.io, port: 443\n{ host: raw.githubusercontent.com, port: 443\n{ host: platform.claude.com, port: 443\nbinaries\n{ path: /usr/local/bin/claude\n{ path: /usr/bin/node\nNVIDIA inference endpoint\nnvidia_inference\nname: nvidia-inference\nendpoints\n{ host: integrate.api.nvidia.com, port: 443\nbinaries\n{ path: /usr/bin/curl\n{ path: /bin/bash\n{ path: /usr/local/bin/opencode\n── GitHub: git operations (clone, fetch, push)\ngithub_git\nname: github-git\nendpoints\nhost: github.com\nport: 443\nprotocol: rest\nenforcement: enforce\nrules\nallow\nmethod: GET\npath: \"/<org>/<repo>.git/info/refs\nallow\nmethod: POST\npath: \"/<org>/<repo>.git/git-upload-pack\nallow\nmethod: POST\npath: \"/<org>/<repo>.git/git-receive-pack\nbinaries\n{ path: /usr/bin/git\n── GitHub: REST API\ngithub_api\nname: github-api\nendpoints\nhost: api.github.com\nport: 443\nprotocol: rest\nenforcement: enforce\nrules\nGraphQL API (used by gh CLI\nallow\nmethod: POST\npath: \"/graphql\nFull read-write access to the repository\nallow\nmethod:\npath: \"/repos/<org>/<repo\nbinaries\n{ path: /usr/local/bin/claude\n{ path: /usr/local/bin/opencode\n{ path: /usr/bin/gh\n{ path: /usr/bin/curl\n── Package managers\npypi\nname: pypi\nendpoints\n{ host: pypi.org, port: 443\n{ host: files.pythonhosted.org, port: 443\n{ host: github.com, port: 443\n{ host: objects.githubusercontent.com, port: 443\n{ host: api.github.com, port: 443\n{ host: downloads.python.org, port: 443\nbinaries\n{ path: /sandbox/.venv/bin/python\n{ path: /sandbox/.venv/bin/python3\n{ path: /sandbox/.venv/bin/pip\n{ path: \"/sandbox/.uv/python/**/python*\"\n{ path: /usr/local/bin/uv\n{ path: \"/sandbox/.uv/python/**\"\n── VS Code Remote\nvscode\nname: vscode\nendpoints\n{ host: update.code.visualstudio.com, port: 443\n{ host: \"*.vo.msecnd.net\", port: 443\n{ host: vscode.download.prss.microsoft.com, port: 443\n{ host: marketplace.visualstudio.com, port: 443\n{ host: \"*.gallerycdn.vsassets.io\", port: 443\nbinaries\n{ path: /usr/bin/curl\n{ path: /usr/bin/wget\n{ path: \"/sandbox/.vscode-server/**\"\n{ path: \"/sandbox/.vscode-remote-containers/**\" } The following table summarizes the two GitHub-specific blocks: Block Endpoint Behavior github_git github.com:443 Git Smart HTTP protocol. The proxy auto-detects and terminates TLS to inspect requests. Permits info/refs (clone/fetch), git-upload-pack (fetch data), and git-receive-pack (push) for the specified repository. Denies all operations on unlisted repositories. github_api api.github.com:443 REST API. The proxy auto-detects and terminates TLS to inspect requests. Permits all HTTP methods for the specified repository and GraphQL queries. Denies API access to unlisted repositories. The remaining blocks ( claude_code , nvidia_inference , pypi , vscode ) are identical to the default policy . The default policy’s github_ssh_over_https and github_rest_api blocks are replaced by the github_git and github_api blocks above, which grant write access to the specified repository. Sandbox behavior outside of GitHub operations is unchanged. For details on policy block structure, refer to Policies . Apply the Policy After you have reviewed the generated policy, apply it to the running sandbox: $ openshell policy set <sandbox-name> --policy /tmp/sandbox-policy-update.yaml --wait\nNetwork policies are hot-reloadable. The --wait flag blocks until the policy engine confirms the new revision loaded, and the update takes effect immediately without restarting the sandbox or reconnecting Claude Code. Retry the Push In terminal 1, ask Claude Code to retry the push: The sandbox policy has been updated. Try pushing to the repository again\nThe push completes successfully. The openshell term dashboard now shows l7_decision=allow entries for api.github.com and github.com where it previously showed denials. Clean Up When you are finished, delete the sandbox to free cluster resources: $ openshell sandbox delete <sandbox-name\nNext Steps The following resources cover related topics in greater depth: To add per-repository access levels (read-write vs read-only) or restrict to specific API methods, refer to the Policy Schema Reference . To learn the full policy iteration workflow (pull, edit, push, verify), refer to /sandboxes/policies . To inject credentials automatically instead of pasting tokens, refer to /sandboxes/manage-providers","format":"text","content_length":12977,"word_count":1892,"summary":"This tutorial walks through an iterative sandbox policy workflow. You launch a sandbox, ask Claude Code to push code to GitHub, and observe the default network policy denying the request. You then diagnose the denial from your machine and from inside the sandbox, apply a policy update, and verify...","headings":[{"text":"Grant GitHub Push Access to a Sandboxed Agent","level":1,"id":"grant-github-push-access-to-a-sandboxed-agent"},{"text":"Prerequisites","level":2,"id":"prerequisites"},{"text":"Set Up a Sandbox with Your GitHub Token","level":2,"id":"set-up-a-sandbox-with-your-github-token"},{"text":"Push Code to GitHub","level":2,"id":"push-code-to-github"},{"text":"Diagnose the Denial","level":2,"id":"diagnose-the-denial"},{"text":"View the Logs from Your Machine","level":3,"id":"view-the-logs-from-your-machine"},{"text":"Ask Claude Code to Check the Sandbox Logs","level":3,"id":"ask-claude-code-to-check-the-sandbox-logs"},{"text":"Update the Policy from Your Machine","level":2,"id":"update-the-policy-from-your-machine"},{"text":"Review the Generated Policy","level":2,"id":"review-the-generated-policy"},{"text":"Apply the Policy","level":2,"id":"apply-the-policy"},{"text":"Retry the Push","level":2,"id":"retry-the-push"},{"text":"Clean Up","level":2,"id":"clean-up"},{"text":"Next Steps","level":2,"id":"next-steps"}],"headings_text":"Grant GitHub Push Access to a Sandboxed Agent Prerequisites Set Up a Sandbox with Your GitHub Token Push Code to GitHub Diagnose the Denial View the Logs from Your Machine Ask Claude Code to Check the Sandbox Logs Update the Policy from Your Machine Review the Generated Policy Apply the Policy Retry the Push Clean Up Next Steps","keywords":["access","add","after","agent","anthropic","api","apply","ask","based","behavior","block","blocks","both","check","claude","clean","code","com","compatibility","complete","confirm","copy","create","cursor","denial","denies","depending","depth","detail","diagnose","dst_host","dst_port","dynamic","each","endpoint","enforcement","experience","following","from","full","generate","generated","git","github","grant","graphql","have","host","https","include_workdir"],"code_blocks":[{"content":"$ GITHUB_TOKEN=<your-token>\n$ openshell provider create --name my-github --type github --from-existing\n$ openshell sandbox create --provider my-github -- claude","language":"text"},{"content":"$ openshell sandbox connect <sandbox-name>\n$ export GITHUB_TOKEN=<your-token>","language":"text"},{"content":"$ openshell term","language":"text"},{"content":"l7_action: PUT\nl7_target: /repos/<org>/<repo>/contents/hello_world.py\nl7_decision: deny\ndst_host: api.github.com\ndst_port: 443\nl7_protocol: rest\npolicy: github_rest_api\nl7_deny_reason: PUT /repos/<org>/<repo>/contents/hello_world.py not permitted by policy","language":"text"},{"content":"version: 1\n\n# ── Static (locked at sandbox creation) ──────────────────────────\n\nfilesystem_policy:\n include_workdir: true\n read_only:\n - /usr\n - /lib\n - /proc\n - /dev/urandom\n - /app\n - /etc\n - /var/log\n read_write:\n - /sandbox\n - /tmp\n - /dev/null\n\nlandlock:\n compatibility: best_effort\n\nprocess:\n run_as_user: sandbox\n run_as_group: sandbox\n\n# ── Dynamic (hot-reloadable) ─────────────────────────────────────\n\nnetwork_policies:\n\n # Claude Code ↔ Anthropic API\n claude_code:\n name: claude-code\n endpoints:\n - { host: api.anthropic.com, port: 443, protocol: rest, enforcement: enforce, access: full }\n - { host: statsig.anthropic.com, port: 443 }\n - { host: sentry.io, port: 443 }\n - { host: raw.githubusercontent.com, port: 443 }\n - { host: platform.claude.com, port: 443 }\n binaries:\n - { path: /usr/local/bin/claude }\n - { path: /usr/bin/node }\n\n # NVIDIA inference endpoint\n nvidia_inference:\n name: nvidia-inference\n endpoints:\n - { host: integrate.api.nvidia.com, port: 443 }\n binaries:\n - { path: /usr/bin/curl }\n - { path: /bin/bash }\n - { path: /usr/local/bin/opencode }\n\n # ── GitHub: git operations (clone, fetch, push) ──────────────\n\n github_git:\n name: github-git\n endpoints:\n - host: github.com\n port: 443\n protocol: rest\n enforcement: enforce\n rules:\n - allow:\n method: GET\n path: \"/<org>/<repo>.git/info/refs*\"\n - allow:\n method: POST\n path: \"/<org>/<repo>.git/git-upload-pack\"\n - allow:\n method: POST\n path: \"/<org>/<repo>.git/git-receive-pack\"\n binaries:\n - { path: /usr/bin/git }\n\n # ── GitHub: REST API ─────────────────────────────────────────\n\n github_api:\n name: github-api\n endpoints:\n - host: api.github.com\n port: 443\n protocol: rest\n enforcement: enforce\n rules:\n # GraphQL API (used by gh CLI)\n - allow:\n method: POST\n path: \"/graphql\"\n # Full read-write access to the repository\n - allow:\n method: \"*\"\n path: \"/repos/<org>/<repo>/**\"\n binaries:\n - { path: /usr/local/bin/claude }\n - { path: /usr/local/bin/opencode }\n - { path: /usr/bin/gh }\n - { path: /usr/bin/curl }\n\n # ── Package managers ─────────────────────────────────────────\n\n pypi:\n name: pypi\n endpoints:\n - { host: pypi.org, port: 443 }\n - { host: files.pythonhosted.org, port: 443 }\n - { host: github.com, port: 443 }\n - { host: objects.githubusercontent.com, port: 443 }\n - { host: api.github.com, port: 443 }\n - { host: downloads.python.org, port: 443 }\n binaries:\n - { path: /sandbox/.venv/bin/python }\n - { path: /sandbox/.venv/bin/python3 }\n - { path: /sandbox/.venv/bin/pip }\n - { path: \"/sandbox/.uv/python/**/python*\" }\n - { path: /usr/local/bin/uv }\n - { path: \"/sandbox/.uv/python/**\" }\n\n # ── VS Code Remote ──────────────────────────────────────────\n\n vscode:\n name: vscode\n endpoints:\n - { host: update.code.visualstudio.com, port: 443 }\n - { host: \"*.vo.msecnd.net\", port: 443 }\n - { host: vscode.download.prss.microsoft.com, port: 443 }\n - { host: marketplace.visualstudio.com, port: 443 }\n - { host: \"*.gallerycdn.vsassets.io\", port: 443 }\n binaries:\n - { path: /usr/bin/curl }\n - { path: /usr/bin/wget }\n - { path: \"/sandbox/.vscode-server/**\" }\n - { path: \"/sandbox/.vscode-remote-containers/**\" }","language":"text"},{"content":"$ openshell policy set <sandbox-name> --policy /tmp/sandbox-policy-update.yaml --wait","language":"text"},{"content":"The sandbox policy has been updated. Try pushing to the repository again.","language":"text"},{"content":"$ openshell sandbox delete <sandbox-name>","language":"text"}],"links":[{"text":"GitHub personal access token settings page","type":"external","url":"https://github.com/settings/tokens"},{"text":"Anthropic account","type":"external","url":"https://console.anthropic.com/"},{"text":"create one","type":"external","url":"https://github.com/new"}],"images":[],"doc_type":"tutorial","section_path":["Tutorials","Github Sandbox"]},{"id":"tutorials/inference-ollama","title":"Run Local Inference with Ollama","url":"tutorials/inference-ollama.html","book":{"title":"NVIDIA OpenShell Developer Guide","version":"latest"},"product":{"name":"OpenShell","version":"latest"},"description":"Run local and cloud models inside an OpenShell sandbox using the Ollama community sandbox, or route sandbox requests to a host-level Ollama server.","tags":["Tutorial","Inference Routing","Ollama","Local Inference","Sandbox"],"topics":["Generative AI","Cybersecurity"],"content_type":"tutorial","learning_level":"technical_intermediate","audience":["engineer"],"content":"Run Local Inference with Ollama This tutorial covers two ways to use Ollama with OpenShell: Ollama sandbox (recommended) — a self-contained sandbox with Ollama, Claude Code, and Codex pre-installed. One command to start. Host-level Ollama — run Ollama on the gateway host and route sandbox inference to it. Useful when you want a single Ollama instance shared across multiple sandboxes. After completing this tutorial, you will know how to: Launch the Ollama community sandbox for a batteries-included experience. Use ollama launch to start coding agents inside a sandbox. Expose a host-level Ollama server to sandboxes through inference.local . Prerequisites A working OpenShell installation. Complete the /get-started/quickstart before proceeding. Option A: Ollama Community Sandbox (Recommended) The Ollama community sandbox bundles Ollama, Claude Code, OpenCode, and Codex into a single image. Ollama starts automatically when the sandbox launches. Step 1: Create the Sandbox $ openshell sandbox create --from ollama\nThis pulls the community sandbox image, applies the bundled policy, and drops you into a shell with Ollama running. Step 2: Chat with a Model Chat with a local model $ ollama run qwen3.5\nOr a cloud model $ ollama run kimi-k2.5:cloud\nOr use ollama launch to start a coding agent with Ollama as the model backend: $ ollama launch claude\nollama launch codex\nollama launch opencode\nFor CI/CD and automated workflows, ollama launch supports a headless mode: $ ollama launch claude --yes --model qwen3.5\nModel Recommendations Use case Model Notes Smoke test qwen3.5:0.8b Fast, lightweight, good for verifying setup Coding and reasoning qwen3.5 Strong tool calling support for agentic workflows Complex tasks nemotron-3-super 122B parameter model, needs 48GB+ VRAM No local GPU qwen3.5:cloud Runs on Ollama’s cloud infrastructure, no ollama pull required Cloud models use the :cloud tag suffix and do not require local hardware. $ openshell sandbox create --from ollama\nTool Calling Agentic workflows (Claude Code, Codex, OpenCode) rely on tool calling. The following models have reliable tool calling support: Qwen 3.5, Nemotron-3-Super, GLM-5, and Kimi-K2.5. Check the Ollama model library for the latest models. Updating Ollama To update Ollama inside a running sandbox: $ update-ollama\nOr auto-update on every sandbox start: $ openshell sandbox create --from ollama -e OLLAMA_UPDATE=1\nOption B: Host-Level Ollama Use this approach when you want a single Ollama instance on the gateway host, shared across multiple sandboxes through inference.local . This approach uses Ollama because it is easy to install and run locally, but you can substitute other inference engines such as vLLM, SGLang, TRT-LLM, and NVIDIA NIM by changing the startup command, base URL, and model name. Step 1: Install and Start Ollama Install Ollama on the gateway host: $ curl -fsSL https://ollama.com/install.sh | sh\nStart Ollama on all interfaces so it is reachable from sandboxes: $ OLLAMA_HOST=0.0.0.0:11434 ollama serve\nIf you see Error: listen tcp 0.0.0.0:11434: bind: address already in use , Ollama is already running as a system service. Stop it first: $ systemctl stop ollama\nOLLAMA_HOST=0.0.0.0:11434 ollama serve\nStep 2: Pull a Model In a second terminal, pull a model: $ ollama run qwen3.5:0.8b\nType /bye to exit the interactive session. The model stays loaded. Step 3: Create a Provider Create an OpenAI-compatible provider pointing at the host Ollama: $ openshell provider create\nname ollama\ntype openai\ncredential OPENAI_API_KEY=empty\nconfig OPENAI_BASE_URL=http://host.openshell.internal:11434/v1\nOpenShell injects host.openshell.internal so sandboxes and the gateway can reach the host machine. You can also use the host’s LAN IP. Step 4: Set Inference Routing $ openshell inference set --provider ollama --model qwen3.5:0.8b\nConfirm: $ openshell inference get\nStep 5: Verify from a Sandbox $ openshell sandbox create --\ncurl https://inference.local/v1/chat/completions\njson '{\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}],\"max_tokens\":10\nThe response should be JSON from the model. Troubleshooting Common issues and fixes: Ollama not reachable from sandbox — Ollama must be bound to 0.0.0.0 , not 127.0.0.1 . This applies to host-level Ollama only; the community sandbox handles this automatically. OPENAI_BASE_URL wrong — Use http://host.openshell.internal:11434/v1 , not localhost or 127.0.0.1 . Model not found — Run ollama ps to confirm the model is loaded. Run ollama pull <model> if needed. HTTPS vs HTTP — Code inside sandboxes must call https://inference.local , not http:// . AMD GPU driver issues — Ollama v0.18+ requires ROCm 7 drivers for AMD GPUs. Update your drivers if you see GPU detection failures. Useful commands: $ openshell status\nopenshell inference get\nopenshell provider get ollama\nNext Steps To learn more about managed inference, refer to /inference/index . To configure a different self-hosted backend, refer to /inference/configure . To explore more community sandboxes, refer to /sandboxes/community-sandboxes","format":"text","content_length":5050,"word_count":743,"summary":"This tutorial covers two ways to use Ollama with OpenShell:","headings":[{"text":"Run Local Inference with Ollama","level":1,"id":"run-local-inference-with-ollama"},{"text":"Prerequisites","level":2,"id":"prerequisites"},{"text":"Option A: Ollama Community Sandbox (Recommended)","level":2,"id":"option-a-ollama-community-sandbox-recommended"},{"text":"Step 1: Create the Sandbox","level":3,"id":"step-1-create-the-sandbox"},{"text":"Tool Calling","level":3,"id":"tool-calling"},{"text":"Updating Ollama","level":3,"id":"updating-ollama"},{"text":"Option B: Host-Level Ollama","level":2,"id":"option-b-host-level-ollama"},{"text":"Step 1: Install and Start Ollama","level":3,"id":"step-1-install-and-start-ollama"},{"text":"Step 2: Pull a Model","level":3,"id":"step-2-pull-a-model"},{"text":"Step 3: Create a Provider","level":3,"id":"step-3-create-a-provider"},{"text":"Step 4: Set Inference Routing","level":3,"id":"step-4-set-inference-routing"},{"text":"Step 5: Verify from a Sandbox","level":3,"id":"step-5-verify-from-a-sandbox"},{"text":"Troubleshooting","level":2,"id":"troubleshooting"},{"text":"Next Steps","level":2,"id":"next-steps"}],"headings_text":"Run Local Inference with Ollama Prerequisites Option A: Ollama Community Sandbox (Recommended) Step 1: Create the Sandbox Tool Calling Updating Ollama Option B: Host-Level Ollama Step 1: Install and Start Ollama Step 2: Pull a Model Step 3: Create a Provider Step 4: Set Inference Routing Step 5: Verify from a Sandbox Troubleshooting Next Steps","keywords":["after","agentic","backend","bind","calling","chat","check","claude","cloud","code","codex","coding","com","commands","common","community","complete","complex","confirm","content","create","error","expose","fast","first","fixes","from","gpus","hello","host","http","https","inference","install","internal","kimi","launch","level","local","max_tokens","messages","mode","model","nemotron","next","notes","ollama","openai","opencode","openshell"],"code_blocks":[{"content":"$ openshell sandbox create --from ollama","language":"text"},{"content":"$ ollama run qwen3.5","language":"text"},{"content":"$ ollama run kimi-k2.5:cloud","language":"text"},{"content":"$ ollama launch claude\n$ ollama launch codex\n$ ollama launch opencode","language":"text"},{"content":"$ ollama launch claude --yes --model qwen3.5","language":"text"},{"content":"$ openshell sandbox create --from ollama","language":"text"},{"content":"$ update-ollama","language":"text"},{"content":"$ openshell sandbox create --from ollama -e OLLAMA_UPDATE=1","language":"text"},{"content":"$ curl -fsSL https://ollama.com/install.sh | sh","language":"text"},{"content":"$ OLLAMA_HOST=0.0.0.0:11434 ollama serve","language":"text"},{"content":"$ systemctl stop ollama\n$ OLLAMA_HOST=0.0.0.0:11434 ollama serve","language":"text"},{"content":"$ ollama run qwen3.5:0.8b","language":"text"},{"content":"$ openshell provider create \\\n --name ollama \\\n --type openai \\\n --credential OPENAI_API_KEY=empty \\\n --config OPENAI_BASE_URL=http://host.openshell.internal:11434/v1","language":"text"},{"content":"$ openshell inference set --provider ollama --model qwen3.5:0.8b","language":"text"},{"content":"$ openshell inference get","language":"text"},{"content":"$ openshell sandbox create -- \\\n curl https://inference.local/v1/chat/completions \\\n --json '{\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}],\"max_tokens\":10}'","language":"text"},{"content":"$ openshell status\n$ openshell inference get\n$ openshell provider get ollama","language":"text"}],"links":[{"text":"Ollama model library","type":"external","url":"https://ollama.com/library"},{"text":"Ollama","type":"external","url":"https://ollama.com/"}],"images":[],"doc_type":"tutorial","section_path":["Tutorials","Inference Ollama"]},{"id":"tutorials/local-inference-lmstudio","title":"Route Local Inference Requests to LM Studio","url":"tutorials/local-inference-lmstudio.html","book":{"title":"NVIDIA OpenShell Developer Guide","version":"latest"},"product":{"name":"OpenShell","version":"latest"},"description":"Configure inference.local to route sandbox requests to a local LM Studio server running on the gateway host.","tags":["Tutorial","Inference Routing","LM Studio","Local Inference","Sandbox"],"topics":["Generative AI","Cybersecurity"],"content_type":"tutorial","learning_level":"technical_intermediate","audience":["engineer"],"content":"Route Local Inference Requests to LM Studio This tutorial describes how to configure OpenShell to route inference requests to a local LM Studio server. The LM Studio server provides easy setup with both OpenAI and Anthropic compatible endpoints. This tutorial will cover: Expose a local inference server to OpenShell sandboxes. Verify end-to-end inference from inside a sandbox. Prerequisites First, complete OpenShell installation and follow the /get-started/quickstart . Install the LM Studio app . Make sure that your LM Studio is running in the same environment as your gateway. If you prefer to work without having to keep the LM Studio app open, download llmster (headless LM Studio) with the following command: Linux/Mac $ curl -fsSL https://lmstudio.ai/install.sh | bash\nWindows $ irm https://lmstudio.ai/install.ps1 | iex\nAnd start llmster: $ lms daemon up\nStep 1: Start LM Studio Local Server Start the LM Studio local server from the Developer tab, and verify the OpenAI-compatible endpoint is enabled. LM Studio will listen to 127.0.0.1:1234 by default. For use with OpenShell, you’ll need to configure LM Studio to listen on all interfaces ( 0.0.0.0 ). If you’re using the GUI, go to the Developer Tab, select Server Settings, then enable Serve on Local Network. If you’re using llmster in headless mode, run lms server start --bind 0.0.0.0 . Step 2: Test with a small model In the LM Studio app, head to the Model Search tab to download a small model like Qwen3.5 2B. In the terminal, use the following command to download and load the model: $ lms get qwen/qwen3.5-2b\nlms load qwen/qwen3.5-2b\nStep 3: Add LM Studio as a provider Choose the provider type that matches the client protocol you want to route through inference.local . OpenAI-compatible Add LM Studio as an OpenAI-compatible provider through host.openshell.internal : $ openshell provider create\nname lmstudio\ntype openai\ncredential OPENAI_API_KEY=lmstudio\nconfig OPENAI_BASE_URL=http://host.openshell.internal:1234/v1\nUse this provider for clients that send OpenAI-compatible requests such as POST /v1/chat/completions or POST /v1/responses . Anthropic-compatible Add a provider that points to LM Studio’s Anthropic-compatible POST /v1/messages endpoint: $ openshell provider create\nname lmstudio-anthropic\ntype anthropic\ncredential ANTHROPIC_API_KEY=lmstudio\nconfig ANTHROPIC_BASE_URL=http://host.openshell.internal:1234\nUse this provider for Anthropic-compatible POST /v1/messages requests. Step 4: Configure LM Studio as the local inference provider Set the managed inference route for the active gateway: OpenAI-compatible $ openshell inference set --provider lmstudio --model qwen/qwen3.5-2b\nIf the command succeeds, OpenShell has verified that the upstream is reachable and accepts the expected OpenAI-compatible request shape. Anthropic-compatible $ openshell inference set --provider lmstudio-anthropic --model qwen/qwen3.5-2b\nIf the command succeeds, OpenShell has verified that the upstream is reachable and accepts the expected Anthropic-compatible request shape. The active inference.local route is gateway-scoped, so only one provider and model pair is active at a time. Re-run openshell inference set whenever you want to switch between OpenAI-compatible and Anthropic-compatible clients. Confirm the saved config: $ openshell inference get\nYou should see either Provider: lmstudio or Provider: lmstudio-anthropic , along with Model: qwen/qwen3.5-2b . Step 5: Verify from Inside a Sandbox Run a simple request through https://inference.local : OpenAI-compatible openshell sandbox create --\ncurl https://inference.local/v1/chat/completions\njson '{\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}],\"max_tokens\":10\nopenshell sandbox create --\ncurl https://inference.local/v1/responses\njson\ninstructions\": \"You are a helpful assistant\ninput\": \"hello\nmax_output_tokens\": 10\nAnthropic-compatible openshell sandbox create --\ncurl https://inference.local/v1/messages\njson '{\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}],\"max_tokens\":10\nTroubleshooting If setup fails, check these first: LM Studio local server is running and reachable from the gateway host OPENAI_BASE_URL uses http://host.openshell.internal:1234/v1 when you use an openai provider ANTHROPIC_BASE_URL uses http://host.openshell.internal:1234 when you use an anthropic provider The gateway and LM Studio run on the same machine or a reachable network path The configured model name matches the model exposed by LM Studio Useful commands: $ openshell status\nopenshell inference get\nopenshell provider get lmstudio\nopenshell provider get lmstudio-anthropic\nNext Steps To learn more about using the LM Studio CLI, refer to LM Studio docs To learn more about managed inference, refer to /inference/index . To configure a different self-hosted backend, refer to /inference/configure","format":"text","content_length":4825,"word_count":650,"summary":"This tutorial describes how to configure OpenShell to route inference requests to a local LM Studio server.","headings":[{"text":"Route Local Inference Requests to LM Studio","level":1,"id":"route-local-inference-requests-to-lm-studio"},{"text":"Prerequisites","level":2,"id":"prerequisites"},{"text":"Linux/Mac","level":3,"id":"linuxmac"},{"text":"Windows","level":3,"id":"windows"},{"text":"Step 1: Start LM Studio Local Server","level":2,"id":"step-1-start-lm-studio-local-server"},{"text":"Step 2: Test with a small model","level":2,"id":"step-2-test-with-a-small-model"},{"text":"Step 3: Add LM Studio as a provider","level":2,"id":"step-3-add-lm-studio-as-a-provider"},{"text":"Step 4: Configure LM Studio as the local inference provider","level":2,"id":"step-4-configure-lm-studio-as-the-local-inference-provider"},{"text":"Step 5: Verify from Inside a Sandbox","level":2,"id":"step-5-verify-from-inside-a-sandbox"},{"text":"Troubleshooting","level":2,"id":"troubleshooting"},{"text":"Next Steps","level":2,"id":"next-steps"}],"headings_text":"Route Local Inference Requests to LM Studio Prerequisites Linux/Mac Windows Step 1: Start LM Studio Local Server Step 2: Test with a small model Step 3: Add LM Studio as a provider Step 4: Configure LM Studio as the local inference provider Step 5: Verify from Inside a Sandbox Troubleshooting Next Steps","keywords":["add","anthropic","choose","command","commands","config","configure","confirm","content","cover","developer","endpoint","expose","first","from","gateway","hello","http","https","inference","inside","install","internal","linux","llmster","local","mac","make","max_tokens","messages","model","network","next","openai","openshell","prerequisites","provider","qwen3","requests","role","route","run","sandbox","search","serve","server","set","settings","small","start"],"code_blocks":[{"content":"$ curl -fsSL https://lmstudio.ai/install.sh | bash","language":"text"},{"content":"$ irm https://lmstudio.ai/install.ps1 | iex","language":"text"},{"content":"$ lms daemon up","language":"text"},{"content":"$ lms get qwen/qwen3.5-2b\n$ lms load qwen/qwen3.5-2b","language":"text"},{"content":"$ openshell provider create \\\n --name lmstudio \\\n --type openai \\\n --credential OPENAI_API_KEY=lmstudio \\\n --config OPENAI_BASE_URL=http://host.openshell.internal:1234/v1","language":"text"},{"content":"$ openshell provider create \\\n --name lmstudio-anthropic \\\n --type anthropic \\\n --credential ANTHROPIC_API_KEY=lmstudio \\\n --config ANTHROPIC_BASE_URL=http://host.openshell.internal:1234","language":"text"},{"content":"$ openshell inference set --provider lmstudio --model qwen/qwen3.5-2b","language":"text"},{"content":"$ openshell inference set --provider lmstudio-anthropic --model qwen/qwen3.5-2b","language":"text"},{"content":"$ openshell inference get","language":"text"},{"content":"openshell sandbox create -- \\\n curl https://inference.local/v1/chat/completions \\\n --json '{\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}],\"max_tokens\":10}'\n\nopenshell sandbox create -- \\\n curl https://inference.local/v1/responses \\\n --json '{\n \"instructions\": \"You are a helpful assistant.\",\n \"input\": \"hello\",\n \"max_output_tokens\": 10\n }'","language":"text"},{"content":"openshell sandbox create -- \\\n curl https://inference.local/v1/messages \\\n --json '{\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}],\"max_tokens\":10}'","language":"text"},{"content":"$ openshell status\n$ openshell inference get\n$ openshell provider get lmstudio\n$ openshell provider get lmstudio-anthropic","language":"text"}],"links":[{"text":"Install the LM Studio app","type":"external","url":"https://lmstudio.ai/download"},{"text":"LM Studio docs","type":"external","url":"https://lmstudio.ai/docs/cli"}],"images":[],"doc_type":"tutorial","section_path":["Tutorials","Local Inference Lmstudio"]}]} |