Plugin-Framework-Version-Compatibility
Design Log #172 — Plugin ↔ Framework Version Compatibility (CLI)
Written for AI agents. See Log Methodology Note below for details.
Background
Jay Stack projects install plugins via yarn add + jay-stack setup + jay-stack agent-kit. Today, tooling that triggers install (including npm create jay and downstream UIs) often resolves registry latest with no check against the project's existing @jay-framework/* line.
That worked while plugin and framework versions moved together. It breaks when they diverge — e.g. a project on ^0.20.0 installing a plugin whose package.json requires @jay-framework/stack-server-runtime@^0.22.2. Yarn can install two framework trees, causing subtle runtime failures.
Future: Wix integration packages (wix-media, wix-stores, …) may ship on a different cadence than core Jay. Plugin version numbers must not be assumed equal to framework version numbers.
Related: Design Log #86 (lifecycle), #87 (setup), #153 (npm create jay), #66 (transitive plugin deps). Orchestrated install + structured reports are specified in a separate consumer design (AIditor DL#35); this log owns compatibility resolution in stack-cli.
Problem
- Latest ≠ compatible — install picks newest publish without reading framework requirements.
- Requirements live in registry metadata — each plugin version's
package.jsondeclares what it needs; that must be fetched and compared to the project snapshot. - Today's plugins use
dependencies, notpeerDependencies— on@jay-framework/*(see wix-media). The resolver must readdependenciesin v1 (see §7). Longer term, plugins should migrate to peers. - No machine-readable compat report — consumers cannot offer "install older plugin" vs "upgrade framework" without duplicating logic.
- No post-install doctor signal — duplicate
@jay-framework/*versions in the lockfile go undetected.
Questions and Answers
Q: Should we assume plugin version === framework version? A: No. Resolve from packument metadata at a specific plugin version vs project snapshot.
Q: Read dependencies or peerDependencies?
A: Both. Any @jay-framework/* entry in either field is a framework requirement. v1 must read dependencies because published plugins today declare framework packages there (see §7).
Q: If latest plugin needs framework 0.22 but project is on 0.20? A: Default: install the newest plugin version that fits. Offer a structured upgrade-framework plan for latest — never silent full-project bump.
Q: Greenfield project (no @jay-framework/*)?
A: Latest plugin is fine; no compat walk.
Q: Local monorepo / plugin-sources.yaml overrides?
A: Unchanged; compat applies to registry installs only.
Design
1. Project framework snapshot
// packages/jay-stack/stack-cli/lib/plugins/framework-snapshot.ts
type FrameworkPackageRef = {
packageName: string; // @jay-framework/stack-server-runtime
declaredRange: string; // ^0.20.0
resolvedVersion?: string; // from yarn.lock / package-lock when available
};
type ProjectFrameworkSnapshot = {
dominantLine: string | null; // e.g. "0.20" — mode of major.minor
packages: FrameworkPackageRef[];
packageManager: 'yarn' | 'npm' | 'pnpm';
};
2. Plugin requirements at a version
// packages/jay-stack/stack-cli/lib/plugins/plugin-requirements.ts
type PluginFrameworkRequirements = {
pluginPackage: string;
pluginVersion: string;
frameworkRequirements: Record<string, string>;
};
Fetch from npm packument. Merge requirements from:
| Source | Priority |
|---|---|
peerDependencies (@jay-framework/*) |
Preferred |
dependencies (@jay-framework/*) |
Required in v1 (current publish shape) |
engines.jay (optional future) |
Single semver range string |
3. Compatibility report
// packages/jay-stack/stack-server-runtime/lib/plugin-compat-report.ts
// (shared type — CLI emits, consumers parse --json)
type CompatibilityStatus =
| 'compatible'
| 'plugin_requires_newer_framework'
| 'plugin_requires_older_framework'
| 'no_compatible_plugin_version'
| 'registry_unavailable';
type CompatibilityOption =
| {
kind: 'install-plugin';
installSpec: string;
pluginVersion: string;
recommended: boolean;
}
| {
kind: 'upgrade-framework';
bumps: Array<{ package: string; from: string; to: string }>;
requiresRestart: boolean;
}
| {
kind: 'install-latest-anyway';
installSpec: string;
warning: string;
}
| { kind: 'cancel' };
interface PluginCompatibilityReport {
pluginPackage: string;
project: ProjectFrameworkSnapshot;
status: CompatibilityStatus;
evaluatedLatest?: PluginFrameworkRequirements;
recommended?: CompatibilityOption;
options: CompatibilityOption[];
issues: PluginIssue[];
}
Extend PluginIssueCode (install report schema):
| Code | When |
|---|---|
FRAMEWORK_VERSION_MISMATCH |
Latest plugin needs newer framework |
DUAL_FRAMEWORK_TREE |
Doctor: two resolved versions of same @jay-framework/* |
NO_COMPATIBLE_PLUGIN_VERSION |
No publish fits project |
4. Resolution algorithm
resolveCompatiblePluginInstall(projectRoot, pluginPackage):
Satisfaction: project resolved (or declared) version must satisfy every frameworkRequirements range (semver).
5. CLI commands
# Preflight — no yarn add
jay-stack plugins compat <package> [--json]
# Install runs compat first unless overridden
jay-stack plugins install <package> [--json] [--version <spec>] [--force-latest]
# Optional: apply framework bumps from compat report
jay-stack deps upgrade-framework --from-report <path> [--json]
compat --json→PluginCompatibilityReportinstallwithout flags → usesrecommendedinstallSpec; exit 1 + report if no default without--force-latest- Wire into
npm create jayplugin selection (DL#153)
6. Doctor
jay-stack plugins doctor adds:
DUAL_FRAMEWORK_TREE— scan lockfile for duplicate@jay-framework/*resolved versions- Suggest
plugins compatwhen adding a new plugin package
7. Why v1 reads dependencies (not only peers)
Published Jay plugins today list framework packages under dependencies:
"dependencies": {
"@jay-framework/stack-server-runtime": "^0.21.0",
"@jay-framework/wix-server-client": "^0.22.2"
}
Meaning of "v1 still reads dependencies so existing packages work without republish":
- The ideal signal is
peerDependencies— the consumer project supplies one copy of each framework package. - Today's packages do not use peers yet. If the resolver only looked at
peerDependencies, it would see nothing and could not judge compatibility. - v1 therefore also reads
dependencieson@jay-framework/*from the registry copy of each plugin version'spackage.json. - Plugin authors can migrate to peers later; the resolver already checks both fields, so no forced republish before compat works.
Long-term plugin authoring (document in plugin agent-kit, not blocking v1):
- Move
@jay-framework/*topeerDependencies - Optional
"engines": { "jay": ">=0.20.0 <0.23.0" }
Examples
✅ Project ^0.20.0, install wix-media:
compat → latest 0.22.2 requires stack-server-runtime ^0.22.2 → mismatch
→ walk → recommend wix-media@0.20.x
❌ Avoid:
installSpec = `@jay-framework/wix-media@${project.dominantLine}.0`; // version coupling
Implementation Plan
Phase 1 — Types + resolver (~5 files in stack-cli / stack-server-runtime)
framework-snapshot.tsplugin-requirements.ts(packument fetch + parse)resolve-compatible-plugin-version.tsplugin-compat-report.ts(shared types)- Unit tests with fixture packuments (no network)
Phase 2 — CLI
plugins compatcommand- Integrate into
plugins install(coordinate with install orchestration in consumer specs) plugins doctor→DUAL_FRAMEWORK_TREE
Phase 3 — npm create jay
- Call compat before adding selected plugins
Trade-offs
- Packument fetch — network at install time; cache per run. Correctness over offline heuristic.
- Reading
dependencies— reflects what Yarn will nest today; peers migration reduces duplicate trees later. --force-latest— escape hatch; must emit explicit warning in report.
Verification Criteria
- Golf on
^0.20.0:plugins compat @jay-framework/wix-mediarecommends 0.20.x, not 0.22.x -
plugins install→ singlewix-server-clientversion in lockfile - Greenfield: latest allowed
- Unit tests use fixture packuments only
-
plugins doctorflags dual framework tree after deliberate mismatch install
Log Methodology Note
Note: These design logs are written primarily for AI agents as part of the Design Log methodology and made accessible here for human readers. The language and structure are optimized for machine consumption — expect precise, specification-style prose rather than narrative documentation.