Skip to content

Multi-stack support — React/React Native now (Stage 1), any detected stack via L2 research (Stage 2) #646

Description

@artyhoo

Summary

The framework's promise is "generate enforcement rules from principles, not copy-pasted presets" (README "Methodology"), but it currently ships one preset — preset-next-15-canonical — and install.sh only accepts ts-server / react-next. This issue tracks making the one-button install configure the full enforcement perimeter (rules-as-tests + mutation + arch boundaries + hooks/CI + docs/skills/agents) for more stacks, in two stages:

  • Stage 1 (curated bridge): add react (SPA) and react-native (Expo/RN) presets by hand. Cheap relative to Stage 2, not zero — includes de-Next-ifying shared templates (eslint.config.react.mjs currently pulls @next/eslint-plugin-next).
  • Stage 2 (general): realize the deferred L2 LLM-driven research path so an arbitrary detected stack is researched → synthesized → self-validated → installed, removing the per-stack hand-authoring bottleneck — without weakening "documents lie; tests don't".

Why it's Next-only today (grounded)

  • The engine is already stack-agnostic: synthesizer/synthesize.ts is a pure ResearchPlan → SynthesisPlan function, recipes filtered by an appliesTo: string[] framework key. The detector already generalizes (packages/core/detector/ emits stack + version + missing[] for any project; does not assume Next).
  • The content is Next-only: synthesizer/recipes/ has 5 files, all next-* / nextjs-*; only preset package is packages/preset-next-15-canonical/. Its 3 ESLint rules are Next-specific (RSC server/client boundary + server actions).
  • The research layer (L2) was pivoted to deterministic-curated in Phase 5 — no live LLM/HTTP at runtime (retros/phase-5.md:14-19). LLM-driven research is the documented future superset, deferred to a v2 trigger (retros/phase-5.md:81,151); the v2 contract (Anthropic web_search + allowed_domains) is already stubbed as a static allowlist (:19,73).
  • Stack-agnostic core already applies to any TS project: no-direct-time-randomness, no-unsafe-zod-parse, require-otel-span (packages/core/eslint-rules/).

So "more stacks" is blocked on rule content, not the pipeline.

Stage 1 — curated react and react-native presets

Presets

  • packages/preset-react-spa/ — React 19 SPA on Vite (no SSR / server actions).
  • packages/preset-react-native/ — Expo / React Native.

Mirror the preset-next-15-canonical layout: eslint-rules/, templates/ (eslint config, test-runner config, ARCHITECTURE.*.md, CI workflow), RULES.*.md, audit-self/.

Installer wiring

  • Accept react / react-native in the arg parser (install.sh:81) and stack guard (:189).
  • Add menu options 3) react / 4) react-native (install.sh:177-190).
  • Extend auto-detect: react-native/expo in deps → react-native; react-dom present and next absent → react; else existing fallback.

Rules — REUSE first (per build-first-reuse-default.md)

  • React SPA: ADOPT eslint-plugin-react, eslint-plugin-react-hooks (exhaustive-deps), eslint-plugin-jsx-a11y (already in the dev-dep list). BUILD only gap rules, candidates: no-business-logic-in-component (via dependency-cruiser layer boundary), require-error-boundary.
  • React Native: BUILD where no upstream analog fits — no-web-only-globals (flag document/window/localStorage/DOM in RN), require-stylesheet-create, prefer-flashlist-over-flatlist. Each ships a paired valid/invalid test (principle 02).
  • REFERENCE existing ecosystem skills instead of re-deriving RN best practices: react-native-best-practices, building-native-ui, vercel-react-native-skills, treemap-rn.
  • Prior-art SSOT is empty for these plugins — no eslint-plugin-react/react-native entries in prior-art-evaluations.md today. The BUILD candidates above are hypotheses pending a per-preset R-phase (DeepWiki/WebSearch ≥3 phrasings + SSOT consult), not approved builds. Stage 1 adds the ADOPT/BUILD verdict entries as an explicit deliverable (each rule is a capability commit).

These two presets also serve as the proving cases for Stage 2's generate path.

Stage 2 — any detected stack (L2 LLM research path / v2)

L2 Research Agent — LLM path (Planner, read-only)

