In March 2026, someone filed a feature request on GitHub Community that I have thought about more than any product announcement from that month. The setup is two repositories. A web app and an orders-service it consumes. The web app calls the service’s endpoints, depends on its DTOs, and has to stay aligned with every route rename, payload change, and validation rule. The request walks through what Copilot cannot do across that boundary: it cannot reason about contracts defined in the other repo, cannot detect when the frontend calls an endpoint that no longer exists, cannot coordinate one change across both sides. It ends with two questions. Is this on the roadmap, and are there recommended best practices to approximate this behaviour today?

GitHub has not answered. I eventually left a reply in the thread myself, because the second question deserved one, and this post is the long version of that reply.

The honest answer is more useful than “wait for the roadmap”. As of June 2026 there are three working ways to give GitHub Copilot context across repositories. All three are real, all three ship today, and all three have a ceiling that is worth knowing about before you invest in one. Underneath all three sits the same unanswered question, and that question is the part I actually want to get to.

What Copilot can see today, precisely

It is worth being precise here, because the answer is different for each Copilot surface, and it changes fast enough that this paragraph carries a date.

Copilot Chat in VS Code sees the workspace you have open. One folder open means one repo’s worth of context. Copilot Chat on github.com is scoped to a single repository, or to a Space, which we will get to. And the Copilot cloud agent, the one you hand an issue and get a pull request back from, runs in its own environment scoped to the single repository where the task was opened, holding a repository-scoped GITHUB_TOKEN that cannot read its siblings.

None of this is an oversight. It is a permissions model doing its job. Which is why every working approach to cross-repo context is a way of routing around that model deliberately: widen the workspace, curate a context set, or hand the agent extra credentials. Those are the three approaches, in that order.

Approach 1: a multi-root workspace in VS Code

The cheapest path, and the one most teams should try first. VS Code supports multi-root workspaces: a .code-workspace file listing several repository folders that open together in one window.

{
  "folders": [
    { "path": "web-app" },
    { "path": "orders-service" },
    { "path": "platform-context" }
  ]
}

Copilot Chat indexes across every folder in the workspace, and #codebase searches all of them. For the web-app and orders-service case this is genuinely transformative: both sides of the contract are in the window, so “does the frontend call anything I just renamed” becomes an answerable question.

The pattern has grown a refinement that is worth copying. Several teams now pair the workspace with repository custom instructions, a .github/copilot-instructions.md per repo, and the more advanced version adds a dedicated context-only repository to the workspace. Arinco published a detailed writeup of running this across a 15-plus-repo platform this week: a repo containing nothing but Copilot customisation files, added as a workspace folder, whose shared instructions file acts as a routing table describing the architecture and pointing at each repo’s own conventions.

That is the strongest version of the approach, so let me be fair to it before drawing the line. At two to five tightly coupled repos, with someone who cares keeping the instructions current, this works, and it costs an afternoon.

It stops in three ways, and they compound.

First, the workspace does not load itself into the model’s context. The agent searches and greps it, every session, and that cost is paid again every session. Meta’s published numbers put a graph lookup for “what depends on X” at roughly 200 tokens against roughly 6,000 for answering the same question by exploration, a 30x difference I went through in detail in the virtual monorepo post. Grep over a workspace is O(N) in workspace size, and the workspace only ever grows.

Second, the instructions file decays. It is a hand-written map of how the system fits together, and the system keeps moving after the map is written. The research on hand-written context files is sobering, marginal gains at meaningfully higher inference cost, and Meta’s engineering team named the underlying problem in one line: “context that decays is worse than no context”. A confident agent navigating by a stale map does not feel stale. It feels fast, right up until the change lands.

Third, somebody chose which folders go in that .code-workspace file, and they chose from memory. Hold that thought.

Approach 2: Copilot Spaces

The native option, and the one I see teams miss because it lives on github.com rather than in the editor. Copilot Spaces let you assemble a curated context set, including entire repositories, plural, alongside specific files and folders, pull requests, issues, uploaded documents, and free-text notes, then chat with Copilot grounded in exactly that set. You can attach custom instructions, share the space with your organisation, and the GitHub-based sources stay synced as the code changes. Any Copilot licence can use it.

Credit where due: this is zero infrastructure, it is the only genuinely multi-repo Copilot surface GitHub ships today, and for a team that lives on github.com it is the lowest-friction answer on this list. A space holding web-app, orders-service, and the API contract files is a real improvement for onboarding questions, contract questions, and “explain how these fit together” questions.

The ceiling is in how it retrieves. When you attach a whole repository, Copilot searches within it for relevant content rather than loading it, and GitHub’s own guidance is to curate the specific files that matter because that is what produces the best answers. So the quality of a space is the quality of its curation. Sources are grounded in the latest state of the main branch, which means in-flight work on branches is invisible to it. And a space is a chat surface: it informs the human asking, it does not gate a deploy or coordinate a change. It answers questions about the repos somebody remembered to add.

That phrase again. Somebody curated the source list, by hand, from memory.

Approach 3: give the cloud agent reach with MCP

The first two approaches help you, working interactively. The third helps the autonomous path, the cloud agent that takes an issue and opens a pull request, which is exactly the surface the original feature request was filed against.

The agent’s environment is configured through a copilot-setup-steps.yml workflow file, and the community workaround for its single-repo scoping is now well documented: configure an MCP server in the agent’s environment, typically the GitHub MCP server itself, supplied with a fine-grained personal access token stored as an Actions secret, scoped read-only to the sibling repositories it needs. The agent working in web-app can then search and read orders-service mid-task.

