{"id":51825577,"url":"https://github.com/stevysmith/agentk","last_synced_at":"2026-07-22T09:02:57.497Z","repository":{"id":370196567,"uuid":"1181198211","full_name":"stevysmith/agentk","owner":"stevysmith","description":"A command palette for the agentic web — cmdk fork with WebMCP registration, auto-generated forms, and human-in-the-loop agent mode","archived":false,"fork":false,"pushed_at":"2026-07-08T14:32:29.000Z","size":719,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-08T16:10:06.969Z","etag":null,"topics":["ai-agents","cmdk","command-palette","model-context-protocol","react","webmcp"],"latest_commit_sha":null,"homepage":"https://agentk-ya5h.onrender.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stevysmith.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-13T21:21:19.000Z","updated_at":"2026-07-08T14:34:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/stevysmith/agentk","commit_stats":null,"previous_names":["stevysmith/agentk"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/stevysmith/agentk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevysmith%2Fagentk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevysmith%2Fagentk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevysmith%2Fagentk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevysmith%2Fagentk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stevysmith","download_url":"https://codeload.github.com/stevysmith/agentk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stevysmith%2Fagentk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35755761,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-22T02:00:06.236Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","cmdk","command-palette","model-context-protocol","react","webmcp"],"created_at":"2026-07-22T09:02:56.755Z","updated_at":"2026-07-22T09:02:57.485Z","avatar_url":"https://github.com/stevysmith.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# agentk\n\nA command palette for the agentic web. Extends [cmdk](https://github.com/pacocoursey/cmdk) with tool execution, auto-generated forms, WebMCP registration, and human-in-the-loop agent mode.\n\nDefine your tools once as JSON Schema. Users browse and execute them from a command palette. AI agents discover them via [WebMCP](https://chromestatus.com/feature/5261274379001856). Both share the same interface — human-in-the-loop by design, with an opt-in approval gate.\n\nOn-page agent experiences usually mean high fidelity at the cost of a bespoke integration to maintain. agentk collapses that trade: one tool catalog gives humans a palette and agents a WebMCP surface, so the on-page fidelity comes free with the UI you were building anyway.\n\n**[Live demo](https://agentk.stacktr.ee/)** · **[npm](https://www.npmjs.com/package/@stevysmith/agentk)** — running in production on the [Stacktree](https://stacktr.ee) dashboard, where the same catalog serves the ⌘K palette and in-browser agents.\n\n## Install\n\n```bash\nnpm install @stevysmith/agentk\n```\n\n## Use\n\n```tsx\nimport { Command } from '@stevysmith/agentk'\n\nconst tools = [\n  {\n    name: 'search',\n    label: 'Search Products',\n    description: 'Find products by keyword',\n    inputSchema: {\n      type: 'object',\n      properties: {\n        query: { type: 'string', description: 'Search query' },\n      },\n      required: ['query'],\n    },\n  },\n]\n\nasync function executeTool(name: string, params: Record\u003cstring, any\u003e) {\n  // your app logic\n}\n\nconst App = () =\u003e {\n  const [open, setOpen] = React.useState(false)\n\n  return (\n    \u003cCommand.Dialog\n      open={open}\n      onOpenChange={setOpen}\n      tools={tools}\n      onToolExecute={executeTool}\n      label=\"Command Menu\"\n    \u003e\n      \u003cCommand.Input placeholder=\"Type a command or search...\" /\u003e\n      \u003cCommand.List\u003e\n        \u003cCommand.Group heading=\"Tools\"\u003e\n          {tools.map((tool) =\u003e (\n            \u003cCommand.Tool key={tool.name} tool={tool} /\u003e\n          ))}\n        \u003c/Command.Group\u003e\n        \u003cCommand.Empty\u003eNo results found.\u003c/Command.Empty\u003e\n      \u003c/Command.List\u003e\n      \u003cCommand.ToolForm /\u003e\n      \u003cCommand.ToolResult /\u003e\n    \u003c/Command.Dialog\u003e\n  )\n}\n```\n\nWhen a user selects a tool, agentk transitions through a built-in lifecycle: **browse → form → executing → result**. Forms are generated automatically from `inputSchema` — `enum` fields render as dropdowns, `number` fields with `minimum`/`maximum` render as sliders, and `string` fields render as text inputs.\n\n### With agent mode\n\nAdd the `agent` prop and three more primitives to enable natural language intent → tool execution:\n\n```tsx\n\u003cCommand.Dialog\n  open={open}\n  onOpenChange={setOpen}\n  tools={tools}\n  onToolExecute={executeTool}\n  agent={{\n    provider: 'anthropic',\n    endpoint: '/api/agent',\n    requireApproval: true,\n  }}\n  label=\"Command Menu\"\n\u003e\n  \u003cCommand.Input placeholder=\"Type a command or search...\" /\u003e\n  \u003cCommand.List\u003e\n    \u003cCommand.Group heading=\"Tools\"\u003e\n      {tools.map((tool) =\u003e (\n        \u003cCommand.Tool key={tool.name} tool={tool} /\u003e\n      ))}\n    \u003c/Command.Group\u003e\n    \u003cCommand.Empty\u003eNo results found.\u003c/Command.Empty\u003e\n  \u003c/Command.List\u003e\n  \u003cCommand.AgentHint /\u003e\n  \u003cCommand.Approval /\u003e\n  \u003cCommand.ToolForm /\u003e\n  \u003cCommand.ToolResult /\u003e\n  \u003cCommand.ActivityFeed /\u003e\n\u003c/Command.Dialog\u003e\n```\n\nWhen the user types a query that doesn't match any tool, `AgentHint` appears prompting them to press Enter. The query is sent to the LLM, which returns a plan of tool calls. The user reviews and approves the plan in `Approval` before any tools execute.\n\n## Parts and styling\n\nAll parts forward props and refs to an appropriate element. Each part has a specific data-attribute that can be used for styling.\n\n### Command `[cmdk-root]`\n\nRoot component. Inherits the full [cmdk](https://github.com/pacocoursey/cmdk) API and adds the following props:\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `tools` | `AgentKToolDef[]` | Tool definitions to register in the palette |\n| `onToolExecute` | `(name, params) =\u003e Promise\u003cstring \\| Record\u003e` | Called when a tool is executed. Return a string for text display, an object for JSON. |\n| `onToolResult` | `(name, result) =\u003e void` | Called after successful execution |\n| `onToolError` | `(name, error) =\u003e void` | Called on execution failure |\n| `onModeChange` | `(mode) =\u003e void` | Called when mode changes |\n| `agent` | `AgentKAgentConfig` | LLM agent configuration (omit to disable) |\n| `onAgentPlan` | `(plan) =\u003e void` | Called when the LLM returns a plan |\n| `onAgentApprove` | `(plan) =\u003e void` | Called when user approves a plan |\n| `onAgentReject` | `(plan) =\u003e void` | Called when user rejects a plan |\n\nAll standard cmdk props (`value`, `onValueChange`, `filter`, `shouldFilter`, `loop`, `label`) are also supported.\n\nThe root element exposes `data-agentk-mode` reflecting the current state machine mode. Use it for mode-aware styling:\n\n```css\n/* Hide tool list when a form, result, or execution is active */\n[data-agentk-mode=\"form\"] [cmdk-list]      { display: none; }\n[data-agentk-mode=\"executing\"] [cmdk-list]  { display: none; }\n[data-agentk-mode=\"result\"] [cmdk-list]     { display: none; }\n[data-agentk-mode=\"planning\"] [cmdk-list]   { display: none; }\n[data-agentk-mode=\"approval\"] [cmdk-list]   { display: none; }\n```\n\nPossible values: `browse`, `form`, `executing`, `result`, `planning`, `approval`. Works alongside `data-agentk-entering` and `data-agentk-exiting` for transition animations.\n\n### Dialog `[cmdk-dialog]` `[cmdk-overlay]`\n\nComposes Radix UI's Dialog. Props are forwarded to [Command](#command-cmdk-root).\n\n```tsx\n\u003cCommand.Dialog open={open} onOpenChange={setOpen}\u003e\n  ...\n\u003c/Command.Dialog\u003e\n```\n\n### Input `[cmdk-input]`\n\nSearch input. All props forwarded to the underlying `input` element.\n\n```tsx\n\u003cCommand.Input placeholder=\"Search tools...\" /\u003e\n```\n\n### List `[cmdk-list]`\n\nContains Tool items and groups. Animate height using the `--cmdk-list-height` CSS variable.\n\n```css\n[cmdk-list] {\n  height: var(--cmdk-list-height);\n  transition: height 100ms ease;\n}\n```\n\n### Tool `[cmdk-item]` `[data-agentk-tool]`\n\nRenders a selectable tool item. Selecting it transitions to the form view.\n\n```tsx\n// Default rendering: icon + name + description\n\u003cCommand.Tool tool={tool} /\u003e\n\n// Custom rendering: children fully replace the default layout\n\u003cCommand.Tool tool={tool}\u003e\n  \u003cMyCustomIcon /\u003e\n  \u003cdiv\u003e\n    \u003cstrong\u003e{tool.label}\u003c/strong\u003e\n    \u003cp\u003e{tool.description}\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/Command.Tool\u003e\n```\n\nWhen children are omitted, the default layout renders `data-agentk-tool-icon`, `data-agentk-tool-name`, and `data-agentk-tool-description` elements for styling. When children are provided, only your children render.\n\nThe `tool` prop is an `AgentKToolDef`:\n\n```tsx\ntype AgentKToolDef = {\n  name: string\n  label?: string           // Falls back to humanized name\n  description?: string\n  inputSchema?: {          // JSON Schema for parameters\n    type: 'object'\n    properties: Record\u003cstring, {\n      type: string\n      description?: string\n      enum?: string[]      // → renders dropdown\n      minimum?: number     // → renders slider (with maximum)\n      maximum?: number\n      default?: any\n    }\u003e\n    required?: string[]\n  }\n  icon?: React.ReactNode\n  keywords?: string[]      // Aliases for fuzzy matching\n}\n```\n\n### ToolForm `[data-agentk-form]`\n\nAuto-generates a parameter form from the active tool's `inputSchema`. Renders when mode is `form`.\n\n```tsx\n// Default: auto-generated fields\n\u003cCommand.ToolForm /\u003e\n\n// Custom field renderer\n\u003cCommand.ToolForm\n  renderField={(name, schema, value, onChange) =\u003e (\n    \u003cMyCustomInput value={value} onChange={onChange} /\u003e\n  )}\n/\u003e\n\n// Custom action buttons (Cancel + Execute)\n\u003cCommand.ToolForm\n  renderActions={({ cancel, submit, canSubmit }) =\u003e (\n    \u003cdiv\u003e\n      \u003cbutton onClick={cancel}\u003eCancel\u003c/button\u003e\n      \u003cbutton onClick={submit} disabled={!canSubmit}\u003eRun it\u003c/button\u003e\n    \u003c/div\u003e\n  )}\n/\u003e\n```\n\nSchema type mapping:\n\n| Schema | Rendered as |\n|--------|-------------|\n| `type: 'string'` | Text input |\n| `type: 'string', enum: [...]` | Select dropdown |\n| `type: 'number', minimum, maximum` | Range slider |\n| `type: 'number'` | Number input |\n| `type: 'boolean'` | Checkbox |\n\n### ToolResult `[data-agentk-result]`\n\nDisplays the result after tool execution. Renders when mode is `result`.\n\nThe return value of `onToolExecute` controls what is displayed:\n\n```tsx\nonToolExecute={async (name, params) =\u003e {\n  const data = await myApi(name, params);\n  // String → rendered as text in \u003cspan data-agentk-result-data=\"\"\u003e\n  return `Found ${data.length} results`;\n  // Object → rendered as formatted JSON in \u003cpre data-agentk-result-data=\"\"\u003e\n  // return { count: data.length, items: data };\n}}\n```\n\n```tsx\n// Default display\n\u003cCommand.ToolResult /\u003e\n\n// Custom result renderer\n\u003cCommand.ToolResult\n  renderResult={(execution) =\u003e (\n    \u003cdiv\u003e\n      {execution.error\n        ? \u003cspan\u003eError: {execution.error}\u003c/span\u003e\n        : \u003cspan\u003eDone in {((Date.now() - execution.startedAt) / 1000).toFixed(1)}s\u003c/span\u003e\n      }\n    \u003c/div\u003e\n  )}\n/\u003e\n\n// Custom dismiss button\n\u003cCommand.ToolResult\n  renderDismiss={({ dismiss }) =\u003e (\n    \u003cbutton onClick={dismiss}\u003eGot it\u003c/button\u003e\n  )}\n/\u003e\n\n// Auto-dismiss successful results after 6s\n\u003cCommand.ToolResult autoDismissAfterMs={6000} /\u003e\n```\n\n`autoDismissAfterMs` only fires for successful results — errors stay visible\nuntil the user dismisses them manually. Combine with `onModeChange` if you need\nside effects (e.g. navigation) when the panel closes.\n\nThe `execution` object:\n\n```tsx\ntype ToolExecution = {\n  toolName: string\n  parameters: Record\u003cstring, any\u003e\n  result?: any\n  error?: string\n  startedAt: number\n}\n```\n\n### AgentHint `[data-agentk-agent-hint]`\n\nAppears when the search query doesn't match any tool but an agent is configured. Interactive — clicking, pressing Enter, or pressing Space triggers `sendIntent` with the current search query. Renders with `role=\"button\"` and `tabIndex={0}` for accessibility.\n\n```tsx\n// Default: \"Ask the agent\" with sparkle icon\n\u003cCommand.AgentHint /\u003e\n\n// Custom content\n\u003cCommand.AgentHint\u003e\n  \u003cspan\u003eLet AI handle this\u003c/span\u003e\n\u003c/Command.AgentHint\u003e\n```\n\nSet `data-agentk-hint` on `[cmdk-root]` is toggled automatically when the hint is visible, useful for styling the input border:\n\n```css\n[cmdk-root][data-agentk-hint] [cmdk-input] {\n  border-bottom-color: var(--accent);\n}\n```\n\n### Approval `[data-agentk-approval]`\n\nRenders the agent's plan for user review before execution. Shows each proposed tool call with parameters. The user can approve or reject.\n\n```tsx\n// Default display\n\u003cCommand.Approval /\u003e\n\n// Custom renderers\n\u003cCommand.Approval\n  renderSummary={(plan) =\u003e \u003cp\u003e{plan.summary}\u003c/p\u003e}\n  renderCall={(call, index) =\u003e (\n    \u003cdiv\u003e{call.toolName}({JSON.stringify(call.parameters)})\u003c/div\u003e\n  )}\n  renderActions={({ approve, reject }) =\u003e (\n    \u003cdiv\u003e\n      \u003cbutton onClick={reject}\u003eCancel\u003c/button\u003e\n      \u003cbutton onClick={approve}\u003eRun plan\u003c/button\u003e\n    \u003c/div\u003e\n  )}\n/\u003e\n```\n\n### ActivityFeed `[data-agentk-activity]`\n\nShows a timeline of agent activity: intent detection, planning, tool execution, results.\n\n```tsx\n\u003cCommand.ActivityFeed maxEntries={20} /\u003e\n```\n\n### IntentTrigger `[data-agentk-intent-trigger]`\n\nA `Command.Item` that triggers `sendIntent` when selected, instead of the default tool-selection behaviour. Renders identically to other items — same styling, same keyboard navigation.\n\n```tsx\n\u003cCommand.IntentTrigger query=\"summer programs in europe\"\u003e\n  Search Europe\n\u003c/Command.IntentTrigger\u003e\n```\n\nMust be rendered inside a `Command.List`. Style with `[data-agentk-intent-trigger]`.\n\n**Note:** Since `IntentTrigger` is a `Command.Item`, it counts as a matching item for filtering. If you want `AgentHint` to appear when the user types a custom query, place IntentTrigger items alongside other items so they get filtered out by cmdk's fuzzy matching. For agent-only search (no items), use `AgentHint` directly without IntentTrigger.\n\n### Empty `[cmdk-empty]`\n\nRenders when there are no results. Automatically hidden when `AgentHint` is visible.\n\n### Group `[cmdk-group]`\n\nGroups items with a heading. Same as cmdk.\n\n```tsx\n\u003cCommand.Group heading=\"Actions\"\u003e\n  \u003cCommand.Tool tool={tool} /\u003e\n\u003c/Command.Group\u003e\n```\n\n### Separator, Loading\n\nSame as cmdk. See [cmdk documentation](https://github.com/pacocoursey/cmdk).\n\n## Hooks\n\n### `useAgentK()`\n\nAccess agentk state from within the Command tree.\n\n```tsx\nfunction MyComponent() {\n  const ak = useAgentK()\n\n  // Read state\n  ak.state.mode        // 'browse' | 'form' | 'executing' | 'result' | 'planning' | 'approval'\n  ak.state.activeTool  // current tool or null\n  ak.state.parameters  // current form values\n  ak.state.execution   // current execution or null\n  ak.agentHintVisible  // true when agent hint is showing\n\n  // Actions\n  ak.selectTool(tool)\n  ak.setParameter('key', value)\n  ak.execute()\n  ak.reset()\n  ak.sendIntent('natural language query')\n  ak.approvePlan()\n  ak.rejectPlan()\n}\n```\n\n### `useWebMCPTools()`\n\nDiscover tools registered by other apps on the page via WebMCP.\n\n```tsx\nconst { tools, available, refresh, executeTool } = useWebMCPTools()\n// tools: AgentKToolDef[] — discovered tools\n// available: boolean — whether WebMCP API is present\n// refresh: () =\u003e void — re-scan for tools\n// executeTool: (name, params) =\u003e Promise\u003cany\u003e\n```\n\n### `useCommandState(state =\u003e state.field)`\n\nSame as cmdk. Access the underlying combobox state.\n\n## Agent configuration\n\nThe `agent` prop accepts:\n\n```tsx\ntype AgentKAgentConfig = {\n  provider: 'anthropic' | 'openai' | 'google' | 'custom'\n  apiKey?: string         // For development only — warns in browser\n  endpoint?: string       // Proxy URL for production\n  model?: string          // Defaults: claude-sonnet-4-20250514, gpt-4o, gemini-2.0-flash\n  systemPrompt?: string   // Override the built-in system prompt\n  requireApproval?: boolean  // Show Approval before executing (default: false)\n  maxCalls?: number       // Max tool calls per plan\n  providerFn?: AgentKProvider  // Custom provider function\n}\n```\n\nFor production, proxy through your own server using the `endpoint` prop instead of exposing API keys client-side:\n\n```tsx\nagent={{\n  provider: 'anthropic',\n  endpoint: '/api/agent',\n  requireApproval: true,\n}}\n```\n\n### Custom provider\n\n```tsx\nagent={{\n  provider: 'custom',\n  providerFn: async (prompt, tools, config) =\u003e {\n    const res = await fetch('/my-api', {\n      method: 'POST',\n      body: JSON.stringify({ prompt, tools }),\n    })\n    return res.json() // { calls: AgentKToolCall[], summary: string }\n  },\n}}\n```\n\n## WebMCP registration\n\nagentk tools use the same JSON Schema format as WebMCP. Register them so AI agents can discover your app. Note that Chrome 150 moved the API from `navigator.modelContext` to `document.modelContext`; feature-detect both:\n\n```tsx\nuseEffect(() =\u003e {\n  const mc = document.modelContext ?? navigator.modelContext\n  if (!mc) return\n\n  for (const tool of tools) {\n    mc.registerTool({\n      name: tool.name,\n      description: tool.description,\n      inputSchema: tool.inputSchema,\n      execute: async (params) =\u003e {\n        const result = await executeTool(tool.name, params)\n        return { content: [{ type: 'text', text: JSON.stringify(result) }] }\n      },\n    })\n  }\n\n  return () =\u003e {\n    for (const tool of tools) {\n      mc.unregisterTool(tool.name)\n    }\n  }\n}, [])\n```\n\nDefine once, use everywhere — the same tool definitions power the palette UI, the agent, and WebMCP discovery.\n\n## Recipes\n\n### Consumer search (agent-only, no tool list)\n\nFor customer-facing search where users type natural language and get results — no tool browsing needed:\n\n```tsx\n\u003cCommand.Dialog\n  open={open}\n  onOpenChange={setOpen}\n  tools={tools}\n  onToolExecute={handleExecute}\n  agent={{ provider: 'anthropic', endpoint: '/api/agent' }}\n\u003e\n  \u003cCommand.Input placeholder=\"What are you looking for?\" /\u003e\n  \u003cCommand.List\u003e\n    {/* No Command.Tool items — agent-only */}\n    \u003cCommand.AgentHint /\u003e\n    \u003cCommand.Empty\u003eType to search with AI\u003c/Command.Empty\u003e\n  \u003c/Command.List\u003e\n  \u003cCommand.ToolResult /\u003e\n\u003c/Command.Dialog\u003e\n```\n\nUse `data-agentk-mode` to hide the list during execution:\n\n```css\n[data-agentk-mode=\"executing\"] [cmdk-list] { display: none; }\n[data-agentk-mode=\"result\"] [cmdk-list]    { display: none; }\n```\n\nAdd suggested queries with `IntentTrigger`:\n\n```tsx\n\u003cCommand.List\u003e\n  \u003cCommand.Group heading=\"Suggestions\"\u003e\n    \u003cCommand.IntentTrigger query=\"popular items\"\u003ePopular items\u003c/Command.IntentTrigger\u003e\n    \u003cCommand.IntentTrigger query=\"deals under $50\"\u003eDeals under $50\u003c/Command.IntentTrigger\u003e\n  \u003c/Command.Group\u003e\n  \u003cCommand.AgentHint /\u003e\n\u003c/Command.List\u003e\n```\n\n## Data-attribute reference\n\nEvery part exposes data-attributes you can target from CSS without bundling\nstyles. The cmdk-prefixed attrs come from cmdk; everything `data-agentk-*` is\nintroduced by agentk.\n\n### Root and dialog\n\n| Selector | Where |\n|---|---|\n| `[cmdk-root]` | Top-level element (Command / Command.Dialog) |\n| `[cmdk-root][data-agentk-mode=\"\u003cmode\u003e\"]` | Reflects the current state machine mode (`browse`, `form`, `executing`, `result`, `planning`, `approval`) |\n| `[cmdk-root][data-agentk-hint]` | Present when `AgentHint` is showing |\n| `[cmdk-overlay]` | Dialog backdrop |\n| `[cmdk-dialog]` | Dialog surface |\n| `[cmdk-input]` | Search input |\n| `[cmdk-list]` | List wrapper (animatable via `--cmdk-list-height`) |\n| `[cmdk-group]`, `[cmdk-group-heading]` | Group + its heading |\n| `[cmdk-empty]` | Empty state |\n\n### Tool item\n\n| Selector | Where |\n|---|---|\n| `[cmdk-item][data-agentk-tool=\"\u003cname\u003e\"]` | The tool list item |\n| `[data-agentk-tool-icon]` | Default icon span (only when `tool.icon` is set) |\n| `[data-agentk-tool-name]` | Default label span |\n| `[data-agentk-tool-description]` | Default description span |\n| `[data-agentk-intent-trigger]` | A `Command.IntentTrigger` item |\n\n### ToolForm\n\n| Selector | Where |\n|---|---|\n| `[data-agentk-form]` | Form container |\n| `[data-agentk-form-invalid]` | Set on the form when validation has errors |\n| `[data-agentk-form-heading]` | Header row (icon + title + description) |\n| `[data-agentk-form-title]` | Form title |\n| `[data-agentk-form-description]` | Form description |\n| `[data-agentk-form-fields]` | Wrapper around the field list |\n| `[data-agentk-form-field]` | Wrapper around a single field |\n| `[data-agentk-form-field][data-agentk-field-error]` | Field whose value is invalid |\n| `[data-agentk-form-label]` | Default field label |\n| `[data-agentk-required]` | Required-field marker (default `*`) |\n| `[data-agentk-form-hint]` | Field description / hint |\n| `[data-agentk-field-error-message]` | Inline validation message |\n| `[data-agentk-form-actions]` | Cancel + submit row |\n| `[data-agentk-form-cancel]` | Cancel button |\n| `[data-agentk-form-submit]` | Submit button |\n\n### ToolResult\n\n| Selector | Where |\n|---|---|\n| `[data-agentk-result]` | Result container |\n| `[data-agentk-result][data-agentk-executing]` | Set during the executing phase |\n| `[data-agentk-result-loading]` | Spinner row during execution |\n| `[data-agentk-progress]` | \"Step N of M\" indicator during a chained plan |\n| `[data-agentk-result][data-agentk-success]` | Set when a successful result is shown |\n| `[data-agentk-result][data-agentk-error]` | Set when an error is shown |\n| `[data-agentk-result-heading]` | Result title row |\n| `[data-agentk-result-body]` | Result content wrapper |\n| `[data-agentk-result-data]` | The result value (string `\u003cspan\u003e` or JSON `\u003cpre\u003e`) |\n| `[data-agentk-result-error]` | The error message `\u003cpre\u003e` |\n| `[data-agentk-result-meta]` | Meta row (e.g. duration) |\n| `[data-agentk-result-dismiss]` | Default dismiss button |\n\n### AgentHint\n\n| Selector | Where |\n|---|---|\n| `[data-agentk-agent-hint]` | Hint container (clickable) |\n| `[data-agentk-agent-hint-icon]` | Default sparkle icon |\n| `[data-agentk-agent-hint-content]` | Label + query wrapper |\n| `[data-agentk-agent-hint-label]` | \"Ask the agent\" label |\n| `[data-agentk-agent-hint-query]` | The current search text in quotes |\n| `[data-agentk-agent-hint-kbd]` | Default `↵` kbd glyph |\n\n### Approval\n\n| Selector | Where |\n|---|---|\n| `[data-agentk-approval]` | Approval container |\n| `[data-agentk-approval-summary]` | Plan summary line |\n| `[data-agentk-approval-calls]` | List of planned tool calls |\n| `[data-agentk-approval-call]` | A single planned tool call |\n| `[data-agentk-approval-call-icon]` | Tool icon (only when set) |\n| `[data-agentk-approval-call-name]` | Tool name |\n| `[data-agentk-approval-call-params]` | Parameter chips wrapper |\n| `[data-agentk-approval-param]` | Single parameter chip |\n| `[data-agentk-approval-param-value]` | Stringified parameter value |\n| `[data-agentk-approval-actions]` | Reject + approve row |\n| `[data-agentk-approval-reject]` | Reject button |\n| `[data-agentk-approval-approve]` | Approve button |\n\n### Planning / spinner\n\n| Selector | Where |\n|---|---|\n| `[data-agentk-planning]` | Planning indicator container |\n| `[data-agentk-planning-text]` | \"Thinking…\" label |\n| `[data-agentk-spinner]` | The animated spinner element (also reused inside `[data-agentk-result-loading]`) |\n\n### ActivityFeed\n\n| Selector | Where |\n|---|---|\n| `[data-agentk-activity]` | Feed container |\n| `[data-agentk-activity][data-agentk-activity-expanded]` | Set when the feed is expanded |\n| `[data-agentk-activity-toggle]` | Expand/collapse button |\n| `[data-agentk-activity-status]` | Latest status text |\n| `[data-agentk-activity-chevron]` | Chevron icon (with `data-expanded` when open) |\n| `[data-agentk-activity-entry]` | A feed entry |\n| `[data-agentk-activity-entry][data-agentk-activity-type=\"\u003ctype\u003e\"]` | Entry type (`tool_start`, `tool_complete`, `tool_error`, etc.) |\n| `[data-agentk-activity-icon]` | Per-entry icon |\n| `[data-agentk-activity-message]` | Per-entry message |\n\n## FAQ\n\n**cmdk compatible?** Yes. agentk is a superset of cmdk. Existing cmdk code works unchanged — add tool props when you're ready.\n\n**Unstyled?** Yes. All components expose data-attributes for styling. No CSS is bundled.\n\n**Which LLM providers?** Anthropic, OpenAI, and Google (Gemini) are built in. Use `provider: 'custom'` with `providerFn` for anything else.\n\n**What is WebMCP?** A [browser API](https://developer.chrome.com/docs/ai/webmcp) (`document.modelContext`, formerly `navigator.modelContext`) for registering tools that AI agents can discover. Chrome has it in origin trial. agentk makes your app WebMCP-ready.\n\n**Do I need WebMCP to use agentk?** No. The command palette and tool execution work without it. WebMCP registration is opt-in.\n\n**Do I need an LLM to use agentk?** No. Without the `agent` prop, agentk is a command palette with tool forms and execution — no AI required.\n\n**Auto-generated forms?** Yes. `inputSchema` defines the form. `enum` → dropdown, `number` with `min/max` → slider, `string` → text input. Override with `renderField` for custom fields.\n\n**Human-in-the-loop?** Set `requireApproval: true` and render `\u003cCommand.Approval /\u003e`. The agent's plan is shown to the user before any tools execute.\n\n**React 18+ only?** Yes. Uses `useId` and `useSyncExternalStore`.\n\n**React server component?** No, it's a client component.\n\n## Acknowledgements\n\nBuilt on [cmdk](https://github.com/pacocoursey/cmdk) by [Paco Coursey](https://twitter.com/pacocoursey). Uses [Radix UI](https://www.radix-ui.com/) primitives.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevysmith%2Fagentk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstevysmith%2Fagentk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstevysmith%2Fagentk/lists"}