Repository navigation
feat(assistant): run Python and bash in an OpenShell sandbox per conversation - #473
Merged
Merged
Conversation
…ersation The assistant gets run_python, run_bash, sandbox_files and import_sandbox_file once an admin turns on Settings > Code sandbox (sandbox.enabled, off by default) and points Lens at an NVIDIA OpenShell gateway. Each conversation gets its own sandbox (lens-chat-<id>) with none of Lens's data or keys, no egress unless sandbox.network allows the package registries or public addresses, and its files kept between runs. Attachments go in by id; a file comes out only through an import_files approval. With the network on, a run after outside text asks first. Idle sandboxes are stopped and unused ones deleted by the routines loop, and deleting a conversation deletes its sandbox. OpenShell's Python client is the `sandbox` extra, fetched as a component when the sandbox is turned on; tests run it against a fake gRPC gateway. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
The last check asked for 2026-10-17's note after the call without a date had made today's note, so on that day it found the note the deleted root had left behind. It now asks for a day no earlier call makes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
…-r960xc-c7-sandbox Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
# Conflicts: # threat-model.yaml
# Conflicts: # docs/assistant.md # fastapi_backend/app/domain/ai_tools.py # fastapi_backend/app/domain/components.py # fastapi_backend/app/domain/settings.py # fastapi_backend/pyproject.toml # fastapi_backend/uv.lock # threat-model.md # threat-model.yaml
This was referenced Oct 17, 2026
adeelahmad
pushed a commit
that referenced
this pull request
Oct 17, 2026
C1 (#469), web search (#472) and the sandbox (#473) are in main. The routes keep C5's web pages in citations alongside the export, and the export test now checks a cited web page stays through access changes. The OpenAPI schema and client are regenerated with make openapi's two commands, and the threat model's prose_version is recomputed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HXPWXcSCQb9hWPr7xkZu7B
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.
Description
Before: the assistant could only guess at arithmetic, data analysis or file conversion, and had no way to run code for people.
After: an admin turns on Settings → Code sandbox (off by default) and points Lens at an NVIDIA OpenShell gateway. The assistant then gets
run_python,run_bash,sandbox_filesandimport_sandbox_file. Code runs in a sandbox that belongs to one conversation (lens-chat-<id>), keeps its files between runs, and holds none of Lens's data or keys. It has no network unlesssandbox.networkallows the package registries or public addresses. Files attached to the conversation can be copied in. A file the code makes reaches a namespace only through animport_filesapproval.How:
domain/sandbox.pyreaches the gateway through OpenShell's Python client (the newsandboxextra, fetched as a component once the sandbox is on). The sandbox's policy is built from the settings: read-only system folders, a writable workdir and/tmp, and egress that is none, PyPI/npm on 443, or public IP ranges on 80/443. The policy never allows private, loopback or link-local ranges. Each run is an activity-ledger row (sandbox.run). With the network on, a run after the answer read outside text waits for approval (Toolbox.wary). The routines loop stops idle sandboxes and deletes unused ones. Deleting a conversation deletes its sandbox.This is PR 1 of 3 for the code sandbox. PR 2 adds the Compose profile that starts the gateway from Settings, with TLS or a token and a preflight check (Docker 28, Landlock). PR 3 adds the conversation step that shows the code and its output, and a
share_sandbox_filedownload chip.Motivation and Context
Adeel asked for standard Python and bash tools for the chat app on OpenShell (chat gaps, module C7).
Screenshots (if appropriate):
n/a (a Settings section with the existing field types; the conversation step comes in PR 3).
Steps to reproduce (if appropriate):
Types of changes
!in the title)Checklist:
make hookschecks it on commit).docs/accordingly.## UnreleasedinCHANGELOG.md.Done questions (AGENTS.md)
sandbox.*like any other editable section, through the settings API or the assistant'schange_settings. A direct sandbox API for agents is listed as refine later.sandbox.*settings are in Settings → Code sandbox, with defaults. Nothing is in the setup wizard.threat-model.md/.yaml/.jsongain the entry point, the OpenShell dependency and P-SANDBOX.ci/validate_threat_model.pypasses.sandbox.run) and counted for the conversation.code_sandboxand new defaults, with no change to existing stored data.tests/api/test_sandbox.py(8 tests against a gRPC fake gateway driven by OpenShell's own client).docs/assistant.md,docs/configuration.mdanddocs/components.mdare updated.openapi.jsonand the SDK are regenerated withmake openapi.uv.lockcomes fromuv lock.docs/assistant.md#code-sandbox. Automations without a conversation, Python extension tools in the sandbox, microsandbox installs, Podman, GPUs, a direct sandbox API, and a real OpenShell run in CI are all listed there.Local checks:
ruff check,ruff format --checkandmypy(151 files) are clean. The full backendpytestpasses after merging main (1341 passed, 20 skipped).openapi-checkshows no diff. Frontendtsc,eslint,prettierandjest(957 tests) pass.mkdocs build --strictis clean.Generated by Claude Code