1What you can ask it
| Command | What it does |
|---|---|
/netrya:kickoff | Intake questions and a stack decision before anything is scaffolded |
/netrya:modernize | Phased migration onto the stack: tests first, existing look and feel preserved by contract |
/netrya:pair | Prototype in code with stakeholders instead of Figma, then iterate on feedback |
/netrya:review | Code review, plus a design review at 1440, 768 and 375 if anything visual changed |
/netrya:doctor | The full quality gate, with failures triaged |
/netrya:ship | Gate, then draft the PR with screenshots and test evidence |
/netrya:standup | Where the project stands against the bar, and the three things worth doing next |
/netrya:drift | What changed upstream since the last check, and a draft PR for the safe parts |
2It catches problems as Claude writes them
A typical first draft of a plate-QC dashboard: MUI, Recharts, a native select, a hard-coded brand colour. The moment Claude saves the file, Netrya's hook reviews it and hands the findings straight back to Claude, which fixes them in the same turn. It never blocks the edit.
src/PlateQCDashboard.tsx, as first written
import { useEffect, useState } from "react";
import { Button } from "@mui/material";
import { LineChart } from "recharts";
export function PlateQCDashboard({ plates }: { plates: Plate[] }) {
const [passRate, setPassRate] = useState(0);
useEffect(() => {
setPassRate(plates.filter((p) => p.ok).length / plates.length);
}, [plates]);
return (
<div className="bg-blue-500 font-medium" style={{ color: "#005596" }}>
<select>{plates.map((p) => <option key={p.id}>{p.id}</option>)}</select>
<LineChart data={plates} />
<Button onClick={() => window.confirm("Reject plate?")}>Reject</Button>
Pass rate {passRate}
</div>
);
}What the hook tells Claude, immediately
Design system check โ app/src/PlateQCDashboard.tsx โข Material UI import โ use @cs-coe registry components (npx shadcn@latest add @cs-coe/<name>) โข Chart library import โ use @tanstack/charts โข <select> โ use <Select> from @cs-coe/select โข window.confirm() โ use <AlertDialog> from @cs-coe/alert-dialog โข Hardcoded #005596 โ use bg-primary / text-primary โข Tailwind color-scale class โ use semantic tokens (bg-primary, text-muted-foreground) โข font-medium โ Gene Sans has no weight 500. Use font-normal (400), font-semibold (600), or font-bold (700) Run 'npm run check:design-system' for the full, authoritative pass.
3The same gate before every PR
/netrya:doctor and /netrya:ship run the full quality gate. Two of its checks are shown here: the design-system check, and the monorepo's mandatory useEffect rule, which Netrya now wires into every new app.
npm run check:design-system
Design system check โ 1 files in: src โ BANNED_IMPORT src/PlateQCDashboard.tsx:2 Material UI import โ Use @cs-coe registry components: npx shadcn@latest add @cs-coe/<name> โ BANNED_IMPORT src/PlateQCDashboard.tsx:3 Banned chart library import โ Use @tanstack/charts โ RAW_HTML src/PlateQCDashboard.tsx:13 Native <select> element โ Use <Select> from @cs-coe/select โ RAW_HTML src/PlateQCDashboard.tsx:15 window.confirm() โ Use <AlertDialog> from @cs-coe/alert-dialog โ HARDCODED_COLOR src/PlateQCDashboard.tsx:12 Hardcoded Genentech Blue โ Use bg-primary / text-primary โ TAILWIND_COLOR src/PlateQCDashboard.tsx:12 Tailwind color-scale class โ Use semantic tokens (bg-primary, text-muted-foreground) โ FONT_WEIGHT src/PlateQCDashboard.tsx:12 font-medium โ Gene Sans has no weight 500 โ Use font-normal (400), font-semibold (600, house style), or font-bold (700) Violations: 4 Warnings: 3 Install registry components with: npx shadcn@latest add @cs-coe/<component> See AGENTS.md for the full component mapping and token list. Note: .astro files are not scanned โ review those templates by eye.
npm run check:useeffect
โโโ useEffect Guard โโโ
Scanning for unjustified useEffect calls...
โ src/PlateQCDashboard.tsx:7
useEffect(() => {
โ Add: // useEffect: <describe the external system being synchronized>
โโโ useEffect Guard Summary โโโ
โ 1 file(s) with useEffect in exempt paths (ui/, gyde/, tests)
โ 1 unjustified useEffect call(s)
Every useEffect must have a comment on the line above:
// useEffect: sync chart resize observer with container dimensions
useEffect(() => { ... }, [width, height]);
Common replacements (https://react.dev/learn/you-might-not-need-an-effect):
โข Derived state โ compute during render
โข Data fetching โ TanStack Query, loader, or server component
โข User-caused work โ event handler
โข Reset on prop change โ key the component
โข External store โ useSyncExternalStore4Staying current with the design system
A month after adopting v0.3.0, upstream ships v0.4.0. /netrya:drift compares every installed component against the registry and a saved baseline, so it knows which side moved.
Drift check against v0.4.0
Registry items: 4 Local ui files: 4
! upstream-update (1)
safe to reinstall: npx shadcn@latest add @cs-coe/<name>
button src/components/ui/button.tsx
! conflict (1)
both sides changed โ merge by hand, then --write-baseline --resolve <name>
card src/components/ui/card.tsx
local-customization (1)
allowed โ confirm it is still intentional
badge src/components/ui/badge.tsx
in-sync (1)
dialog src/components/ui/dialog.tsx
Actionable: 2After merging card by hand: --resolve card
drift-scan: card resolved at its current hashes
Registry items: 4 Local ui files: 4
! upstream-update (1)
safe to reinstall: npx shadcn@latest add @cs-coe/<name>
button src/components/ui/button.tsx
local-customization (2)
allowed โ confirm it is still intentional
badge src/components/ui/badge.tsx
card src/components/ui/card.tsx
in-sync (1)
dialog src/components/ui/dialog.tsx
Actionable: 15DevOps and DevEx: from first commit to production
Netrya doesn't stop at the code. It knows the environments, pipelines and deploys the CS CoE runs, and /netrya:ship wires the same CI and deployment into a new app, so it has the monorepo's path to production from day one.
Ephemeral dev environments in the monorepo
- One click opens a fresh Ona workspace from
.devcontainer, on Roche's Ona base image - Node 22, the GitHub CLI and the pinned Playwright Chromium builds are baked in;
ffmpegand Xvfb are there for screenshots and demo GIFs - Automations install all three apps, verify the browsers, and install
@cs-coecomponents into prototypes from a registry served locally - Dev servers start with health checks on
:4320components,:4321showcase and:4322prototypes, and are thrown away when you're done
CI that is a real gate in new apps
- An 8-job pipeline template: lockfile sync, design-system and
useEffectchecks, lint, typecheck, unit tests with coverage, accessibility, visual regression, build - Every action is pinned to a commit SHA, and every workflow has least-privilege permissions
- react-doctor as advisory, knip for dead code,
CODEOWNERSand a PR template with screenshot and test evidence /netrya:shipruns the gate, then drafts the PR
Continuous deployment live
maingoes to production on every merge; tags mark the versions teams upgrade to- Cloudflare Pages at
cscoe-frontend.ghpages.roche.com: every Roche employee via SSO, no GitHub licence needed - Deploys use GitHub OIDC exchanged for a Vault token, so no cloud secret lives in the repo
- GitHub Pages mirror; each app gets its own
ASTRO_BASEsubpath, with the registry JSON served alongside
Protected review environments ready to enable
- Model evals run on Amazon Bedrock through OIDC: no API keys anywhere
netrya-evalsis locked tomainfor the unattended weekly runnetrya-evals-reviewrequires a second reviewer before any branch run gets credentials- Built and in review; switches on once the Bedrock role is created
- Pull requests get an offline validation job and never touch paid infrastructure
Per-PR preview environments, for review and for prototyping proven on TargetNexus part of Netrya
Every pull request gets its own live, short-lived environment with a shareable link, torn down on merge. It's the same mechanism whether the change is production code or a prototype.
A new engineer on TargetNexus spotted rough edges in the Reports table. Instead of filing a ticket or drawing a mockup, they used the AI coding setup to prototype table changes in a preview environment the team could try for themselves.
A drive-by idea became something working to react to, without touching production.
6TargetNexus as a benchmark
Our team works in the openโฆ in private Slack channels. So the iteration history lived in threads, not in any tracker. I built a skill to read it back and measure how often each feature was reworked: the UX/Product Rework-Rate Baseline Report.
7Netrya on a real app: DDC Forge
DDC Forge is built on the Frontend Tech Solutions stack and was AI-coded from the app starter prompts. I ran Netrya's quality gate, useEffect guard and drift check against its frontend (roche-innersource/cscoe-ddc-forge, commit c4f1534), read-only, with no install and none of its own code executed.
| Area | Result | What Netrya found |
|---|---|---|
| Right from the start: the starter prompts at work | ||
| Stack | Strong | React 19, TypeScript, Tailwind v4 CSS-first, Base UI, TanStack Query and Table, lucide, and the @cs-coe registry already configured. Vite and React Router instead of an Astro shell, which is reasonable for a single-page app. |
| Theme | Strong | Aligned: --primary is Genentech Blue, on a CSS-first token system. Two refinements: the font is Inter rather than Gene Sans (which is why font-medium appears in 60 files: fine under Inter, invalid under Gene Sans), and status colours are hard-coded Tailwind scales in 44 files (text-green-700 ร20, bg-red-50 ร15, โฆ) where --success, --warning and --info tokens now exist. 8 files override colours with dark:. |
| Tests | Strong | 173 unit test files, 11 Playwright specs, an axe accessibility spec and visual regression. Gap: the e2e, accessibility and visual suites run nightly only, so a PR can merge a regression they would catch. |
| Grown in organically: architecture and CI patterns | ||
| Effects | Gap | 97 effects without a // useEffect: justification, and 13 suppressed exhaustive-deps warnings. The monorepo makes this mandatory; nothing in forge checks it. |
| Components | Partial | 23 of the 61 registry components are installed, all edited locally. The biggest difference is Prettier style: forge drops semicolons, so every file differs from upstream. Eight components are hand-built, and the registry now covers three of them: multi-select-filter โ the chip multi-select combobox (#515), pagination-bar โ pagination, date-range-picker โ calendar. Also 1 native <select> and 1 direct Base UI import. |
| CI gates | Partial | PR CI runs lint, typecheck and unit tests with coverage. It doesn't run the design-system check, the useEffect check, a format check, knip or react-doctor. |
The three things worth doing next
1. Addcheck:useeffectandcheck:design-systemto PR CI, and run the accessibility suite on PRs, not nightly.
2. Move status colours onto thesuccess,warningandinfotokens, and decide on Gene Sans vs Inter.
3. Swap the hand-built multi-select, pagination and date-range picker for the registry versions, then re-run the drift check with a baseline.
What running it taught us about Netrya
Dogfooding on a real codebase found four fixes to make in the plugin itself:
โข The batch design-system script ran over 7 minutes on 349 files without finishing; the hook's rules covered 575 files in 34 s.
โข The drift check counted.testand.storiesfiles as components.
โข--ignore-whitespacedoesn't absorb Prettier style such as semicolons, so a formatted fork reads as all-drift.
โข Thefont-mediumrule assumes Gene Sans; it should follow the app's actual font.
8Netrya on a real app: Autolab
A different starting point. Autolab's web frontend (roche-innersource/cscoe-openlab, src/autolab/web, commit a72af34) is hand-built and doesn't use the Frontend Tech Solutions stack. Where DDC Forge needs a drift check, Autolab needs /netrya:modernize. Same read-only run: no install, and none of its code executed.
| Area | Result | What Netrya found |
|---|---|---|
| Already in good shape | ||
| Footprint | Strong | Only six runtime dependencies. TypeScript throughout, Janus auth (@janus/core) wired in, and dedicated deploy workflows for the web app, Ona and promotion between environments. |
| Theme | Own system | A well-engineered token layer: CSS custom properties, light and dark via data-theme, Tailwind colours mapped to tokens. But it's Autolab's own warm monochrome palette in Inter, not the Genentech theme. |
| Where modernization pays off | ||
| Stack | Behind | React 18, Tailwind 3 with a JavaScript config, Vite 5 and React Router 6. The stack is React 19, Tailwind v4 CSS-first, Base UI and TanStack. |
| Components | Gap | No @cs-coe registry. Its own primitives (Btn, Card, Field, โฆ) are used in only 2 files; the rest is inline markup: 9 raw <table>s, hand-built dialogs in 4 files, 17 inline SVG icons, 2 window.confirm() and a native <select>, each with a registry equivalent. |
| Effects | Gap | 94 unjustified useEffect calls in 133 files, plus 5 suppressed exhaustive-deps warnings: several times Forge's density. |
| Tests | Partial | 10 unit test files, all for logic (utils, hooks, parsers). No component, end-to-end, accessibility or visual regression tests. |
| CI gates | Partial | CI installs, runs the unit tests and builds (which type-checks). No ESLint (lint is just tsc), no Prettier, and no design-system, useEffect or accessibility check. |
The plan /netrya:modernize would produce
1. Test hardening first: Playwright journeys that query by role and name, and visual baselines that lock in today's look.
2. React 18 โ 19, then a Tailwind v4 token layer carrying Autolab's current palette.
3. Registry components screen by screen: dialogs, tables, tooltips, select, alert dialog.
4. Justify or replace the 94 effects, and add the gates to CI.
5. Optional, last: adopt the Genentech theme, as a deliberate and reviewed visual change.
Two apps, two ways in
DDC Forge started on the stack via starter prompts, so Netrya's job is keeping it there: drift checks, gates, and effect discipline.
Autolab predates the stack, so Netrya's job is getting it there without breaking it: tests first, look and feel preserved by contract, one phase at a time.
Both scans ran in seconds; each analysis cost one to two dollars.
9Built to the bar it enforces
| 39 / 39 | Plugin script tests: drift scanner, CLI, and the hook under macOS /bin/bash |
| 25 / 25 | CI script tests: eval summary, retry logic, offline case validator |
| 14 / 14 | Repository CI checks green on merge, including CodeQL |
| 14 rows | Places this repo's docs contradict its code, which Netrya knows and won't repeat. The drift check re-verifies them monthly. |
What's next
So far this is built from new apps. The next step is the harder half.
Apply it to existing applications
- Point Netrya at apps already in production and bring them onto the stack
- The modernization skill already exists: tests first, look and feel preserved by contract, one phase at a time
A modernization factory, with Lech
- Likely collaboration with Lech on a modernization factory
- Exploring how Netrya's modernization skill can feed repeatable migrations at scale