SuperAPI AI Directory

code-plugin-architecture

Coding & development

View repository

Updated 10-30 16:20

About this skill

Code Plugin Architecture

Keep the knowledge needed to add or remove a variant concentrated within clear boundaries. The goal is to reduce real change propagation and regressions; the structure is chosen according to the problem.

First determine what the user wants

Current request Outputs and boundaries of this round
Explanation / naming / first principles Explain the current mechanism, trade-offs, and counterexamples; do not create implementations, READMEs, or review the project
Read-only review Read the agreed scope, report the current harm, evidence, and minimal suggestions; do not delete plugins or create branches for acceptance
Design Provide the required contracts, placement, behavior, and verification approach; examples are suggestions and do not claim to be implemented
Implementation / refactoring Check the working tree, then modify within the authorized scope, preserve existing behavior and identifiers, and run the corresponding verification

Explanation, review, and design do not automatically become implementation just because this skill is loaded. Existing authorization remains in effect; new scope, external actions, and destructive migrations still require corresponding authorization. When the user only asks about an internal issue of a single variant, handle that issue and do not expand it into a mechanism overhaul.

By default, only read this file. Load the corresponding references only when the current task requires it; do not read through the entire case library for a simple question:

Choose structure starting from change

First follow the path of the most recent addition or removal of a variant, and read the existing keys, consumers, configuration, and tests. Distinguish between "the same fact must be synchronously changed in multiple places" and "implementation, tests, and copy each have legitimate responsibilities." The number of files, the number of variants, or the mere presence of a switch is not evidence for refactoring.

Check the cheapest evidence that can overturn the plan: whether real variants actually share inputs, outputs, and lifecycles; whether what is duplicated is knowledge or appearance; whether the existing framework already provides the required extension points. Check first any facts that can be found from the code. Choose ordinary reversible engineering defaults on your own; ask only about questions that affect product preferences, hard-to-reverse trade-offs, authorization, or user-specific facts.

Current complexity Reasonable starting point
A small number of stable branches, changes do not propagate Keep the function or switch; do not build a plugin system for unknown future requirements
Synchronous static entries that share simple inputs/outputs A map or function table with clear types; no store, Provider, factory, cache, or async boundary needed
Multiple variants genuinely share subscriptions, scheduling, resources, or state transitions Extract a Core that owns these lifecycles, and variants provide narrow contracts; split into directories as needed
The framework already has registration and lifecycle mechanisms Use the existing mechanisms and only add the contracts the business requires; do not copy another host
Third-party independent installation or dynamic discovery First confirm the installation model, compatibility, and permission boundaries; static registration cannot automatically satisfy this requirement

When the benefit does not hold, state "keep the status quo" and the evidence. When the user asks to prove that a certain structure must be correct, check the premises first; do not manufacture a proof.

Five concepts, applied as needed

Identity, Contract, Registry, Runtime Core, and Convention Folder are vocabulary for analyzing responsibilities; they do not require five files, five modules, or all being present every time. A simple type mapping can express the first three at once; without a lifecycle, no separate Core is needed. Directories organize the implementation; they do not determine whether the architecture holds.

  1. Identity: Reuse the most authoritative stable keys and compatible semantics. External vendor IDs, tracking event names, and published routes should not be renamed for naming consistency; local directories may keep explicit mappings. Validate external strings first, then look them up in the registry.
  2. Contract: Clearly specify inputs, outputs, failures, lifecycle, and capabilities. Identity only identifies an entry; it cannot replace a behavioral contract. Shared fields are required only if they truly apply to all variants; optional fields have clear defaults; mutually exclusive capabilities use discriminated unions or separate contracts, and optional fields are not piled on for "structural homogeneity".
  3. Registry: Give "which entries exist" a traceable composition entry point. An explicit table, a framework manifest, or a table contributed by modules and aggregated all work; a single source of truth does not mean only one physical file is allowed. Preserve the existing handling of duplicate keys, unknown keys, and missing capabilities.
  4. Runtime Core: Extract only genuinely shared scheduling and lifecycle, depend on Contract, and do not hard-code business conditions of specific plugins. Single-plugin conditions belong to variants; cross-plugin product ordering belongs to the orchestration layer. When there is no shared state, a plain calling function is enough.
  5. Convention Folder: Gather together when a single variant has multiple related resources; a simple entry staying in one file is also valid. Dependency direction should be such that removing one variant does not break unrelated variants; do not introduce a bus just to eliminate all direct imports.

The minimal static example expresses only the common function signatures and a traceable list:

type Formatter = (value: string) => string;

const formatters = {
  upper: (value: string) => value.toUpperCase(),
  lower: (value: string) => value.toLowerCase(),
} satisfies Record<string, Formatter>;

type FormatterKey = keyof typeof formatters;

function format(key: FormatterKey, value: string): string {
  return formatters[key](value);
}

The example assumes the key is already provided by a caller within the type. If the key comes from a URL, the network, or user input, it must be validated at the boundary and the original unknown-value error preserved; TypeScript types cannot validate runtime input.

Conditional engineering details

  • Lazy loading: Adopt only when loading cost and the actual rendering path support the benefit. It introduces waiting, failure, and first-use delay; preserve SSR, first-screen, and error behavior, and do not default to ssr: false. Confirm the benefit with real network/build-artifact evidence; do not claim success based on the mere presence of dynamic import.
  • Naming and guidance: When there is a recurring cost of finding where things go, provide an example of adding an entry, a short naming mapping, or an existing in-repo generator. Placeholders, READMEs, and scaffolding are not necessary conditions for pluginization.
  • Debugging capability: Prefer reusing existing logs, DevTools, or test interfaces. Add development-environment probes only when actual diagnosis requires it; do not expose a global store, user data, or a cache-clearing write entry point by default.
  • Stateful mechanisms: Login/permission changes must recompute the relevant intents; subscriptions, timers, resources, and asynchronous results must have a clear owner and cleanup; caches are isolated by actual user/tenant boundaries. Static mechanisms do not need these states added. For specific boundaries, see the stateful runtime reference.

Implementation and verification

  1. Freeze the scope of this round, stating which modification propagation is to be reduced and which behaviors are to be preserved; do not treat mere naming consistency or a new framework as the goal.
  2. Make a minimal, revertible variant migration, reusing existing keys, routes, persisted data, and error contracts; remove the old path only after confirming consumers no longer repeat the same decision.
  3. Run verification corresponding to the change: static table checks for valid/unknown keys and existing outputs; stateful mechanisms check updates, unmounting, repeated mounting, failures, and cross-account isolation; public UI behavior also requires real browser/render signals.

Verify propagation of added/removed entries with an isolated fixture or a read-only dependency graph; do not actually delete plugins in the user's workspace for "acceptance". Add necessary behavior tests only when the user asks for implementation and the change carries regression risk; explanations and read-only reviews do not generate test projects.

Search can only locate candidates: differing fields, presence of a switch, static imports, or missing placeholders cannot alone be judged a failure. Build/typecheck cannot replace acceptance of runtime cleanup, UI loading, or account switching. Write required verification that was not run as UNVERIFIED。

Deliver

Deliver only the mode the user requested: for explanations, give conclusions and necessary examples; for reviews, give evidence, impact, and the minimal fix; for design, give applicable boundaries, contracts, and verification; for implementation, give changes and actual results. Migration paths, directory trees, READMEs, and debug probes are provided only when the current change actually needs them, not to fill out a fixed set of artifacts.