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 treeconflictsWith— 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 (
navbarandfooterare 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 conflictsWithhit- 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.