This works, and for teams committed to the cloud agent it is currently the only way to get cross-repo awareness into it at all. It is also the approach with the most operational surface: a PAT to mint, rotate, and audit, a workflow file to maintain per repo, and a security review conversation about why an autonomous agent holds credentials to repositories beyond the one it is changing.

And it has the limit I keep writing about, because it is the limit underneath this whole product category: this is access, not structure. I made the full argument in Repo access was never the hard part, so here it is in two sentences. The agent can now read orders-service while editing web-app. Nothing tells it that it should, or that a third repo consumes the same contract and is not in its token’s scope at all.

The question all three approaches skip

Look at what the three approaches have in common. A .code-workspace file with a folders list. A Space with a sources list. A PAT scoped to a repository list. Every one of them answers the question “how do I put more repositories in front of Copilot”, and every one of them quietly delegates the harder question back to you: which repositories?

That list is a hand-maintained model of what depends on what. Maintaining it has a name on this blog, because platform teams have been running this exact experiment for years with service catalogs: it is the catalog maintenance trap. The list is accurate the day it is written, it drifts the moment the system changes, and nothing tells you it drifted. A workspace missing the repo that consumes your contract does not error. It just gives the agent a confident, complete-looking view of an incomplete world, which is the precise failure mode where a wrong map beats no map for damage done.

What surprised me, going through the tooling landscape for this post, is that nothing else in the stack answers the question either. Renovate understands dependency manifests more deeply than almost any tool in existence, one repository at a time. Asked directly whether cross-repository dependency detection was planned, a maintainer’s answer this May was unambiguous: “Renovate only operates on a per-repository basis”, with no plans to change. Dependabot has the same shape. The tools that read your manifests every single day read them one repo at a time, and then forget what they saw.

So the “which repositories” question goes unanswered by default. But here is the thing: for most of the edges that matter, the answer is already written down.

I will concede the exception first, because it is real. The rawest version of the web-app to orders-service edge, a fetch against a service URL, is declared nowhere. No parser will ever find it, and anyone who tells you otherwise is inferring it from names and hoping. But the moment a team formalises that contract, a shared types package, a client SDK, a published schema, and at any scale beyond two repos they do, the edge lands in a manifest. A package.json dependency on the contracts package. A go.mod require. And the edges that carry the rest of the org are declared the same way: Terraform source blocks pointing at module repos, Dockerfile FROM lines pointing at base images built elsewhere, Helm Chart.yaml dependencies, GitLab CI includes and reusable GitHub Actions workflow uses: references. I have spent a whole series walking those edges one ecosystem at a time. They are deterministic. Parsed, not inferred. The dependency graph that should be writing your workspace file already exists in your org’s manifests, unassembled.

Feeding the graph back into Copilot

This is the part that turns the argument into a setup, so let me be concrete. A queryable cross-repo dependency graph does not replace the three approaches above. It feeds them, in three places.

It writes the lists. The folders array in the workspace file, the source list in the Space, the repo scope on the agent’s PAT: generate them from a dependents query instead of from memory. “Every repo that consumes the orders-service contract package” is one API call, and when the graph changes, the lists change with it. The curation problem does not get solved by curating harder. It gets solved by deriving.

It is a tool call during the task. In agent mode, Copilot can call out to tools, and the graph as an HTTP API means a planning step can ask “who depends on what I am about to change” before the first edit. With Riftmap that is two calls:

# Resolve the working tree to a node in the graph
REPO_ID=$(curl -s \
  "https://api.riftmap.dev/api/v1/repositories/lookup?url=https://github.com/myorg/orders-service" \
  -H "X-API-Key: $RIFTMAP_API_KEY" | jq -r '.id')

# One round-trip: dependencies, dependents, artifacts
curl -s "https://api.riftmap.dev/api/v1/repositories/$REPO_ID/context" \
  -H "X-API-Key: $RIFTMAP_API_KEY"

For the cloud agent, the same pattern works with the API key as an Actions secret in the agent’s environment. The agent integration guide covers the full call pattern, and one rule from it matters more than the rest: every response carries last_scanned_at and last_activity_at, and if the repo has been pushed to since it was last scanned, the agent treats the graph as stale and says so. That is the “context that decays” problem handled as a contract rather than a hope.

It is the same map at review time. On a pull request touching a shared component, CI queries the transitive impact and posts the consumer list as a comment, so the human reviewing the agent’s change is checking it against the same structural account the agent planned with, instead of against memory.

That last point is the architecture I think this whole category lands on, and you do not need my product to adopt it. Mabl built their own coordination graph by hand and runs agents across 100-plus repos on top of it. The pattern is the point: a parsed, queryable graph underneath, and Copilot, or whichever agent you run, consuming it. Riftmap is the version of that substrate you do not have to build, auto-discovered from one read-only token across GitLab or GitHub, with the API above on every tier.

So, to answer the question the feature request actually asked. The best practice for approximating cross-repo context in Copilot today is one of the three approaches above, chosen by which Copilot surface you live in. The best practice for making any of them survive contact with a changing org is to stop hand-maintaining the repository lists they all depend on, and derive them from the graph your manifests already declare.

Every one of these approaches ends in a list of repositories that somebody has to get right. You can maintain that list, or you can derive it. Only one of those is still correct three months from now.