Profiles & stacks
Eighteen stack rule sets, composed into profiles. A repo installs exactly one profile — that is the entire disambiguation mechanism.
Why profiles, not glob negation
Negated globs (!**/*.native.*) are not part of Copilot's applyTo contract and have no AGENTS.md equivalent at all — relying on them meant React rules silently firing on NestJS files. Instead, a profile never contains two rule sets that contradict each other, so plain globs are unambiguous inside any single repo. scripts/validate.mjs fails the build if a negated or brace-expanded glob is ever reintroduced.
The profiles
| Profile | Stacks |
|---|---|
| web-react | javascript · react |
| web-next | javascript · react · nextjs (App Router) |
| web-angular | javascript · angular |
| web-vue | javascript · vue |
| web-svelte | javascript · svelte / sveltekit |
| web-vanilla | javascript · browser / dom |
| mobile-rn | javascript · react · react-native |
| mobile-android | kotlin |
| mobile-ios | swift |
| service-java | microservices · java (Spring Boot) |
| service-go | microservices · go |
| service-node | javascript · microservices · nodejs (NestJS) |
| service-express | javascript · microservices · express |
| service-python | microservices · python |
| service-dotnet | microservices · csharp |
| fullstack-node | javascript · react · microservices · nodejs |
| infra | terraform / hcl |
| tooling | javascript |
The one deliberate overlap — mobile-rn installing both React and React Native — is additive by design, and each file says so in its own text. Legacy names (mobile, node, java…) are accepted as aliases.
web is one of those aliases. It used to mean React, because React was the only web framework Redline carried; it now resolves to web-react and renders the same rules it always did. A repo onboarded before the split needs no change: the only difference in its artifacts is the marker line, which names the resolved profile and so reads profile: web-react. Naming the framework in .redline.json is still clearer for whoever reads it next.
web-next and service-express are both cases where a broader profile would otherwise claim the repo. Every Next.js repo also depends on React, and detection tries web-nextfirst so a Next codebase is not reviewed with nothing covering Server Actions, the client boundary or NEXT_PUBLIC_. Express runs the other way: it is a dev dependency in a great many front-end repos, so it is tried last, below every web framework — a React app with an express dev server is a React app. A NestJS service that lists express directly stays service-node, because the Express rules say in their own scope section that they do not apply to Nest.
web-vanilla is never proposed by detection, only chosen. Plain browser JavaScript and a build script are indistinguishable from the outside, and guessing wrong installs DOM rules on a repo with no DOM. Its rule set covers what a framework normally hides: innerHTML sinks, postMessage origin checks, listeners and observers that outlive their widget.
Stack coverage vs org reality
Primary-language tally across the org's active repos: Java 187 · TypeScript 86 · Python 47 · JavaScript 32 · HCL 24 · C# 22 · Kotlin 14 · Swift 9 · Go 6 — all covered, including plain JavaScript. On the web side the framework is what decides the rules, not the language, which is why there are six web profiles and one javascript stack underneath all of them. Shell, Dockerfile and Gherkin are intentionally uncovered: linters serve better than LLM review there.