Implement the live path behind the existing L2 interface (packages/core/research/): given {stack, version, missing[]} from the detector, produce a versioned ResearchPlan (research-plan.schema.json) via Anthropic web_search constrained to allowed_domains. Planner is read-only — never writes files (keeps the L2/L3 prompt-injection firewall: untrusted fetched docs can't reach disk).

L3 Synthesizer — generalize beyond curated recipes

When no curated recipe matches a researched pattern, emit a candidate rule from the research plan as a structured, validated SynthesisPlan (never free-form LLM code). Curated recipes stay the deterministic fast-path/cache for known stacks (Next stays byte-stable).

L4 Self-validation gate — BUILD, then mandatory (tenet-preserving)

Every generated rule — curated or LLM-derived — must pass the principle gate before install: paired negative test (02), non-tautological (04), AST-over-grep where applicable (03), manifest-SSOT (05). A rule that can't fail against a synthetic violation fixture is dropped, not shipped. Determinism moves from "how the rule was authored" to "the rule provably fails when violated". Note: the L4 install-gate does not exist yet — retros/phase-5.md deferred the L4 Validator to "Phase 7+". Building it is an explicit Stage 2 deliverable, not a pre-existing mechanism this stage merely invokes.

Installer wiring — generic stack

  • Detector result → curated preset if one exists, else the generate-and-validate flow.
  • Generation is an explicit, consumer-side, opt-in step (--generate / AIF_RESEARCH=llm) run install-time on the consumer's own Claude subscription — never in CI, so no-paid-llm-in-ci.md is intact. The framework itself never bills: any cost is the consumer's own, incurred only on explicit opt-in.
  • Cache the generated ResearchPlan + SynthesisPlan into .ai-factory/ so re-installs / --refresh are deterministic and reviewable (snapshot the artifact, not the generation).

Sequencing commitment (hybrid decision — added 2026-06-19)

Stage 1 is a bridge, not a terminus. To prevent it from stranding 3 hand-maintained presets (the "stale presets" failure README §Methodology warns of):

  • On Stage 1 close (both presets merged) → the merging session writes docs/meta-factory/research-patches/<date>-phase-5-v2-trigger-fired.md (fires the deferred Phase-5 v2 trigger this issue already names) AND opens the Stage 2 tracking umbrella. Stage 2 is the mandatory immediately-following umbrella, not "someday".
  • Until that patch lands, every hand-authored preset beyond Next is tracked debt against README §Methodology, not silent drift.

Design rationale: docs/superpowers/specs/2026-06-19-multi-stack-hybrid-design.md (hybrid A-now + B-committed, with full A-vs-B trade-off analysis).

Acceptance criteria

Stage 1:

  • ./install.sh react --dry-run and ./install.sh react-native --dry-run complete with ✅ Dry-run complete, no ❌ Unknown stack.
  • Fresh Vite-React and Expo repos install cleanly; lint / test / arch:check / test:mutation all run; at least one custom rule per stack catches its target antipattern.

Stage 2:

  • ./install.sh --generate on a stack with no curated preset (e.g. SvelteKit, Vue SPA, Fastify-only) installs a stack-appropriate set; every generated rule has a passing/failing paired test; rules failing the L4 gate are reported and excluded.
  • Next.js path stays byte-identical; re-install from cache is deterministic.

Both: make self-audit stays green (recursive self-application unbroken); auto-detect picks the right stack from package.json.

Conventions to honor (repo discipline)

  • Each new preset/rule is a capability commit → prior-art consult (docs/meta-factory/prior-art-evaluations.md) + DeepWiki/WebSearch ≥3 phrasings + Prior-art: trailer (CLAUDE.md "Build-vs-reuse invariant"). Default per build-first-reuse-default.md: ADOPT upstream lint plugins; BUILD only genuine gaps + the research→synthesize→validate pipeline.
  • New shipped docs (RULES.*.md, ARCHITECTURE.*.md) carry Authoritative for: headers and join SHIPPED_DOCS in install.sh (principle 09). New rules ship paired negative tests (principle 02), AST-over-grep where applicable (principle 03).
  • Stage 2 must preserve the L2 (read-only Planner) / L3 (validated-output-only) prompt-injection split; LLM fetch constrained to allowed_domains. no-paid-llm-in-ci.md unchanged (research is install-time, not CI). Document Stage 2 as the firing of the deferred Phase-5 v2 trigger in a research-patch.

Risks / open questions

  • LLM non-determinism → mitigated by L4 gate + caching the generated artifact; open: how to snapshot-test a path whose first run is variable (test the validator on fixtures, not raw generator output).
  • Research quality for niche stacks → low-confidence stacks install only stack-agnostic core + flag "generated, review before trusting"; never claim full coverage.

Code claims in this issue verified against staging on 2026-06-19: install.sh:81 accepts only ts-server|react-next (guard :189-190, menu :179-184); synthesizer/recipes/ = 5 files, all next-*/nextjs-*; single packages/preset-next-15-canonical; 3 agnostic core rules in packages/core/eslint-rules/; L2 scaffolding present (packages/core/research/ incl. research-plan.schema.json, allowlist.ts, validate-plan.ts).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestepicLarge multi-stage feature spanning multiple PRsmeta-factoryRelates to the meta-factory (rule-generation pipeline / synthesizer / research)stack-supportAdds or extends support for a tech stack (preset / detector / installer)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions