Stack detection
Most wrong frontend edits are correct code for a stack the project does not use. Detection is cheap; guessing is not.
When this fires
Before the first edit in a frontend repo you have not already mapped in this session, and again whenever you catch yourself about to say "this project probably uses". It does not fire for a repo whose conventions you have already read this session.
Procedure
- Find the right
package.jsonfirst. In a monorepo the root one describes the workspace, not the app. Locate the nearestpackage.jsonabove the file you are changing, and note whether a root one also exists — dependencies can be hoisted, tooling config usually is. - Read dependencies and scripts together.
dependenciesanddevDependenciessay what is installed;scriptssay what is actually run. The dev, build and test commands are the ones to use later — do not inventnpm run devif the project spells it differently. - Get real versions from the lockfile, not the range.
^15.0.0inpackage.jsonis a constraint. The lockfile (package-lock.json,pnpm-lock.yaml,yarn.lock,bun.lock*) holds the resolved version, and its filename is also the only reliable statement of which package manager to invoke. Two lockfiles present is a finding, not a choice. - Read the config files that exist, and note the ones that do not. Build/framework config, TypeScript config, lint and format config, test config. Their presence tells you the tool is wired in; their contents tell you path aliases, strictness, and what is excluded.
- Confirm the routing and rendering model from the directory layout, not from the framework name. Which route directories exist, where the entry file is, whether routes are file-based or declared in code, and — for frameworks with a server/client split — which files carry the directives that mark the boundary.
- Identify the styling layer and its version. A config file's existence does not pin a major version; check the lockfile and how the stylesheet imports the framework. Also check for a CSS modules / styled-in-JS / vanilla CSS layer coexisting with it — mixed styling is common and changes what you should write.
- Check for a vendored component layer.
components.jsonor an equivalent marker plus a UI directory means components were copied in and are now project source (seeshadcn-ui). - Open two or three real source files in the area you will touch. Config says what is possible; the source says what this team actually does — import style, file naming, test colocation, state library usage.
- Write the stack down in one short block, with the file each claim came from, and a separate list of what you could not determine. That list is part of the result.
What a signal does and does not license
- A framework in
dependencies→ the framework is installed. It does not tell you which router, rendering mode or directory convention is in use. Read the layout. - A config file exists → that tool runs. It does not tell you the major version, and majors move config between files. The lockfile decides.
- TypeScript installed → files are typed. It does not mean
strictis on, thatanyis discouraged, or that generated types are current. Readtsconfigand one real file. - A test framework installed → tests can run. It does not mean they pass, cover this area, or are run in CI. Running them is a separate act.
- A state or data library installed → it is available somewhere. It does not mean the module you are editing uses it. Grep the directory you are in.
components.jsonpresent → a component CLI was used at some point. It does not mean the components are unmodified, current, or the only UI layer.- A lockfile entry → what would install.
node_modulesis what actually runs; if behaviour contradicts the lockfile, the installed tree is the tiebreaker.
Checklist
- The
package.jsonread is the one governing the file being changed - Package manager identified from the lockfile, not from habit
- Framework and styling versions taken from the lockfile
- Routing/rendering model confirmed from the directory layout
- Dev, build and test commands quoted from
scripts - At least two real source files read for convention
- Unknowns written down rather than filled in by assumption
Failure handling
- No lockfile — versions are unknown. Say so; do not resolve the range in your head. Behaviour that depends on a major version has to be checked against the installed tree or the docs.
- Conflicting signals (two lockfiles, a config for a tool that is not installed, a framework version that contradicts the layout) — report the conflict. Picking one silently makes you the source of the next bug.
- Vendored or patched dependencies (
patches/, resolutions/overrides, a checked-in fork) — upstream documentation may not describe what runs here. Read the patch. - Detection disagrees with the user — say what you found and where, then follow the user. Do not quietly rewrite their description of their own project.
Evidence to report
A short stack block — package manager, framework and version, router/rendering model, styling layer and version, component layer, TypeScript posture, test setup, dev/build/test commands — with the file each line came from, followed by an explicit "not determined" list. A stack summary with no file references is a guess with formatting.


