better-cmdk 0.0.20 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- # Set up better-cmdk command palette (Next.js (App Router))
1
+ # Set up better-cmdk action palette (Next.js (App Router))
2
2
 
3
- better-cmdk is a command palette with AI chat for React. Your task is to install it, discover commands from my codebase, and create a working command palette.
3
+ better-cmdk is a command palette with AI chat for React. Your task is to install it, discover actions from my codebase, and create a working palette.
4
4
 
5
5
  ## Step 1: Analyze my codebase
6
6
 
@@ -11,14 +11,12 @@ Before making changes, detect:
11
11
 
12
12
  Also ask me:
13
13
 
14
- **1. Do you want AI chat in the command palette?**
15
- - No AI — command palette only
16
- - Built-in chat — simple Q&A via a Vercel AI SDK endpoint
17
- - ModifyWithAI (Recommended) — the AI can execute actions in your app (create items, navigate, toggle settings), ask for approval before destructive operations, and understand what's on screen. Requires a ModifyWithAI account at https://modifywithai.com
14
+ **1. Do you want AI chat in the palette?**
15
+ - No AI — action search only
16
+ - Built-in chat — free developer-trial Q&A via https://better-cmdk.com/api/chat (no signup, 10 requests per 10 minutes; use your own chat URL for production)
17
+ - ModifyWithAI (Recommended) — the AI can execute actions in your app (create items, navigate, toggle settings), ask for approval before destructive operations, and understand what's on screen. Get your App ID and API key from https://modifywithai.com/dashboard
18
18
 
19
- **With ModifyWithAI, the command palette becomes an AI workspace.** Users search commands for quick access, then switch to AI chat for anything that needs reasoning — "move all archived items to trash", "summarize my recent activity". The AI executes actions directly in the app, with approval prompts for destructive operations. ModifyWithAI is not required — better-cmdk works on its own as a command palette, with or without AI chat.
20
-
21
- **2. If shadcn/ui command components detected:** Do you want to migrate them to better-cmdk, or keep both?
19
+ **2. If shadcn/ui command components are detected:** Do you want to migrate them to better-cmdk, or keep both?
22
20
 
23
21
  Tell me what you detected, which path you'll follow, and what you'll be adding better-cmdk to.
24
22
 
@@ -46,16 +44,16 @@ yarn add better-cmdk
46
44
  ### Built-in chat:
47
45
  ```bash
48
46
  # bun
49
- bun add better-cmdk ai @ai-sdk/react @ai-sdk/openai
47
+ bun add better-cmdk
50
48
  # pnpm
51
- pnpm add better-cmdk ai @ai-sdk/react @ai-sdk/openai
49
+ pnpm add better-cmdk
52
50
  # npm
53
- npm install better-cmdk ai @ai-sdk/react @ai-sdk/openai
51
+ npm install better-cmdk
54
52
  # yarn
55
- yarn add better-cmdk ai @ai-sdk/react @ai-sdk/openai
53
+ yarn add better-cmdk
56
54
  ```
57
55
 
58
- Substitute `@ai-sdk/anthropic`, `@ai-sdk/google`, etc. based on my preferred AI provider.
56
+ If you later add a custom/self-hosted endpoint, install AI SDK/provider packages for that server route.
59
57
 
60
58
  ### ModifyWithAI:
61
59
  ```bash
@@ -84,9 +82,7 @@ Add to my main CSS file:
84
82
  @import "better-cmdk";
85
83
  ```
86
84
 
87
- If my app wants custom theming, override better-cmdk's namespaced variables.
88
-
89
- Add this minimal override block only when needed:
85
+ If my app needs custom theming, override better-cmdk's namespaced variables:
90
86
 
