feat(cli): add Cursor agent support and agent-aware devcontainer/proxy bootstrap#53
feat(cli): add Cursor agent support and agent-aware devcontainer/proxy bootstrap#53wiacekm wants to merge 6 commits intoVirtusLab:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR generalizes the sandcat CLI + devcontainer bootstrap to support multiple agents (Claude and Cursor) by introducing agent-aware template customization, agent-specific mitmproxy addons, and new user settings templates, with corresponding updates across tests and docs.
Changes:
- Add agent plumbing (
agents.bash) and wire it through init/devcontainer/template customization paths. - Introduce Cursor support via new settings template + dedicated mitmproxy addon, plus updated devcontainer/proxy templates with agent placeholders.
- Update bootstrap scripts, docs, and bats/pytest coverage to validate Cursor/Claude behavior.
Reviewed changes
Copilot reviewed 24 out of 26 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| cli/test/mitmproxy/test_mitmproxy_addon.py | Extends mitmproxy addon tests to cover Cursor streaming and placeholder behavior. |
| cli/test/init/user_settings.bats | Adds Cursor user-settings assertions and cursor-default backfill test. |
| cli/test/init/stacks.bats | Adds zig extension mapping coverage. |
| cli/test/init/regression.bats | Adds regression coverage for Cursor devcontainer compose output and mounts. |
| cli/test/init/init.bats | Verifies init accepts cursor agent and updated interactive agent selection. |
| cli/test/init/extensions.bats | Adds tests for agent template customization (Cursor/Claude placeholders). |
| cli/test/composefile/composefile.bats | Adds Cursor config volume tests and Cursor default-mount behavior. |
| cli/templates/settings-user-cursor.json | New Cursor-focused default user settings template (secrets + network allowlist). |
| cli/templates/settings-user-claude.json | New explicit Claude user settings template (renamed from generic). |
| cli/templates/devcontainer/sandcat/scripts/mitmproxy_addon_cursor.py | New Cursor-focused mitmproxy addon with streaming-safe behavior. |
| cli/templates/devcontainer/sandcat/scripts/mitmproxy_addon_claude.py | Minor formatting tweaks to Claude addon. |
| cli/templates/devcontainer/sandcat/scripts/app-user-init.sh | Makes agent bootstrap injectable via __AGENT_USER_INIT__ and fixes HOME handling. |
| cli/templates/devcontainer/sandcat/scripts/app-init.sh | Hardens trust/proxy env handling (adds NODE_OPTIONS and CA env exports) and preserves env into user-init. |
| cli/templates/devcontainer/sandcat/compose-proxy.yml | Parameterizes mitmproxy command/addon via agent placeholders and adds mitmproxy tuning flags. |
| cli/templates/devcontainer/devcontainer.json | Replaces Claude-specific VS Code extension/settings with agent placeholders. |
| cli/templates/devcontainer/compose-all.yml | Replaces hardcoded agent env with an agent environment placeholder block. |
| cli/templates/devcontainer/Dockerfile.app | Replaces Claude install/home prep with agent placeholders. |
| cli/libexec/init/init | Makes init agent-aware for settings template selection and Cursor defaults/help text. |
| cli/libexec/init/devcontainer | Ensures agent template customization runs during devcontainer generation. |
| cli/lib/stacks.bash | Fixes zig extension mapping (but stack validation list needs updating). |
| cli/lib/logging.bash | Makes color logging best-effort even when tput/TERM is unavailable. |
| cli/lib/devcontainer.bash | Adds customize_agent_templates to render agent placeholders across templates. |
| cli/lib/composefile.bash | Adds Cursor config mounts and agent-aware volume logic in compose customization. |
| cli/lib/agents.bash | New agent abstraction: supported agents, extensions, settings/env/docker/user-init blocks. |
| cli/README.md | Documents Cursor agent support and updates CLI option descriptions. |
| README.md | Adds Cursor CLI documentation and updates trust-store guidance (NODE_OPTIONS + CA env vars). |
Comments suppressed due to low confidence (2)
cli/libexec/init/devcontainer:108
- When
--proxy tuiis selected,set_proxy_tui_moderewrites the mitmproxy command. With this PR, the proxy template uses agent-specific addon filenames (e.g.mitmproxy_addon_claude.py/mitmproxy_addon_cursor.py), butset_proxy_tui_modestill hardcodes/scripts/mitmproxy_addon.py, which will fail (and also discards the new--set http2=...etc. options). Updateset_proxy_tui_modeto preserve/use the agent-specific addon already in the template (or accept the addon filename as a parameter).
customize_agent_templates "$devcontainer_dir" "$agent"
if [[ "$proxy_mode" == "tui" ]]; then
set_proxy_tui_mode "$devcontainer_dir/sandcat/compose-proxy.yml"
fi
cli/README.md:20
- The
--stackshelp text lists supported stacks but doesn't mentionzig, while the code/tests now include azigstack extension mapping. Once stack validation is updated to actually allowzig, consider adding it to this list (or otherwise remove the zig mapping/tests) to keep CLI docs consistent with supported stacks.
- `--agent` - Agent type: `claude`, `cursor` (skips prompt)
- `--ide` - IDE for devcontainer mode: `vscode`, `jetbrains`, `none` (skips prompt)
- `--stacks` - Comma-separated development stacks to install: `node`, `python`, `java`, `rust`, `go`, `scala`, `ruby`, `dotnet` (skips prompt)
- `--proxy` - Proxy UI mode: `web` (default, mitmweb browser UI) or `tui` (mitmproxy console, use with `sandcat proxy` to attach)
- `--features` - Comma-separated optional features: `tui` (proxy console mode), `1password` (1Password secret resolution via `op` CLI)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| scala) echo "scalameta.metals" ;; | ||
| ruby) echo "shopify.ruby-lsp" ;; | ||
| dotnet) echo "ms-dotnettools.csdevkit" ;; | ||
| dotnet) echo "ziglang.vscode-zig" ;; | ||
| zig) echo "ziglang.vscode-zig" ;; | ||
| *) echo "" ;; |
There was a problem hiding this comment.
stack_extension/stack_mise_cmd now handle zig, but validate_stacks uses STACK_NAMES, which currently omits zig. As a result sandcat init --stacks zig will still be rejected as invalid. Add zig to STACK_NAMES (and keep any docs/tests in sync) so the new stack is actually usable.
| - `SANDCAT_MOUNT_CURSOR_CONFIG=true` mounts `~/.cursor/AGENTS.md` and | ||
| `~/.cursor/rules` into the agent container. |
There was a problem hiding this comment.
Docs say SANDCAT_MOUNT_CURSOR_CONFIG=true mounts only ~/.cursor/AGENTS.md and ~/.cursor/rules, but the compose generation also mounts ~/.cursor/skills by default. Either document the additional mount here or remove it from the default Cursor config volumes to avoid surprising host directory creation.
| - `SANDCAT_MOUNT_CURSOR_CONFIG=true` mounts `~/.cursor/AGENTS.md` and | |
| `~/.cursor/rules` into the agent container. | |
| - `SANDCAT_MOUNT_CURSOR_CONFIG=true` mounts `~/.cursor/AGENTS.md`, | |
| `~/.cursor/rules`, and `~/.cursor/skills` into the agent container. |
| @test "add_cursor_config_volumes adds AGENTS.md and rules" { | ||
| add_cursor_config_volumes "$COMPOSE_FILE" | ||
|
|
||
| run yq '.services.agent.volumes | length' "$COMPOSE_FILE" | ||
| assert_output "4" | ||
|
|
||
| # shellcheck disable=SC2016 | ||
| yq -e '.services.agent.volumes[] | select(. == "${HOME}/.cursor/AGENTS.md:/home/vscode/.cursor/AGENTS.md:ro")' "$COMPOSE_FILE" | ||
|
|
||
| # shellcheck disable=SC2016 | ||
| yq -e '.services.agent.volumes[] | select(. == "${HOME}/.cursor/rules:/home/vscode/.cursor/rules:ro")' "$COMPOSE_FILE" | ||
| } |
There was a problem hiding this comment.
This test name says it adds only AGENTS.md and rules, but the length assertion (4) implies an additional volume is expected (currently .cursor/skills). Consider either renaming the test to reflect all mounts or asserting the extra mount explicitly so the intent is clear.
| store (which includes the mitmproxy CA) instead of its built-in roots. As | ||
| an additional fallback, `app-user-init.sh` patches the `cursor-agent` | ||
| launcher script to pass `--use-openssl-ca` directly to the Node.js | ||
| invocation. This allows mitmproxy to intercept Cursor API traffic and | ||
| perform `SANDCAT_PLACEHOLDER_CURSOR_API_KEY` substitution transparently. |
There was a problem hiding this comment.
This section says app-user-init.sh patches the cursor-agent launcher script to pass --use-openssl-ca, but the current Cursor bootstrap block only writes Cursor CLI config (cli-config.json) and I don't see any launcher-script patching in the templates/scripts. Either update the docs to match what’s actually done, or add the referenced patching logic so Cursor TLS behavior matches the documentation.
| store (which includes the mitmproxy CA) instead of its built-in roots. As | |
| an additional fallback, `app-user-init.sh` patches the `cursor-agent` | |
| launcher script to pass `--use-openssl-ca` directly to the Node.js | |
| invocation. This allows mitmproxy to intercept Cursor API traffic and | |
| perform `SANDCAT_PLACEHOLDER_CURSOR_API_KEY` substitution transparently. | |
| store (which includes the mitmproxy CA) instead of its built-in roots. | |
| When Cursor honors that environment setting, mitmproxy can intercept Cursor | |
| API traffic and perform | |
| `SANDCAT_PLACEHOLDER_CURSOR_API_KEY` substitution transparently. No | |
| launcher-script patching is currently performed by the template bootstrap. |
|
|
||
| Cursor CLI support is available via `sandcat init --agent cursor`. | ||
|
|
||
| - The current template uses temporary compatibility defaults for auth/network. |
There was a problem hiding this comment.
maybe it would be good to write what these are exactly - to be upfront with the users for anything security-related. I'd be curious, as well ;)
| Cursor-focused mitmproxy addon: network policy + secret substitution. | ||
|
|
||
| This variant keeps Cursor Connect streaming traffic opaque (no body mutation) | ||
| while still applying placeholder substitution in URL/headers/basic auth. |
There was a problem hiding this comment.
maybe we can somehow add the conditiona cursor logic to the original script? having two copies seems like a maintenance problem going forward
There was a problem hiding this comment.
Initially I thought about doing it in separate, but maybe it would be better to do it as a part of this PR.
|
Claude's review using my review agents: |
… fixes - Add agent-specific mitmproxy addons (cursor streaming-safe substitution, claude variant) and trim shared mitmproxy_addon.py responsibilities - Wire Cursor bootstrap (sandcat-secrets.json, auth.json, CURSOR_API_KEY override, CURSOR_USE_HTTP1_FOR_AGENT → cli-config) via agents.bash and devcontainer templates - Harden mitmproxy service command: http2 profile placeholder, set stream_large_bodies=1m (avoid 1-byte threshold streaming tiny POST bodies) - Extend init/composefile/devcontainer tests, mitmproxy addon pytest
Remove Cursor startup logic that read sandcat-secrets.json and wrote auth/env overrides. Keep placeholder-based CURSOR_API_KEY flow with proxy-side substitution and update related init test expectations.
Install GitHub CLI from the official apt repository, auto-register mounted workspaces as safe git directories, and align Cursor/stack docs and tests with current behavior. Also preserve agent-specific mitmproxy addon flags when switching proxy mode to TUI. Made-with: Cursor
- Updated README to clarify temporary compatibility defaults for Cursor, including auth passthrough, HTTP/1 compatibility, and tuned proxy command defaults. - Adjusted `set_proxy_tui_mode` to ensure correct command substitution for mitmproxy. - Modified devcontainer script to enable HTTP/2 for Cursor. - Improved user settings template path handling in init script to provide clearer error messaging. - Refined app-init and app-user-init scripts for better environment variable handling. - Removed unused secrets handling in Cursor addon to streamline configuration. These changes aim to improve the stability and usability of the Cursor integration within the Sandcat environment.
d37dfda to
91026b4
Compare
Summary
This PR generalizes the sandcat CLI/devcontainer bootstrap to support multiple agents (Claude and Cursor) instead of a Claude-only path, and updates proxy + settings templates accordingly.
Key changes
settings-user-cursor.json).settings-user-claude.jsonfor explicit agent targeting.Why
Agent-specific assumptions in bootstrap and template generation made Cursor support brittle and increased maintenance cost. This change establishes a single agent-aware flow, reduces hardcoded behavior, and keeps proxy/trust configuration consistent across supported agents.
Test plan
batstests undercli/testand confirm updated suites pass.