agentsclimarketplace

Buy vs build right tool

Skill stdin/buy-vs-build/plugins/buy-vs-build/skills/buy-vs-build-right-tool

Stop AI coding agents from adding dependency and build ownership without a decision note.

Install
npx -y skills add stdin/buy-vs-build --skill buy-vs-build-right-tool

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

One thing to look at

  • 3 stars3 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

Use when choosing between options at the same ownership rung — a transport, API style, data store, job/async mechanism, integration pattern, or cache — and you want the one that fits the requirement's real shape (directionality, volume, latency, consistency, failure mode) rather than the most powerful, popular, or familiar default.

SKILL.md

7.1 KB, as published. Nobody here has run it

Buy vs Build — Pick the Right Option, Not the Obvious One

The buy-vs-build ladder picks an ownership level; it does not pick which option at that level. When several options satisfy the rung, the flashy, popular, or familiar one is often wrong: it adds capability you never use and ownership you keep paying for. This is the reference for that second decision.

Reach for this when the choice is non-obvious or a one-way door. When it is obvious, just decide and keep moving.

Find the distinguishing requirement first

Name the one property that actually separates the options, then pick the option that fits it — nothing more:

  • Directionality — one-way vs bidirectional; push vs pull; who initiates.
  • Volume & latency — events per second, payload size, tail-latency budget.
  • Consistency & ordering — transactional vs eventual; exactly-once vs at-least-once; ordered vs not.
  • Durability & delivery — can a message be dropped, or must it survive a crash and retry?
  • Failure mode — reconnect, backpressure, replay, idempotency, partial failure.
  • Operational fit — what your runtime, proxies, clients, and infra already support and can debug.

If two options tie on the distinguishing requirement, pick the one with less long-term ownership (less infra to run, less API surface, easier to remove).

Decision tables

The middle column is the common over-reach. The "Fitting default" is the lower-ownership option that usually wins. Use the heavier option only when its extra capability is actually exercised — the right-hand column says when.

Realtime / transport (server↔client)

You needCommon over-reachFitting defaultUse the heavier option when
Server→client stream: feeds, notifications, progress, token streamingWebSocketsServer-Sent Events (plain HTTP, auto-reconnect)The client must also send a steady high-rate stream back — true full-duplex.
Bidirectional, low-latency: chat, collaboration, multiplayer, live cursorsPolling / SSEWebSockets(this is the case the heavier option is for)
Occasional client→server nudgesWebSocketsfetch / HTTP requestYou measured per-request overhead and it actually hurts.
Browser ↔ browser media/data, low latencyWebSockets relayWebRTCPeer-to-peer NAT traversal and media are the requirement.

Service ↔ service integration

You needCommon over-reachFitting defaultUse the heavier option when
"Tell me when X happens" across servicesPolling loopWebhook / eventThe receiver can't accept inbound calls; then poll on a sane interval.
Internal RPC between two services you ownGraphQLREST or gRPCMany clients with widely divergent field needs — GraphQL's flexibility is used.
One public API, many client shapesMany bespoke REST endpointsGraphQLClients are few and stable — REST is less to own.
High-throughput, typed, streaming RPCREST + JSONgRPCCross-language contracts and streaming are real needs.

Data storage

You needCommon over-reachFitting defaultUse the heavier option when
Relational data with joins and transactionsNoSQL "for scale"SQL / relationalA document/wide-column access pattern genuinely dominates and you've outgrown SQL.
A bit of JSON next to relational rowsA second NoSQL storeJSONB / native JSON columnDocument volume and query needs justify a dedicated store.
Cache / ephemeral counters / rate limitsRedis cluster (day one)In-process cache / DB rowMulti-instance shared state or persistence across restarts is required.
Full-text searchElasticsearchDB full-text (tsvector, FTS5)Relevance tuning, facets, and scale exceed the DB's built-in search.
Time-ordered eventsNew time-series databaseIndexed table by timestampIngest rate / retention math actually needs a TSDB.

Jobs, scheduling & async

You needCommon over-reachFitting defaultUse the heavier option when
One periodic jobQueue + broker + worker fleetCron / scheduled taskWork must fan out, retry with backoff, or survive partial failure.
Decouple a slow step from the requestKafkaDB-backed queue / managed queue (SQS)Event volume, replay, and multiple consumers justify a log.
Multi-step workflow with retries & stateHand-rolled state machine + cronDurable workflow engine (Temporal, Step Functions)The flow is one or two steps — keep it inline.
Event stream many consumers replayDatabase table polled by allLog / streaming platform (Kafka)One consumer, low volume — a queue or table is enough.

Identity, time, money, text

You needCommon over-reachFitting defaultUse the heavier option when
Login / authHand-rolled OAuth/session cryptoPlatform auth / mature providerNever hand-roll trust-boundary crypto; this is reuse-always.
Unique IDsuuid dependencycrypto.randomUUID() / DB defaultYou need sortable/k-ordered IDs (ULID) — then a tiny lib.
Dates & time mathCustom date arithmeticIntl / Temporal / stdlibHeavy tz/recurrence rules — a maintained lib beats DIY.
MoneyFloatsInteger minor units / decimal type(floats are simply the wrong tool here)
Simple string worklodash/left-pad-style importString.prototype / built-insThe operation is genuinely non-trivial (Unicode segmentation, etc.).

The trap, named

The over-reach almost always justifies itself with a hypothetical: "for scale," "we might need it later," "it's the industry standard." If the distinguishing requirement isn't present today, the extra capability is pure ownership cost — infra to run, an API to learn, a thing to debug at 3am, a one-way door to walk back through. Defer it until the requirement is real (do-nothing is rung 1 for a reason).

Write it down

Record a non-obvious choice so the next person sees the tradeoff (this note is often the most valuable artifact — it makes the decision reviewable):

Decision: use native-platform: Server-Sent Events. Tradeoff: one-way HTTP stream with auto-reconnect, no socket infra to run. Rejected: WebSockets because the feed is server→client only and full-duplex is unused. Revisit if the client needs to push a high-rate stream back.

Name the distinguishing requirement, and say why the more powerful or more popular option was rejected. For a one-way door, add an exit plan. Capture it durably with $buy-vs-build-adr, and surface it again later with node scripts/revisit.js. For the full ladder and classification, see $buy-vs-build.

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.