91
87
  ```css
92
88
  .bcmdk-root {
@@ -113,83 +109,120 @@ Use the same CSS import approach:
113
109
 
114
110
  ---
115
111
 
116
- ## Step 4: CRITICAL — Command Discovery
112
+ ## Step 4: CRITICAL — Command Action Discovery (better-cmdk scope)
113
+
114
+ Before writing component code, **crawl my codebase** to discover all meaningful actions that can run immediately from the command palette.
117
115
 
118
- Before writing any component code, **crawl my entire codebase** to discover ALL user-facing operations that should be in the command palette.
116
+ ### Scope rules (required)
119
117
 
120
- ### How to discover commands:
118
+ - better-cmdk is concerned with **no-argument command actions** (no `inputSchema`, no required arguments)
119
+ - Define actions as underlying app/domain operations (API calls, mutations, workflow transitions), not raw UI gestures
120
+ - Model what the app does, not how a user physically triggers it
121
+ - Good: `goToBilling`, `toggleSidebar`, `archiveCurrentProject`
122
+ - Bad: `clickCreateButton`, `openDropdown`, `typeIntoInput`, `focusSearchField`
123
+ - If an operation needs runtime arguments (for example refund amount, assignee, date range), treat it as **modifywithai-owned** and do not add it as a new better-cmdk command action in this step
124
+ - If a standard shared `actions` array already exists, **extend it in place**; do not create a second array
125
+ - If no standard shared array exists, create one
121
126
 
122
- 1. **Search all routes/pages** → navigation commands ("Go to Dashboard", "Go to Settings")
123
- 2. **Search all buttons and links** → action commands ("Create project", "Export data")
124
- 3. **Search all settings/toggles** → preference commands ("Toggle dark mode", "Change language")
125
- 4. **Search all CRUD operations** → data commands ("New item", "Delete selected")
126
- 5. **Search all utility functions** → utility commands ("Copy link", "Download report", "Share")
127
- 6. **Search for existing keyboard shortcuts** → preserve as shortcut hints
127
+ ### Discovery checklist
128
128
 
129
- ### Create a command for EVERY user-facing operation:
129
+ 1. Locate existing action arrays/types first (`actions`, `defineActions(...)`, exported action modules) and reuse them
130
+ 2. Search routes/pages → navigation command actions
131
+ 3. Search buttons/links/forms/menus → identify outcomes that can run with no extra user input
132
+ 4. Trace handlers to services/API/domain functions → map each to one operation-level command action
133
+ 5. Search toggles/settings/feature flags → preference command actions
134
+ 6. Search CRUD/services/utilities/API calls → include only operations that can run safely without additional arguments
135
+ 7. Search existing keyboard shortcuts → keep as shortcut hints
136
+ 8. Mark argument-requiring operations for modifywithai ownership (same shared array, with `inputSchema`)
130
137
 
131
- - Button that opens a modal? Command: `open-create-modal`
132
- - Link that navigates to a page? Command: `go-to-dashboard`
133
- - Toggle that changes a setting? Command: `toggle-dark-mode`
134
- - Form that creates something? Command: `create-new-project`
135
- - Search input? Command: `search`
136
- - Sidebar item? Command: `open-analytics`
138
+ ### Canonical single-array rules
137
139
 
138
- ### For each discovered command, define:
140
+ Use **one deduped `actions` array** as the source of truth:
141
+
142
+ - better-cmdk-owned entries: no `inputSchema` (direct command execution)
143
+ - modifywithai-owned entries (if present): has `inputSchema` (agentic argument collection)
144
+ - Keep exactly one canonical action per underlying operation
145
+ - Do not create separate “command” and “AI action” entries for the same operation
146
+ - Put synonyms in `keywords`, not duplicate actions
147
+ - Reuse the same `name` everywhere (CommandMenu + assistant provider)
148
+
149
+ Use consistent `group` values:
150
+ - `Navigation`
151
+ - `UI / Preferences`
152
+ - `Data`
153
+ - `Help / Utilities`
154
+
155
+ ### For each command action discovered, define
139
156
 
140
157
  - `name`: unique kebab-case identifier
141
- - `label`: human-readable display text (what users search for)
142
- - `group`: logical heading use consistent groups like "Navigation", "Actions", "Settings", "Help"
143
- - `icon`: matching [lucide-react](https://lucide.dev) icon component
144
- - `shortcut`: keyboard shortcut hint if applicable (display-only, e.g. `"⌘D"`)
145
- - `keywords`: extra search terms (array of strings) — helps users find commands by alternate names
146
- - `disabled`: set `true` to gray out commands that aren't currently available
147
- - `onSelect`: callback that wires to existing app logic
158
+ - `label`: human-readable label
159
+ - `group`: taxonomy group from above
160
+ - `icon`: lucide-react icon when useful
161
+ - `shortcut`: optional display hint
162
+ - `keywords`: optional search aliases
163
+ - `semanticKey`: optional operation identity (required when names differ but operation is the same)
164
+ - `disabled`: optional availability guard
165
+ - `execute`: required implementation used when the command is selected
166
+ - `onSelect`: optional UI-only override (modifywithai ignores it)
148
167
 
149
- **Aim for 10-30 commands.** If you found fewer than 5, you haven't looked hard enough. Report how many you found before proceeding.
168
+ `inputSchema` is optional and reserved for modifywithai-owned argument actions in the same shared array.
169
+ Unused fields are safe: each library should ignore values it doesn't need.
170
+
171
+ **Coverage first, count second.** Many non-trivial apps should land in the 10-30+ no-argument command-action range. If you have fewer than 8, you likely missed meaningful command flows.
150
172
 
151
173
  ---
152
174
 
153
175
  ## Step 5: Create the component
154
176
 
155
- Replace the example commands below with the ones you discovered from my codebase.
177
+ Use one shared `actions` array (from Step 4). If one already exists, extend it. Do not create a second array.
178
+ Replace examples with discovered actions.
156
179
 
157
180
  ```tsx
