Blog / capability-contracts

2026-09-05

Capability contracts: provides, requires, conflictsWith

Why BotKelp components declare contracts so purchase_scaffold can refuse broken trees before writing files.

A folder of templates is not a generator. A generator needs a way to say “this block needs that block” and “these two cannot share a tree.”

BotKelp components are not just files. In the engine they declare a contract:

  • provides — capabilities this block contributes (authentication, database, styling, payments, …)
  • requires — other component IDs or capabilities that must already be in the tree
  • conflictsWith — combinations that should fail before a single path is written

This is how purchase_scaffold can reject a list instead of emitting a project that cannot boot.

Why agents need this

If you tell a model “add Supabase and Firebase auth,” it will often add both. You then have two session stories and one layout. A contract can make that an error at resolve time.

Same for CSS foundations. Several UI blocks require Tailwind. Generating navbar without tailwind should not produce a mystery class string in a CSS-less app.

nextjs-base is the root

The catalog’s base is a minimal Next.js App Router project: package.json, tsconfig, root layout, home page. Other components assume those paths exist because generation applies actions in topological order:

1. Resolve IDs + transitive requires 2. Sort so bases land first 3. Run actions: create_file, json_merge, ast_inject

ast_inject is the sharp tool — for example wrapping the root layout in a SupabaseProvider rather than asking the model to splice JSX.

What you can inspect today

Human pages: /components/supabase-client, /components/tailwind, /components/shadcn-ui, etc. Machine list: /catalog.json.

When you evaluate a component, look for:

  • version (v1.0.0, v2.0.0)
  • declared dependencies (Tailwind, Supabase client, …)
  • whether the page says it is auto-wired or must be imported by hand (navbar and footer are explicit about that)

Search by capability, not by folklore

get_help (free) returns the whole catalog as TSV with provides, requires and conflictsWith per id, so an agent can pick by capability (“authentication”) without guessing. Then call purchase_scaffold.

Failure should be loud

Useful errors:

  • unknown ID
  • cycle in requires
  • conflictsWith hit
  • more than 12 IDs
  • catalog hash mismatch

A quiet partial tree is worse than a refused call.

Try a contract-shaped generate

components: ["nextjs-base", "tailwind", "shadcn-ui", "supabase-client"]

That list is a stack, not a prompt. Install: /install.

More