The specific failure that prompted this setup: Copilot Workspace suggested a fix for a failing test in blogs/coding-dunia, and the suggested code referenced a component that only existed in blogs/real-smart-home, a completely different Astro project sharing the same monorepo. The two packages had similarly-named files, and without an explicit scoping hint, Copilot's retrieval treated the whole repo as one undifferentiated codebase.
TL;DR: Copilot Workspace's context retrieval isn't monorepo-aware by default, similarly-named files across unrelated packages can bleed into its suggestions. A
.github/copilot-instructions.mddescribing the monorepo's package boundaries, shared conventions, and per-package differences is the single most effective fix, read on every session rather than something you have to repeat in every prompt.
The Instructions File That Fixed It
<!-- .github/copilot-instructions.md -->
# Repository Structure
This is a Yarn 4 workspace monorepo. Packages live under two roots:
- `packages/*`: shared TypeScript libraries, consumed by blog sites via
`@local/blog-toolkit`. Changes here affect every blog.
- `blogs/*`: individual Astro sites, each with its own `package.json`,
`astro.config.mjs`, and `src/content/` collection. Each blog is
independent; code in one blog's `src/` never imports from another
blog's `src/` directly.
# When Suggesting a Fix
- Check which package the file under discussion belongs to before
suggesting a related file, changes to `blogs/coding-dunia/src/`
should never reference `blogs/real-smart-home/src/` or vice versa.
- Shared logic belongs in `packages/shared/src/`, not duplicated across
blog packages. If a fix looks like it should be shared, check
`packages/shared/src/` for an existing utility first.
# Conventions
- TypeScript strict mode is enabled everywhere; don't suggest `any`.
- Tests use Vitest, files are `*.test.ts` under `tests/`.
This is read automatically on every Copilot Workspace session in the repo, it's the equivalent of a project's CLAUDE.md for Claude Code, giving the same persistent context without needing to restate the monorepo's structure in every individual prompt.
Scoping a Session to One Package
Beyond the persistent instructions file, Copilot Workspace sessions themselves benefit from an explicit scope statement at the start of a task description, rather than relying on file selection alone to communicate intent:
Task: Fix the failing test in blogs/coding-dunia/tests/unit/validator.test.ts
Scope: This task only touches blogs/coding-dunia/. Do not modify files
in packages/shared/ or any other blogs/* package, even if a similar
pattern exists there.
Being explicit about what's out of scope, not just what's in scope, cuts down on a specific failure mode: Copilot proposing a "consistency" fix that touches a sibling package's file because it found a similar pattern there, when the actual task only needed the one file changed.
Handling Shared Package Version Drift
Monorepos often have version drift between packages, a dependency pinned differently in blogs/coding-dunia/package.json than in blogs/real-smart-home/package.json, sometimes deliberately. Without guidance, Copilot's suggestions can assume a version's API that isn't actually what's installed in the specific package being edited:
# In .github/copilot-instructions.md
# Dependency Versions
Package versions can differ between `blogs/*` sites. Before suggesting
an API from a dependency (React, Astro, etc.), check that package's own
`package.json` for its actual installed version, don't assume the
version used in a different blogs/* package applies here.
This single paragraph fixed a recurring issue where a Copilot suggestion used a React 19-only API (use()) in a package still on React 18, because a sibling package in the same monorepo happened to be on React 19 and Copilot's retrieval picked up that context instead.
What Directory-Scoped Instructions Add
For monorepos with genuinely divergent package conventions, not just different dependency versions, a nested .github/copilot-instructions.md inside a specific package directory can layer additional, package-specific guidance on top of the root file, where the platform supports it:
<!-- blogs/coding-dunia/.github/copilot-instructions.md -->
# Coding Dunia Specific Conventions
This blog uses Astro Content Collections with a strict `category` enum
(see src/content.config.ts). Never suggest a category value outside:
react, typescript, javascript, nodejs, css, performance, tooling.
The root file covers repo-wide structure; a package-scoped file covers the specific conventions that only make sense in the context of that one package, like a closed content-category enum that would be meaningless guidance to apply repo-wide.
Conclusion
The gap between "Copilot works fine on a small project" and "Copilot keeps suggesting the wrong package's file" is almost always a missing instructions file, not a limitation of the tool itself. A .github/copilot-instructions.md that states the monorepo's package boundaries, shared-vs-independent code locations, and per-package version differences fixes the cross-contamination failure mode directly, and it only needs to be written once per repo, not repeated in every prompt.