Where do files live? What does each face do? Wiring?
architecture.md
How do I name the tool, design APIs, write the manifest, executor, ExecutionRuntime?
tool-design.md
How do I build Inspector / Render / Placeholder / Streaming / Intervention / Portal?
ui/
When to Use This Skill
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 packages/locales/src/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.
1---2name: builtin-tool3description: Use for LobeHub builtin agent tools: manifests, executors, runtimes, inspectors, renders, streaming and intervention.4---56# Builtin Tool Authoring Guide
78A builtin tool is a package the agent runtime can call. It ships **five faces**:
910| Face | Lives in | Audience |
11| -------------------- | -------------------------------------------------------------------------------------- | ------------------------------------- |
12| **Manifest + types** | `src/{manifest,types,systemRole}.ts` | The LLM (tool spec + system prompt) |
13| **ExecutionRuntime** | `src/ExecutionRuntime/` | Server / desktop / any runtime caller |
14| **Executor** | `src/client/executor/` | Frontend (wraps stores/services) |
15| **Client UI** | `src/client/{Inspector,Render,…}/` | Chat UI |
16| **Registry wiring** | `packages/builtin-tools/src/*.ts` + `src/store/tool/slices/builtin/executors/index.ts` | Framework |
1718---
1920## Read These First
2122| Question | Doc |
23| ------------------------------------------------------------------------------------ | --------------------------------------------- |
24| Where do files live? What does each face do? Wiring? | [architecture.md](references/architecture.md) |
25| How do I name the tool, design APIs, write the manifest, executor, ExecutionRuntime? | [tool-design.md](references/tool-design.md) |
26| How do I build Inspector / Render / Placeholder / Streaming / Intervention / Portal? | [ui/](references/ui/README.md) |
2728---
2930## When to Use This Skill
3132- Creating a new `packages/builtin-tool-<name>/` package
33- Adding a new API method to an existing builtin tool
34- Building or restyling any of the 6 client surfaces for a tool
35- Wiring a tool into the central registries
36- Debugging "tool not found / API not found / render not showing / placeholder stuck" errors
3738---
3940## Top-Level Design Principles
41421. **`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.
432. **ApiName is an `as const` object**, not a TS enum. It doubles as the runtime list `BaseExecutor` iterates over.
443. **Three result fields, three audiences:**
45 - `content: string` → the LLM reads it
46 - `state: Record<…>` → the UI's `pluginState`; **result-domain only**, never echo all params back
47 - `error: { type, message, body? }` → both LLM and UI; `type` is a stable code
484. **Split execution from frontend wiring.**
49 - `src/ExecutionRuntime/` — pure runtime, no React, no Zustand, accepts services via constructor. **The default place for new logic.**
50 - `src/client/executor/` — `BaseExecutor` subclass that calls `ExecutionRuntime` (or stores/services directly when frontend-only).
515. **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.
526. **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.
537. **i18n keys live in `packages/locales/src/default/plugin.ts`.** Inspector titles must come from `t('builtins.<identifier>.apiName.<api>')` so something renders while args stream.
5455---
5657## Package Layout (preferred, post-2026 convention)
5859```
60packages/builtin-tool-<name>/
61├── package.json
62└── src/
63 ├── index.ts # exports manifest + types + systemRole + Identifier (no React, no stores)
64 ├── manifest.ts # BuiltinToolManifest with JSON Schema for every API
65 ├── types.ts # ApiName const + Params/State interfaces per API
66 ├── systemRole.ts # System prompt teaching the model when/how to use the APIs
67 ├── ExecutionRuntime/ # ✅ Default home for runtime logic (server- or anywhere-callable)
68 │ └── index.ts
69 └── client/
70 ├── index.ts # Re-exports for the registries
71 ├── executor/ # ✅ Frontend executor — extends BaseExecutor, often delegates to ExecutionRuntime
72 │ └── index.ts
73 ├── Inspector/ # required — header chip per API
74 ├── Render/ # optional — rich result card
75 ├── Placeholder/ # optional — skeleton during streaming/execution
76 ├── Streaming/ # optional — live output renderer (e.g. RunCommand, WriteFile)
77 ├── Intervention/ # optional — approval / edit-before-run UI
78 ├── Portal/ # optional — full-screen detail view
79 └── components/ # shared subcomponents used by the surfaces above
80```
8182**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.
8384`package.json` exports map:
8586```json
87"exports": {
88 ".": "./src/index.ts",
89 "./client": "./src/client/index.ts",
90 "./executor": "./src/client/executor/index.ts",
91 "./executionRuntime": "./src/ExecutionRuntime/index.ts"
92}
93```
9495---
9697## Authoring Checklist
9899Before opening the PR:
100101- [ ] Identifier follows `lobe-<domain>` and is **stable** (lives in message history).
102- [ ] Every `<Name>ApiName` value has: a manifest `api[]` entry, an executor method, an Inspector, an i18n `apiName.*` key.
103- [ ] `Params` interfaces match the JSON Schema; `State` interfaces match what the executor returns and what the UI surfaces read.
104- [ ] System prompt disambiguates confusable APIs and points to batch variants.
105- [ ] Runtime logic lives in `ExecutionRuntime/`; the `client/executor/` only wires stores/services and delegates.
106- [ ] Executor returns `{ success, content, state, error? }` via a single `toResult()` funnel — `content` always non-empty (default to `error.message`).
107- [ ] Inspector handles `isArgumentsStreaming`, `isLoading`, `partialArgs`, missing `pluginState`.
108- [ ] Render returns `null` until it has data; only created for APIs with rich results.
109- [ ] Placeholder added if the API has a perceivable execution lag (search, list, crawl).
110- [ ] Streaming added for APIs that emit incremental output (run command, write file, code execution).
111- [ ] Intervention added if `humanIntervention` is set in the manifest.
112- [ ] All registry files updated (see [architecture.md → Registry wiring](references/architecture.md#registry-wiring)).
113- [ ] i18n keys in `packages/locales/src/default/plugin.ts` plus dev seeds in `en-US`/`zh-CN`.
114- [ ] `bunx vitest run --silent='passed-only' 'packages/builtin-tool-<name>'` passes.
115- [ ] `bun run type-check` passes.
116117---
118119## Reference Tools
120121Pick the closest neighbor and copy:
122123| If your tool is… | Read first |
124| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
125| Pure-compute, no UI state | `packages/builtin-tool-calculator/` — `ExecutionRuntime` reuses executor (mathjs/nerdamer work everywhere) |
126| CRUD over a domain entity | `packages/builtin-tool-task/` — full Inspector + Render set, batch variants |
127| Heavy UI (Inspector/Render/Placeholder/Portal) | `packages/builtin-tool-web-browsing/` — search-style result UI, Portal for detail view |
128| Desktop / filesystem with all surfaces (incl. Streaming + Intervention) | `packages/builtin-tool-local-system/` — `ExecutionRuntime` injects an `ILocalSystemService`, executor calls it |
129| Server-side pure (no client executor) | `packages/builtin-tool-web-browsing/` — only `ExecutionRuntime` is exported; the chat client doesn't run it |
130| Needs human approval before running | `packages/builtin-tool-local-system/src/client/Intervention/` — per-API approval components |
Run npx skillmds@latest add lobehub/builtin-tool in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Use for LobeHub builtin agent tools: manifests, executors, runtimes, inspectors, renders, streaming and intervention. It is listed under AI & ML on SkillMD.
This skill has not completed SkillMD's automated safety review yet. Capability flags: reads secrets. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
lobehub (@lobehub) published this skill. Their other Agent Skills are listed on their SkillMD profile.