Repository navigation
feat: local npx deployment for Scope (server + standalone CLI) - #1470
Draft
Cedric Vidal (cedricvidal) wants to merge 36 commits into
Draft
Cedric Vidal (cedricvidal) wants to merge 36 commits into
Cedric Vidal (cedricvidal) wants to merge 36 commits into
Conversation
Expose local runtime setup through the API and Portal, and extend Secrets/Token Manager with saved Portal provider selection and compatible text transports. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Pin each command's API/auth/project context, retain explicit-URL legacy behavior, and expose agent setup and secret/provider management. Exercise the real private package outside the checkout. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Start the existing services through Dockerode with bundled sources and Dockerfiles, persistent storage, and selected host or Docker agent setup. Reuse installed Copilot and Claude CLIs through thin worker wrappers, and include the Portal shared dependency in clean container builds. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The existing worker proxy switch treats every nonempty environment value as enabled. Emit an empty value for disabled local capture instead of the truthy string false. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Handle ky NetworkError without replaying setup or credential mutations, and clarify that run submission accepts host worker types. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Bound stop requests and force-remove only containers with verified ownership after graceful failure. Preserve both errors if removal also fails. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Keep management-request timeouts without aborting active image streams during long compression or extraction. Reproduce the failure with the real Dockerode transport. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Document the successful private-package retry and final owned-resource cleanup while retaining the native Copilot blocker and failed Copilot Docker Judge verdict. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Default unset proxy backend to gateway, pin the remaining Compose Claude DevProxy path explicitly, and enable gateway capture for local Docker and host workers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Host targets run as the user and their HTTPS traffic is decrypted by the local capture gateway's own CA. State both, plus the personal-config isolation, before asking for consent rather than mentioning file access alone. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Restore the portal LLM chain to Foundry env, Foundry via Token Manager, then GitHub Models. Remove the provider selector, OpenAI/OpenRouter/compatible credential types, Portal AI settings endpoints, and provider transports while preserving the Foundry reasoning-model parameter normalization. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Keep the secret CRUD/preview/validate commands, remove the Portal AI subcommand group and provider presets, warn on argv secret input, and add output-format coverage proving secret values are not printed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Update resume tests to seed the pre-update request lookup introduced by host-worker availability checks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Feeds a value field the API should never return and asserts it reaches no output format. Verified meaningful by mutation: adding value to the metadata allowlist fails this test. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Both packages stay private, so registry installs do not work; document the tarball path instead. Recommend --omit=optional for the server: it drops a 225 MB bundled Claude binary of the 618 MB install that host runs never execute, because the ACP adapter prefers CLAUDE_CODE_EXECUTABLE. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Routing a host worker through the gateway relies on Node-only proxy and TLS env vars, but the worker ultimately spawns the user's installed CLI, which is a native binary that ignores them and does not trust the interception CA. A real Claude Code host run with capture on fails with FailedToOpenSocket and records an empty HAR, so capture now requires SCOPE_HOST_CAPTURE=1. Docker capture, which is where the missing-execution-history verdict came from, stays on. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Routing ACP Claude Code through the gateway makes its native CLI fail with ConnectionRefused and record an empty HAR, which is why docker-compose still pins that worker to DevProxy. Enable capture for the Copilot Docker worker only, matching the migration's actual state, instead of breaking Claude benchmarks to collect evidence the gateway cannot produce for it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Request 0735ba0e extracted 4 tool calls from the HAR, generated ATIF 1/1 and passed the criterion that requires captured tool-call evidence, closing the missing-execution-history gap. Also note that Claude Docker's earlier pass ran uncaptured and fails when routed through the gateway. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Typing 'start' printed a wall of '[service] stopping' lines, because startup ran the full stop() path to clear a previous launcher's leftovers. That also removed the network connect() had just created, forcing a second connect, and duplicated work startService already does via removeOwned. Replace it with reclaim(): it drops only stale owned containers, keeps the network, reports them as 'reclaimed', and stays silent when there is nothing to reclaim. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Re-adding a name failed with no way to proceed except editing fields one by one. --force replaces the whole entry; without it the command still refuses, so a saved token or project is never silently discarded. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0dbdb5f0-a52e-4f98-9922-b531502619b9
Resolve conflicts with main (#1379, #1373/#1374, #1381, #1385): - Port main's ACP worker logic into the reusable worker.ts; keep index.ts thin - Use main's agent-registry admission; keep host checks for resume/bulk-resume - Pin SCOPE_AGENT_VERSION for host and Docker workers to the registered version - CLI api-client: main's auth + environment-aware client; SSE sends auth - Drop Foundry proxy (superseded by #1379) and .scope Dockerfile rewrite - Regenerate pnpm-lock.yaml and OpenAPI snapshot Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Test Results (Node.js 22)test: Run #210
🎉 All tests passed! |
This was referenced Oct 8, 2026
This branch has not been deployed
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.
Lets someone try Scope on their laptop with two commands and no checkout:
That brings up the full platform — MongoDB, Redis, Azurite, Lowkey Vault, the API, Portal, Judge, scheduler, post-processor, report generator and the capture gateway — prints a Portal and API URL, and runs real benchmarks against real coding agents.
This is a third deployment option alongside the existing Compose development setup and the Kubernetes deployment. Neither of those changes.
How it works
apps/server/— the launcher. A Commander CLI (start,stop,restart,status) that owns the local stack. It declares the services as a small typed manifest and drives Docker throughpackages/docker-orchestrator/(Dockerode) rather than shelling out todocker compose. Every container and network it creates carries adev.scope.server.ownerlabel, so shutdown removes exactly what it created and never the persistent bind-mounted data. Ports are allocated once and reused on later starts, so saved CLI environments and bookmarks keep working.Packaging.
pnpm pack:serverbundles version-matched Scope sources, Dockerfiles, the lockfile and config assets into a private tarball. Images are built locally on first run from those bundled sources — the package never checks out Scope or pulls a prebuilt Scope image. Only public dependencies and base images are fetched. Image cache keys include the sources, package version, build timestamp and component versions.Host coding agents. Alongside the Docker workers, two new packages (
coder-acp-copilot-host,coder-acp-claude-code-host) run the user's already installed Copilot or Claude Code CLI as a benchmark worker, reusing its existing login. Scope never installs, upgrades or logs into those CLIs. Host targets require explicit per-target consent that states what it means: the agent runs as you, with your files and login. To keep results reproducible, host runs disable personal MCP servers and settings (settingSources: []+--strict-mcp-configfor Claude;--disable-builtin-mcpsplus per-server disables for Copilot) while deliberately not relocatingHOMEorCLAUDE_CONFIG_DIR, which would break login reuse.To make this possible, each worker's queue-processing logic moved out of its
index.tsentrypoint into a reusableworker.ts, so the Docker and host entrypoints share one implementation.apps/cli/— a standalone client. Packaged separately so it can be installed on its own. Adds named environments (scope env add/use/set), so one CLI can target the local instance and a shared deployment without re-typing URLs, with explicit precedence between flags, the named environment and process env. Also addsscope agent setupfor enabling agents from the terminal, andscope secretfor credential management — which the CLI previously lacked entirely, a CLI↔Portal parity gap. A regression test pins that nosecretsubcommand can print a credential value in any output format.Portal. A Set up local agents dialog (
ServerAgentSetup) appears only when the launcher is driving the API, offering the same host/Docker agent setup, executable selection and consent as the CLI.Try it
Logs stream live; results, artifacts and reports are available from both the CLI and the Portal. Stopping leaves the data directory intact, so a later
scope-server startresumes with the same projects, runs and verdicts.Also in here
createProxyClient()defaulted to the legacydevproxywhenPROXY_BACKENDwas unset, so any caller that forgot to set it silently got the legacy path. The default is nowgateway, paired in the same commit with an explicitPROXY_BACKEND: devproxypin for the ACP Claude Code worker indocker-compose.yml, which was relying on that implicit default. Behaviour-preserving for existing workers.Validation
Exercised outside the checkout with the packed artifacts, on macOS arm64 with a Podman Docker-compatible socket:
Hello Scope!, exit 0, and its report completed.pnpm exec vitest run— 231 files / 2,859 tests passing.docs/architecture/scope-server.mddocuments packaging, storage layout, agent setup and consent, capture semantics and the observed coverage.Before review
main. Developed againstb494da81, last validated 2026-09-12.docker-compose.ymlstill pins that worker to DevProxy; finishing that migration is out of scope here. Host capture is therefore opt-in viaSCOPE_HOST_CAPTURE=1.session/newtimes out against a personal MCP server returning HTTP 403 with a malformed initialize response. Environmental, but no corrected host benchmark completed.