agentsclimarketplace

Abstract the provider

Skill jcdavis131/cursor-agent-skills/skills/abstract-the-provider

42 agent-discipline skills for Cursor, distilled by watching an autonomous terminal coding agent (Claude Code + Fable 5). Includes the derivation method.

Install
npx -y skills add jcdavis131/cursor-agent-skills --skill abstract-the-provider

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 26 days oldThe repository was created 26 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

When swapping one third-party dependency for another (Shopify→Medusa, Stripe→Paddle, OpenAI→Anthropic), prefer a provider-agnostic abstraction with the new provider as the default, rather than a hard swap. Use when the user asks to replace a vendor, when choosing an open-source alternative to a paid service, or when a feature could plausibly need a second provider later.

SKILL.md

4.4 KB, as published. Nobody here has run it

Abstract The Provider

A hard swap locks you to the new vendor. An agnostic layer with a default lets you swap again without a rewrite. The default means you ship now; the abstraction means you're not stuck.

When to abstract

  • The user asks to replace a vendor ("is there an open-source alternative to Shopify?").
  • The feature could plausibly need a second provider later (commerce, payments, email, auth, LLM, search).
  • You're choosing between a paid and an open-source option and the user prefers optionality.
  • The integration is non-trivial — a hard swap would mean a future hard swap too.

Don't abstract when:

  • The integration is one function call — abstraction is more code than the call.
  • The provider is genuinely irreplaceable (a specific data source only one vendor offers).
  • YAGNI is clear — one provider, no realistic second, and the abstraction adds complexity.

The shape

<feature>/provider.ts        # the interface (methods, types)
<feature>/providers/
  medusa.ts                  # default implementation
  shopify.ts                 # the old one, kept or removed
<feature>/config.ts          # picks the provider, default = "medusa"

Rules:

  • The interface is the stable surface. Callers depend on the interface, never on a provider.
  • A default is chosen, not a wiring puzzle. COMMERCE_PROVIDER=medusa (default) — ship now, no config required.
  • Each provider implements the same interface. No provider-specific methods leak into callers.
  • The old provider is either kept (for migration) or removed (if fully replaced) — don't leave it half-wired.

Example (commerce)

// commerce/provider.ts
export interface CommerceProvider {
  listProducts(): Promise<Product[]>;
  createCheckout(items: CartItem[]): Promise<CheckoutUrl>;
}

// commerce/providers/medusa.ts  (default)
export const medusa: CommerceProvider = { /* ... */ };

// commerce/config.ts
const name = process.env.COMMERCE_PROVIDER ?? "medusa";
export const commerce = providers[name];

Callers import commerce from config.ts — they never import medusa directly.

Why this beats a hard swap

  • Ship now, swap later. The default gets you working today; a future swap is a new provider file + a config flip, not a rewrite.
  • Open-source by default, paid as escape hatch. You can default to Medusa and add Shopify later if a paid feature is needed.
  • Test surface is the interface. Mock the interface in tests; don't mock each provider.
  • The "swap" decision is reversible. A hard swap is a one-way door; an abstraction is a two-way door.

Anti-patterns

  • Hard swap "to keep it simple". Simpler now; the next swap is a full rewrite.
  • Provider methods leak into callers. if (provider === "medusa") ... in a page — the abstraction is broken.
  • No default. Forces config to ship; the default is what makes it shippable today.
  • Abstracting a one-call integration. An interface for getUnixTime() is more code than the call.
  • Keeping the old provider half-wired. Pick: migrate-then-remove, or keep-both-supported. Don't leave it dangling.

Pair with

  • dependency-hygiene — the new provider's pins should be an opt-in extra if it's heavy.
  • match-conventions — mirror the existing provider's interface shape if one already exists.
  • validate-gate — the interface is the test surface; mock it, don't mock the provider.

Include the go-live handoff for the default provider

After the abstraction lands, the default provider still has to be stood up. Hand off the provider-specific go-live steps so the user can take it to production without re-discovering them:

"For Medusa go-live you'll need to: stand up a Medusa backend (npx create-medusa-app@latest), create …"

The abstraction is the wiring; the go-live is the runtime. The handoff closes the loop — without it, the user has a clean interface and no running provider. This belongs in the readiness-report's "next steps" or a follow-up message, not buried in a commit message.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.