Build LobeHub builtin tool packages. Use when adding agent-callable tools,
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Creating a new packages/builtin-tool-<name>/ package
Adding a new API method to an existing builtin tool
Building or restyling any of the 6 client surfaces for a tool
Wiring a tool into the central registries
Debugging "tool not found / API not found / render not showing / placeholder stuck" errors
Top-Level Design Principles
lobe-<domain> identifier is permanent. It's stored in message history. Renames need @deprecated aliases (see packages/builtin-tools/src/inspectors.ts:88-89). Get it right the first time.
ApiName is an as const object, not a TS enum. It doubles as the runtime list BaseExecutor iterates over.
Three result fields, three audiences:
content: string → the LLM reads it
state: Record<…> → the UI's pluginState; result-domain only, never echo all params back
error: { type, message, body? } → both LLM and UI; type is a stable code
Split execution from frontend wiring.
src/ExecutionRuntime/ — pure runtime, no React, no Zustand, accepts services via constructor. The default place for new logic.
src/client/executor/ — BaseExecutor subclass that calls ExecutionRuntime (or stores/services directly when frontend-only).
UI defaults to "do nothing". Inspector is required (the header strip). Render/Placeholder/Streaming/Intervention/Portal are added only when there's something specific to show — empty registries are fine.
Style with createStaticStyles + cssVar.* (zero-runtime). Fall back to createStyles + token only when you genuinely need runtime values. Use @lobehub/ui components, not raw antd.
i18n keys live in src/locales/default/plugin.ts. Inspector titles must come from t('builtins.<identifier>.apiName.<api>') so something renders while args stream.
Package Layout (preferred, post-2026 convention)
packages/builtin-tool-<name>/
├── package.json
└── src/
├── index.ts # exports manifest + types + systemRole + Identifier (no React, no stores)
├── manifest.ts # BuiltinToolManifest with JSON Schema for every API
├── types.ts # ApiName const + Params/State interfaces per API
├── systemRole.ts # System prompt teaching the model when/how to use the APIs
├── ExecutionRuntime/ # ✅ Default home for runtime logic (server- or anywhere-callable)
│ └── index.ts
└── client/
├── index.ts # Re-exports for the registries
├── executor/ # ✅ Frontend executor — extends BaseExecutor, often delegates to ExecutionRuntime
│ └── index.ts
├── Inspector/ # required — header chip per API
├── Render/ # optional — rich result card
├── Placeholder/ # optional — skeleton during streaming/execution
├── Streaming/ # optional — live output renderer (e.g. RunCommand, WriteFile)
├── Intervention/ # optional — approval / edit-before-run UI
├── Portal/ # optional — full-screen detail view
└── components/ # shared subcomponents used by the surfaces above
Older packages (builtin-tool-task, builtin-tool-calculator, etc.) still have src/executor/ as a sibling of src/client/. That's grandfathered; don't relocate without a deliberate refactor. New packages and new APIs added to existing packages should follow the layout above.