Repository navigation
Conversation
A test run found three problems with the macOS sandbox. Resolving a path reads the metadata of every parent folder, and the sandbox denied it. So realpath, uv, and git failed with "Operation not permitted", and the agent fell back to pip and edited pyproject.toml by hand. The parents of each open folder now allow metadata reads, but not their contents. uv writes to ~/.local/share/uv when it inspects a managed Python, and the sandbox opened that folder read-only. It is now writable. The agent searched /private/tmp and found another program's files there. The sandbox now closes /private/tmp and gives the run its own temporary folder in it, which OpenCode gets as TMPDIR. The loopback proxy also wrote "http: proxy error" lines into the wizard's screen. It now discards its log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In test runs, the agent spent about 25 tool calls finding the project and environment that setup used, and it printed the environment or asked the user to paste an API key to learn whether one was set. The facts message now also gives the LaunchDarkly project and environment, and the names of the model provider keys that are set in the environment or in the project's .env. It never gives a value. It tells the agent not to look for keys, print the environment, or ask for a key, and to use $TMPDIR instead of /tmp. `ldcli setup agent` takes --project and --environment for the same facts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
atornsii
added this pull request to stack #902
October 20, 2026 15:48
… into atorns/agent-6-run-fixes
… into atorns/agent-6-run-fixes
…env keys BuildPrompt now gives the project, the environment, the provider key names, and the same rules as BuildFacts. The agent gets these facts when the AI Config cannot load. ProviderKeys now trims the value after it removes the quotes, so a quoted blank value does not count as a set key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into atorns/agent-6-run-fixes
If the sandbox gives no run folder and TMPDIR is not set, ldcli now sets TMPDIR to the system temporary folder. The prompt tells the agent to use $TMPDIR on every platform. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into atorns/agent-6-run-fixes # Conflicts: # cmd/setup/agent_test.go
… into atorns/agent-6-run-fixes # Conflicts: # internal/setup/agent/sandbox.go
… into atorns/agent-6-run-fixes # Conflicts: # internal/setup/agent/sandbox.go
…y folder parentFolders now also walks the folders between an open folder and /private/tmp. A project in a nested folder under /tmp can then use realpath, uv, and git in the sandbox. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into atorns/agent-6-run-fixes # Conflicts: # internal/setup/agent/sandbox_test.go
The agent read .env in a test run, so the values of the user's keys went to the model. The sandbox now denies reading and writing .env and .env.* in the project, in any subfolder, and keeps .env.example, .env.sample, and .env.template open. OpenCode's read and edit tools refuse the same files, so the agent gets a clear refusal. The facts tell the agent that the files are closed and that it must write variable names in .env.example. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The .env rule wrote the project path into a raw Seatbelt string, so a double quote in the path ended the string and the profile was invalid. The rule now uses an escaped profile string. The sandbox test now uses a project path with a double quote. The comment now uses active voice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 21, 2026
This was referenced Oct 21, 2026
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.
This fixes problems that the test runs found.
Sandbox (run 8)
realpath,uv, andgitfailed with "Operation not permitted", and the agent fell back topip. The parents of each open folder now allow metadata reads, but not their contents. This also covers folders under/private/tmp, for a project in a nested folder there.~/.local/share/uvis now writable, becauseuvwrites there when it inspects a managed Python./private/tmp, where the agent found another program's files. Each run gets its own temporary folder there, which OpenCode gets asTMPDIR. Without the sandbox, OpenCode gets the system temporary folder asTMPDIRif the variable is not set.Facts (runs 5, 7, and 8)
.env. ldcli reads those names itself, and it skips a key whose value is blank, also inside quotes.$TMPDIR. Before, the agent spent about 25 tool calls finding the project, and it printed the environment or asked the user to paste a key.ldcli setup agentcontroltakes--projectand--environmentfor the same facts.The project's .env files (runs 10 and 11)
In run 10, the agent read
.envwith OpenCode's read tool, so the values of the user's keys went to the model. The sandbox now denies reading and writing.envand.env.*in the project, in any subfolder..env.example,.env.sample, and.env.templatestay open. OpenCode'sreadandedittools refuse the same files, and the facts tell the agent that they are closed. The profile escapes the project path in the rule, so a path with a double quote still gives a valid profile.The agent therefore cannot run the app with the real keys, so the setup prompt must not ask it to. In run 11, the agent wrote the variable names only to
.env.example, and it did not try to read.env.Testing
realpathin the project and in a nested folder under/private/tmp, a closed file in/private/tmp, and a writable run folder..env,.env.local, and a nestedservices/api/.envare closed, and that.env.exampleand other files stay open.uv python find,realpath,git status, and OpenCode work in the sandbox in the test app..envfiles.Diagram
flowchart TD subgraph facts [Facts for the agent] cmds["commands.go<br/>startAgent: project, environment"]:::chg cmdag["cmd/setup/agent.go<br/>agentTask with project, environment<br/>--project, --environment"]:::chg keys["provider_keys.go<br/>ProviderKeys, dotEnvNames"]:::new task["agent.go<br/>Task.ProjectKey, EnvironmentKey<br/>Task.ProviderKeys"]:::chg prompt["prompt.go<br/>BuildFacts: project, environment<br/>key names, TMPDIR note"]:::chg cmds -->|agentTask| cmdag cmdag -->|ProviderKeys| keys cmdag -->|fills Task| task prompt -->|reads Task| task end subgraph box [Sandbox and screen] srv["server.go<br/>TMPDIR = box.TempDir"]:::chg sb["sandbox.go<br/>parentFolders<br/>RunTemp, sharedTemp<br/>.local/share/uv writable"]:::chg proc[["opencode serve<br/>own TMPDIR"]]:::ext tmp[["/private/tmp<br/>closed, except the run folder"]]:::ext proxy["relay_proxy.go<br/>ErrorLog: discard"]:::chg srv -->|sandboxCommand| sb srv -->|sets TMPDIR| proc sb -.->|profile rules| tmp end classDef new fill:#e6f0fa,stroke:#1d6fb8,stroke-width:2px,color:#19202b classDef chg fill:#fbf1e1,stroke:#a86a12,stroke-width:2px,color:#19202b classDef earlier fill:#ffffff,stroke:#7a8494,stroke-dasharray:5 4,color:#19202b classDef ext fill:#eceefa,stroke:#4e5a9c,stroke-width:2px,color:#19202bBlue boxes are new files, orange boxes are changed files, dashed boxes are files from an earlier PR, and purple boxes are outside ldcli. A solid arrow goes from the caller to the code that it calls. A dashed arrow shows data that moves without a direct call.
The facts group starts in the wizard.
commands.gopasses the selected project and environment toagentTask, which also callsProviderKeysto get the names of the provider keys that are set.agentTaskputs these values in theTask, andBuildFactswrites them into the first message. In the sandbox group,sandboxCommandnow creates a run folder in/private/tmpand closes the rest of that folder. It returns the run folder asTempDir, andserver.gogives it to OpenCode asTMPDIR. The profile also allows metadata reads on parent folders, sorealpath,uv, andgitwork.relay_proxy.gostops writing proxy errors on the wizard screen.The two groups do not depend on each other. The facts group changes the wizard from #895 and the prompt from #897. The sandbox group changes files from #896 and #897.
Stack
This is one of seven PRs for the
ldcli setupagent. Review and merge them in order, after #877 (Go 1.26):The gonfalon side is launchdarkly/gonfalon#75196 to #75199 (the SDK relay) and launchdarkly/gonfalon#75426 (the model relay). This stack replaces #876 and #878, which are closed.
🤖 Generated with Claude Code
Note
Overview
Hardens the setup agent after test-run failures by tightening macOS sandboxing, blocking secret leakage from
.env, and feeding the model safer context.Sandbox: Parent directories of allowed paths now permit metadata-only reads so
realpath,uv, andgitwork;~/.local/share/uvis writable; shared/private/tmpis denied except a per-run folder passed asTMPDIRto OpenCode. Seatbelt regex rules deny read/write on project.env/.env.*while keeping.env.example(and similar) open. The relay proxy discards HTTP error logs so failures do not clutter the wizard UI.Secrets & prompts: OpenCode
read/editpermissions use ordered rules to deny.envfiles (same exceptions as the sandbox). NewProviderKeysreports only names of set model-provider env vars (from the process env and.envparsing, never values).Taskand prompts/facts now include LaunchDarkly project/environment, provider key names, and sharedsetupRules(no key hunting, no running with real.env, use$TMPDIR). The wizard andsetup agentCLI gain--project/--environmentflags.Tests: Coverage for env-file permissions, sandbox temp isolation,
.envblocking, provider keys, and prompt/fact parity.Reviewed by Cursor Bugbot for commit 42f2421. Bugbot is set up for automated code reviews on this repo. Configure here.