Thanks for your interest in contributing! This guide covers the legal requirements, how to set up a local environment, the conventions we follow, and how to get a change reviewed and merged.
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the Microsoft Open Source Code of Conduct.
For more information see the Code of Conduct FAQ or
contact opencode@microsoft.com with any additional questions or comments.
See CODE_OF_CONDUCT.md for the full statement.
Please do not report security vulnerabilities through public GitHub issues. Follow the process in
SECURITY.md to report them to the Microsoft Security Response Center (MSRC).
Scope is a pnpm workspaces monorepo (TypeScript, with a Rust component for the AI gateway).
-
Node.js 22 — the version CI builds and tests against.
-
pnpm 10.29.1 — pinned via the
packageManagerfield inpackage.json. The easiest way to get the right version is Corepack:corepack enable -
Docker — required to run the backing services (MongoDB, Redis, Azurite, Lowkey Vault) and to run integration tests.
-
mkcert: required for trusted HTTPS certificates when running the local authentication emulator.
-
GitHub CLI: used to obtain a token for local Copilot runs. The account supplying the token must have an active GitHub Copilot entitlement;
gh auth loginalone does not grant Copilot access. -
Rust / Cargo — only needed if you work on the AI gateway (
apps/gateway/).
pnpm install # Install all workspace dependenciesCI installs with pnpm install --frozen-lockfile; commit an updated pnpm-lock.yaml when you change
dependencies.
Local authentication requires your browser to trust a development certificate.
The Portal development scripts run mkcert -install to add a local certificate
authority to the OS/browser trust store and generate the emulator's localhost
certificate. On first use, you may be prompted to approve this trust-store
change. Follow the
local authentication instructions
for details.
For the Copilot worker, authenticate with an account that has an active Copilot entitlement and make its token available to the development stack:
gh auth login
export GITHUB_TOKEN="$(gh auth token)"Start the backing services first, then run the stack or an individual service:
pnpm docker:up:infra # Start backing services (MongoDB, Redis, Azurite)
pnpm docker:dev:copilot # Full stack with the Copilot worker + portal (hot reload)
pnpm docker:dev:all # All workers + portal + report generator (hot reload)
pnpm dev:api # API only (native)
pnpm dev:portal # Portal only (native)
pnpm dev:coder-acp-copilot # A single worker natively (pnpm dev:<service-name>)
pnpm open:portal # Open the portal in your browserpnpm docker:dev:portal starts the API with the Node inspector enabled. To
debug API TypeScript while retaining the Docker stack and hot reload:
- Run
pnpm docker:dev:portaland wait for the API to start. - Read
API_DEBUG_PORTfrom the generated.envfile (it is worktree-specific). - In VS Code, select Attach API (Docker) from Run and Debug, enter that port, and start debugging.
- Set breakpoints in the workspace source under
apps/api/src, not in a copied or attached snapshot of the file.
The debugger maps the container's /app tree to the workspace and reconnects
when tsx watch restarts the API after a source change. The inspector is
published on 127.0.0.1 only.
The CLI is the primary interface for CI/CD and power users:
pnpm cli --help # Discover CLI subcommandsTests are co-located next to source as <filename>.test.ts and run with Vitest.
pnpm test # Unit tests
pnpm test:coverage # Unit tests with a coverage report
pnpm test:integration # Integration tests (requires a .env file + Docker)CI's worker integration, queue recovery and Windows build jobs
require github.repository == 'microsoft/scope': they do not execute in fork
repositories. A fork PR into upstream still runs the ACP workers' tool checks and
the disposable MongoDB/Redis/Azurite queue tests. Worker credentials are withheld
from fork-head code, so the existing live-auth tests skip when credentials are
absent. Docker Hub login is optional and restricted to trusted code; public images
can be pulled anonymously. LLM evals require trusted PR heads.
The OSS CI workflow does not publish container images or request OIDC;
its ACP test images are built and loaded locally. Public CI requires no Azure/ACR
setup. PR test reporting and video
uploads remain enabled, with missing video directories treated as no recordings.
Changes to the CI workflow select the integration checks through a dedicated
path filter. Run the focused workflow
regressions with pnpm exec vitest run scripts/ci-workflow.test.ts and the real
queue tests with pnpm test:integration:queue (Docker required).
The ACP matrix covers the existing Copilot and Claude workers; the removed VS Code
workers have no Dockerfiles or integration suites in this repository.
Live-model credentials remain necessary for live-auth tests; passing public
tool checks does not validate live-model access.
Windows validation uses GitHub's windows-2022 runner and its Windows Docker
engine. scripts/build-windows-worker.ps1 builds Dockerfile.base from public
servercore:ltsc2022, builds pinned Copilot dependencies against that local image,
then builds and smoke-tests the worker against the local dependencies image.
No internal registry, prebuilt private image, secrets or image publication is
required. Changes to the Windows worker, Linux Copilot dependency, shared packages,
telemetry, workspace/build context, or CI select this check; failures block
CI Summary. Run the same script locally on Windows Server 2022 with Docker.
The PowerShell orchestration tests require pwsh (included on GitHub's Ubuntu
runners); they mock Docker and do not replace the hosted Windows image build.
The OSS repository does not depend on internal scope-core automation. The
internal infrastructure status report and cloud image publishers are removed;
Windows build validation is local, while CLI release publication is retained in
this repository using its own GITHUB_TOKEN. Public Pages is unchanged. The
manual CLI release workflow runs only on upstream main, builds and tests the
exact bundle before publishing it to microsoft/scope, and needs no FLUX token.
See CLI distribution for versioning,
installation and update behavior.
pnpm build # Build every workspace package (pnpm -r build)
pnpm lint # Lint/typecheck every package (pnpm -r lint)For the Rust gateway (apps/gateway/):
pnpm build:gateway # cargo build --release
pnpm test:gateway # cargo test
pnpm lint:gateway # cargo clippy -- -D warnings
pnpm fmt:gateway # cargo fmt --checkSchema changes live in packages/db-migrations/ and use
mongo-migrate-ts (TypeScript files with up() / down()):
pnpm migrate:up # Apply pending migrations
pnpm migrate:down # Roll back the last migration
pnpm migrate:status # Show migration statusMongoDB is CosmosDB-compatible — avoid MongoDB features that CosmosDB's MongoDB API does not support.
- TypeScript: strict mode, ES2022, NodeNext modules.
- License headers: every first-party source file must start with the Microsoft MIT header. Run
pnpm headersto add it; CI enforces it viapnpm headers:check. - Tests: co-locate them next to the source as
<filename>.test.ts(Vitest). - CLI ↔ Portal parity: every feature available in the Portal must also be available in the CLI — the CLI must never lag behind the Portal.
- Portal + Storybook: when you add or change a portal component, update its Storybook stories.
- Rust: for any change under
apps/gateway/, follow therust-best-practicesskill (.agents/skills/rust-best-practices/SKILL.md). - Databases: keep MongoDB usage CosmosDB-compatible (see migrations above).
- Documentation is not optional: if you add or change a component, API, data model, pattern, or
deployment behavior, update the relevant doc in
docs/(or add one and link it from the README) as the last step before opening your PR.
- Fork the repository and create a topic branch from
main. - Make your change, keeping it focused and adding/adjusting co-located tests.
- Run
pnpm lintandpnpm testlocally (pluspnpm test:integrationwhen your change touches a worker or backing service) and make sure they pass. - Update any documentation affected by your change.
- Write clear, descriptive commit messages and PR descriptions; link the issue(s) your PR addresses.
- Open the PR and complete the CLA check if the bot asks you to. Address review feedback and keep the
branch up to date with
main.
See Reviewing and merging community contributions for what to expect, including our acknowledgement target and follow-up on PRs waiting for a response.
For user-visible changes (Portal/CLI features or UX changes), attach a short recording in the PR's Demo section. For user-visible bug fixes, show the same steps before and after the fix. Aim for 20-30 seconds focused on the changed interaction and its result. Write "N/A" for changes that aren't user-visible, such as documentation, internal refactors, or infrastructure-only changes.
Use a screen recorder such as macOS Screenshot (Shift+Command+5), Windows Snipping Tool's video
capture, or OBS Studio to capture the relevant browser or terminal area. An agent with browser or
terminal automation and recording tools can run the steps and produce an annotated recording for
you; review its output before uploading.
Use synthetic data and scrub tokens, cookies, credentials, and real run/customer data from the
recording, including terminal output and browser UI. Check the entire clip before sharing it.
Drag and drop an .mp4, .mov, or .gif into the PR description to upload it to GitHub, and add a
one-line caption describing what it shows so reviewers can search for the behavior.
Recordings complement, not replace, the Testing section: keep test commands, results, and any manual checks in text. Screenshots can add context but do not show interaction or timing.
This process guides how the Scope team reviews and merges external contributions.
Aim to acknowledge each external PR within three business days. Assign a team member to coordinate the review and follow it through to merge or closure. Confirm that the change fits Scope's direction before asking the contributor for substantial revisions. Discuss larger features or architectural changes in an issue first.
Reviewer routing is the team's responsibility, not the contributor's. The repository's
CODEOWNERS file now routes review requests by area. The team should still
designate a triage maintainer to check incoming PRs each business day, assign a maintainer as the PR
owner, and request additional reviewers familiar with the affected area when needed.
Keep the CODEOWNERS file current as maintainers and area ownership evolve.
Team review assignment and branch protection still need to be configured to distribute requests,
require code-owner review, and dismiss stale approvals. Until those settings are enabled, the PR
owner coordinates reviews and the merging maintainer checks the approval requirements.
Before a detailed review, confirm that the PR explains what changed and why, satisfies the CLA requirement, and includes relevant tests and documentation. Portal/CLI user-visible changes should include the demo requested by the PR template. If anything is missing, give the contributor a clear next step.
Require one team maintainer's approval for routine changes. Require two team maintainers'
approvals, including someone familiar with the affected area, for changes involving
authentication, permissions, project scoping or data isolation, data migrations, CI/deployment,
new or upgraded dependencies, breaking APIs, or breaking changes to packages/shared/.
Review correctness, maintainability, security, and compatibility. Apply Scope's existing requirements, including CLI/Portal parity, Storybook updates, and CosmosDB-compatible migrations where relevant. AI review can help, but does not replace human approval.
Keep decisions in the PR so contributors can follow them. Distinguish required changes from optional suggestions, explain the reason for blockers, and avoid expanding the PR into unrelated work. If reviewers disagree, the PR owner brings in the relevant maintainer to resolve it.
Treat external code as untrusted when running it. Do not expose credentials, production data, or
privileged runners to unreviewed code. Before clicking Approve and run workflows for a fork
PR, read the diff. Give extra scrutiny to .github/workflows/, including gh-aw .md and
.lock.yml agentic workflows, and to package.json scripts and lifecycle hooks. Never add
pull_request_target or secrets-bearing triggers to handle fork PRs. Route vulnerability reports
through SECURITY.md.
A team maintainer merges once:
- The required approvals cover the latest substantive changes.
- Required checks pass and blocking feedback is resolved.
- Relevant testing is complete. A check skipped on a fork is not evidence that it passed.
- The CLA requirement is satisfied and any compatibility or rollout implications are documented.
Use squash merge for a focused history. Keep the contributor as the commit author and preserve
Co-authored-by: trailers for other contributors who authored commits in the PR. Use a
Conventional Commit title with the PR number, for example
docs: clarify contribution review policy (#1413). Do not bypass checks or approvals just to
unblock a PR.
Thank the contributor and link any follow-up work. The PR owner checks the post-merge result and coordinates a fix or revert if needed.
If a contribution is not a fit, explain why and close it promptly. When a PR is waiting on the contributor after a clear request for information or changes, send a reminder after two weeks without a response. Close it two weeks after the reminder (four weeks total) if there is still no response, making clear that the contributor can resume later. Do not close PRs under this rule when they are waiting on the team.
The PR owner applies status: waiting when requesting a contributor response and removes it when
the contributor responds. State who owes the next action in a comment; the label alone must not
trigger the closure policy, particularly when a PR is waiting on the team.
Use the existing category: value labels for issue and PR triage. Check the
live label list before applying labels;
do not recreate retired names or the migration-only author: labels.
Keep good first issue and help wanted unprefixed for contribution discovery.
Automations depend on these exact names:
| Consumer | Labels |
|---|---|
| Worker version checker and upgrade workflow | type: worker-update |
| Test Improver issues, PRs, and monthly-summary searches | type: automation, topic: testing |
| Dependabot | type: dependencies, plus language: javascript or language: rust |
| Pull Request Labeler | Area, topic, language, and type labels from .github/labeler.yml |
Use area: reporting for Scope's benchmark reporting component, not daily repository activity.
Worker upgrade routing uses type: worker-update, not the broader area: worker.
The pinned GitHub Agentic Workflows runtimes hard-code the unprefixed agentic-workflows
label when searching for and creating failure reports, no-op tracking issues, and PR fallback
issues. This is a machine-managed compatibility exception to the namespaced label convention.
Before relying on these workflows after a label migration, a maintainer must ensure
agentic-workflows exists and is applied to existing workflow tracking issues that were renamed,
especially [aw] No-Op Runs and [aw] ... failed issues. Otherwise the runtime can miss existing
trackers and attempt duplicate reports. Keep this exact name until every active runtime supports
a replacement for both lookups and writes.
Changing safe-outputs label lists alone does not change these built-in handlers.
Repository configuration does not create or backfill this label automatically.
Update both the label filters and label writes in .github/workflows/check-worker-versions.yml,
.github/labeler.yml, the agentic workflow .md frontmatter, and any label searches in their prompts.
Regenerate the corresponding .lock.yml files with gh aw compile; do not edit generated YAML
by hand. Use each file's recorded compiler version to avoid unrelated runtime upgrades:
| Workflow | Compiler |
|---|---|
daily-test-improver |
v0.57.1 |
worker-version-upgrade |
v0.63.0 |
The daily schedules are explicit cron expressions preserving their existing UTC execution times.
Review changes to .github/aw/actions-lock.json and generated workflow permissions, triggers,
action pins, and handler configuration before merging.
.github/dependabot.yml specifies namespaced labels for the root pnpm workspace, the separate
website package, and the Rust gateway. Each entry has open-pull-requests-limit: 0 to keep
version-update PRs disabled; the required schedule does not enable those PRs. These labels also
apply to security-update PRs when security updates are enabled in repository settings. This file
does not enable security updates or change live labels.
.github/workflows/labeler.yml runs on the unprivileged pull_request event and skips fork PRs.
Do not switch it to pull_request_target just to label fork PRs; that would violate the fork-PR
security boundary above.
Scope redistributes npm production dependencies in its service images and Rust
crates in the gateway binary. Their attributions and license texts are collected
in the root NOTICE file.
NOTICE is generated; don't edit it by hand. Regenerate it after changing
dependencies:
pnpm notice # Regenerate NOTICE and NOTICE-REVIEW.txt
pnpm notice:check # Check whether the committed notices are currentThe generator (scripts/generate-notice.ts)
orchestrates license tooling and concatenates its verbatim output. It doesn't
author or edit license text. It uses
generate-license-file for npm production
dependencies and cargo-about for
crates compiled into the gateway. npm exclusions and multi-license disambiguation
live in the generator; Rust configuration and templates live in
apps/gateway/about.toml and
apps/gateway/about.hbs.
Only scripts/notice-header.txt is written by hand.
Production packages whose licenses can't be resolved as standard open source
are excluded from NOTICE and listed in NOTICE-REVIEW.txt for manual legal
review.
generate-license-file runs through npx. To regenerate the Rust portion,
install its tool with cargo install cargo-about --features cli. Set
SKIP_CARGO=1 to reuse the cached Rust section when it hasn't changed.
Both notice files are platform-independent. Per-platform native binaries
(@os-theme/* and @github/copilot-<os>-<arch>) and macOS-only fsevents are
excluded so macOS and Linux produce the same output. Attributions for excluded
native binaries are carried by their platform-independent parent packages.
The notice-check job in CI checks for drift from
installed dependencies.
- Start with the system architecture and the app design docs for the big picture.
- The README introduces the platform, provides a local quick start, and links the full documentation index.
- Browse open issues for bugs and proposed improvements. Discuss larger changes in an issue before starting work.