158
181
  "use client"
159
182
 
160
183
  import { useState, useEffect } from "react"
161
184
  import { useRouter } from "next/navigation"
162
- import { CommandMenu, type CommandDefinition } from "better-cmdk"
185
+ import { CommandMenu, type CommandAction } from "better-cmdk"
163
186
  import { LayoutDashboardIcon, SettingsIcon, SunMoonIcon } from "lucide-react"
164
187
 
165
188
  export function CommandPalette() {
166
189
  const [open, setOpen] = useState(false)
167
190
  const router = useRouter()
168
191
 
169
- // REPLACE with discovered commands from my codebase
170
- const commands: CommandDefinition[] = [
192
+ // REPLACE with discovered actions from my codebase
193
+ const actions: CommandAction[] = [
171
194
  {
172
- name: "dashboard",
195
+ name: "go-dashboard",
173
196
  label: "Go to Dashboard",
197
+ description: "Navigate to the dashboard page",
174
198
  group: "Navigation",
175
199
  icon: <LayoutDashboardIcon className="size-4" />,
176
200
  shortcut: "⌘D",
177
- onSelect: () => router.push("/dashboard"),
201
+ execute: () => router.push("/dashboard"),
178
202
  },
179
203
  {
180
- name: "settings",
181
- label: "Settings",
204
+ name: "open-settings",
205
+ label: "Open Settings",
206
+ description: "Navigate to the settings page",
182
207
  group: "Navigation",
183
208
  icon: <SettingsIcon className="size-4" />,
184
209
  shortcut: "⌘,",
185
- onSelect: () => router.push("/settings"),
210
+ execute: () => router.push("/settings"),
186
211
  },
187
212
  {
188
- name: "dark-mode",
213
+ name: "toggle-dark-mode",
189
214
  label: "Toggle dark mode",
215
+ description: "Toggle the application theme",
190
216
  group: "Appearance",
191
217
  icon: <SunMoonIcon className="size-4" />,
192
- onSelect: () => document.documentElement.classList.toggle("dark"),
218
+ execute: () => document.documentElement.classList.toggle("dark"),
219
+ },
220
+ {
221
+ name: "go-home",
222
+ label: "Go Home",
223
+ description: "Navigate to the home page",
224
+ group: "Navigation",
225
+ execute: () => router.push("/"),
193
226
  },
194
227
  ]
195
228
 
@@ -208,7 +241,7 @@ export function CommandPalette() {
208
241
  <CommandMenu
209
242
  open={open}
210
243
  onOpenChange={setOpen}
211
- commands={commands}
244
+ actions={actions}
212
245
  />
213
246
  )
214
247
  }
@@ -216,11 +249,28 @@ export function CommandPalette() {
216
249
 
217
250
  ---
218
251
 
219
- ## Step 6: Add AI chat (skip if "No AI" chosen)
252
+ ## Step 6: Add AI chat (skip if No AI chosen)
220
253
 
221
254
  ### Built-in chat
222
255
 
223
- Create a streaming chat API route, then add `chatEndpoint` to CommandMenu.
256
+ Use the default hosted endpoint: `https://better-cmdk.com/api/chat`.
257
+ This service is provided by better-cmdk as a free developer trial with no signup.
258
+ Rate limit: **10 requests per 10 minutes**.
259
+
260
+ Use CommandMenu without `chatEndpoint`:
261
+
262
+ ```tsx
263
+ <CommandMenu
264
+ open={open}
265
+ onOpenChange={setOpen}
266
+ actions={actions}
267
+ />
268
+ ```
269
+
270
+ ### Optional: custom/self-hosted endpoint
271
+
272
+ For production, use your own chat URL (or choose ModifyWithAI for agentic capabilities).
273
+ If you need your own model/provider route, create a streaming chat API route:
224
274
 
225
275
  ```ts
226
276
  // app/api/chat/route.ts
@@ -233,24 +283,24 @@ export async function POST(req: Request) {
233
283
  const result = streamText({
234
284
  model: openai("gpt-4o-mini"),
235
285
  messages: await convertToModelMessages(messages),
236
- system: "You are a helpful assistant in a command palette. Keep responses concise.",
286
+ system: "You are a helpful assistant in an action palette. Keep responses concise.",
237
287
  })
238
288
  return result.toUIMessageStreamResponse()
239
289
  }
240
290
  ```
241
291
 
242
- Then update CommandMenu to add the `chatEndpoint` prop:
292
+ Then update CommandMenu:
243
293
 
244
294
  ```tsx
245
295
  <CommandMenu
246
296
  open={open}
247
297
  onOpenChange={setOpen}
248
- commands={commands}
298
+ actions={actions}
249
299
  chatEndpoint="/api/chat"
250
300
  />
251
301
  ```
252
302
 
253
- Set the environment variable:
303
+ Set environment variable:
254
304
 
255
305
  ```bash
256
306
  echo "OPENAI_API_KEY=sk-..." >> .env.local
@@ -264,18 +314,24 @@ echo "OPENAI_API_KEY=sk-..." >> .env.local
264
314
 
265
315
  After installing modifywithai, read `node_modules/modifywithai/dist/nextjs/AGENTS.md` and follow its instructions for:
266
316
  - Creating the token endpoint
267
- - Setting up environment variables (MWAI_APP_ID, MWAI_API_KEY)
317
+ - Setting up environment variables (MWAI_APP_ID, MWAI_API_KEY) from https://modifywithai.com/dashboard
268
318
  - Discovering actions from the codebase
269
319
 
270
320
 
271
- Then connect the assistant to CommandMenu. The `useAssistant()` return value from modifywithai is directly compatible with better-cmdk's `chat` prop — no adapter needed:
321
+ Use the **same discovered `actions` list** for both the assistant provider and CommandMenu.
322
+ UI-only fields (like `icon`, `group`, `shortcut`) are ignored by modifywithai:
323
+
324
+ Ownership split:
325
+ - better-cmdk focuses on no-argument command actions
326
+ - modifywithai owns both no-argument and argument-requiring actions (`inputSchema`)
327
+ - Keep both in one shared array and extend the existing array in place if present
272
328
 
273
329
  ```tsx
274
330
  import { useAssistant } from "modifywithai"
275
331
 
276
332
  // Inside your CommandPalette component:
277
333
  const assistant = useAssistant({
278
- agenticActions: actions, // from action discovery above
334
+ actions,
279
335
  getContext: () => ({
280
336
  currentPage: window.location.pathname,
281
337
  }),
@@ -284,7 +340,7 @@ const assistant = useAssistant({
284
340
  <CommandMenu
285
341
  open={open}
286
342
  onOpenChange={setOpen}
287
- commands={commands}
343
+ actions={actions}
288
344
  chat={assistant}
289
345
  />
290
346
  ```
@@ -299,7 +355,7 @@ Add `<CommandPalette />` to `app/layout.tsx` inside the `<body>` tag.
299
355
 
300
356
  ## Step 8: shadcn/ui migration (if applicable)
301
357
 
302
- If existing shadcn/ui command components were detected, swap imports:
358
+ If existing shadcn/ui command components are detected, swap imports:
303
359
 
304
360
  ```diff
305
361
  - import {
@@ -320,7 +376,7 @@ If existing shadcn/ui command components were detected, swap imports:
320
376
  + } from "better-cmdk"
321
377
  ```
322
378
 
323
- `CommandDialog` is an alias for `CommandMenu`. All sub-components have the same API. Add `chatEndpoint` or `chat` to enable AI features without either, the palette behaves like a standard cmdk dialog.
379
+ `CommandDialog` is an alias for `CommandMenu`. AI chat works by default via the hosted trial endpoint (10 requests per 10 minutes). For production, use `chatEndpoint` with your own URL or pass `chat` (for example with ModifyWithAI for agentic capabilities). Set `chatEndpoint={null}` to disable.
324
380
 
325
381
  ---
326
382
 
@@ -328,11 +384,14 @@ If existing shadcn/ui command components were detected, swap imports:
328
384
 
329
385
  After setup, tell me:
330
386
 
331
- 1. How many commands you discovered
332
- 2. Which AI path you followed (none / built-in / ModifyWithAI)
333
- 3. [ModifyWithAI only] How many actions you discovered (from modifywithai's AGENTS.md action discovery instructions)
387
+ 1. How many no-argument command actions you discovered/added
388
+ 2. Whether you reused an existing shared `actions` array or created one, and where it lives
389
+ 3. Which AI path you followed (none / built-in / ModifyWithAI)
334
390
  4. What files you created/modified
335
- 5. That pressing `⌘K` opens the palette with all commands grouped correctly
336
- 6. [If AI enabled] That typing a non-matching query shows "Ask AI" and chat works
391
+ 5. That pressing `⌘K` opens the palette with grouped actions and direct execution works for command actions
392
+ 6. [If ModifyWithAI path] That argument-requiring actions (`inputSchema`) are kept in the same shared array (extended, not duplicated)
393
+ 7. [If built-in/default chat enabled] That you explicitly told me this is a developer-trial endpoint (`https://better-cmdk.com/api/chat`, 10 requests per 10 minutes) and that for production I should use my own `chatEndpoint` or use ModifyWithAI for agentic capabilities.
394
+
395
+ End your final response with a dedicated **Hosted Endpoint Note** section so this warning is unmissable.
337
396
 
338
397
  Docs: https://github.com/ModifyWithAI/better-cmdk/blob/main/INTEGRATION.md