Builtin Tool Authoring Guide
SkillAI & modelsGuides your agent through creating and debugging LobeChat-style builtin agent tool packages.
Use Builtin Tool Authoring Guide in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add Builtin Tool Authoring Guide and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the Builtin Tool Authoring Guide skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
About this skill
Use for LobeHub builtin agent tools: manifests, executors, runtimes, inspectors, renders, streaming and intervention.
What this skill tells your AI
The instructions your AI receives, as published by lobehub/lobehub in .agents/skills/builtin-tool/SKILL.md and read by ahel’s review.
A builtin tool is a package the agent runtime can call. It ships five faces:
| Face | Lives in | Audience |
|---|---|---|
| Manifest + types | src/{manifest,types,systemRole}.ts | The LLM (tool spec + system prompt) |
| ExecutionRuntime | src/ExecutionRuntime/ | Server / desktop / any runtime caller |
| Executor | src/client/executor/ | Frontend (wraps stores/services) |
| Client UI | src/client/{Inspector,Render,…}/ | Chat UI |
| Registry wiring | packages/builtin-tools/src/*.ts + src/store/tool/slices/builtin/executors/index.ts | Framework |
Read These First
| Question | Doc |
|---|---|
| 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 legacy aliases kept alongside the new name (see the// Legacy aliasesentries inpackages/builtin-tool-local-system/src/client/Inspector/index.ts, kept afterlistLocalFiles/searchLocalFileswere renamed tolistFiles/searchFiles). Get it right the first time.- ApiName is an
as constobject, not a TS enum. It doubles as the runtime listBaseExecutoriterates over. - Three result fields, three audiences:
content: string→ the LLM reads itstate: Record<…>→ the UI'spluginState; result-domain only, never echo all params backerror: { type, message, body? }→ both LLM and UI;typeis 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/—BaseExecutorsubclass that callsExecutionRuntime(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 tocreateStyles + tokenonly when you genuinely need runtime values. Use@lobehub/uicomponents, not raw antd. - i18n keys live in
packages/locales/src/default/plugin.ts. Inspector titles must come fromt('builtins.<identifier>.apiName.<api>')so something renders while args stream. - A failed long-running call should be continuable, not just inspectable. Example: when
callSubAgentstops halfway, the user says "keep going". So the fix was an optionalsubAgentIdoncallSubAgentthat appends a new instruction to the same sub-agent thread — not a new "look up that run" API the model has to remember to call before retrying from scratch. Add a new API only when a user would ask for it on its own.
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-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.
package.json exports map:
"exports": {
".": "./src/index.ts",
"./client": "./src/client/index.ts",
"./executor": "./src/client/executor/index.ts",
"./executionRuntime": "./src/ExecutionRuntime/index.ts"
}
Authoring Checklist
Before opening the PR:
- Identifier follows
lobe-<domain>and is stable (lives in message history). - Every
<Name>ApiNamevalue has: a manifestapi[]entry, an executor method, an Inspector, an i18napiName.*key. -
Paramsinterfaces match the JSON Schema;Stateinterfaces match what the executor returns and what the UI surfaces read. - System prompt disambiguates confusable APIs and points to batch variants.
- Runtime logic lives in
ExecutionRuntime/; theclient/executor/only wires stores/services and delegates. - Executor returns
{ success, content, state, error? }via a singletoResult()funnel —contentalways non-empty (default toerror.message). - Inspector handles
isArgumentsStreaming,isLoading,partialArgs, missingpluginState. - Render returns
nulluntil it has data; only created for APIs with rich results. - Placeholder added if the API has a perceivable execution lag (search, list, crawl).
- Streaming added for APIs that emit incremental output (run command, write file, code execution).
- Intervention added if
humanInterventionis set in the manifest. - All registry files updated (see architecture.md → Registry wiring).
- i18n keys in
packages/locales/src/default/plugin.tsplus dev seeds inen-US/zh-CN. -
bunx vitest run --silent='passed-only' 'packages/builtin-tool-<name>'passes. -
bun run type-checkpasses.
Reference Tools
Pick the closest neighbor and copy:
| If your tool is… | Read first |
|---|---|
| Pure-compute, no UI state | packages/builtin-tool-calculator/ — ExecutionRuntime reuses executor (mathjs/nerdamer work everywhere) |
| CRUD over a domain entity | packages/builtin-tool-task/ — full Inspector + Render set, batch variants |
| Heavy UI (Inspector/Render/Placeholder/Portal) | packages/builtin-tool-web-browsing/ — search-style result UI, Portal for detail view |
| Desktop / filesystem with all surfaces (incl. Streaming + Intervention) | packages/builtin-tool-local-system/ — ExecutionRuntime injects an ILocalSystemService, executor calls it |
| Server-side pure (no client executor) | packages/builtin-tool-web-browsing/ — only ExecutionRuntime is exported; the chat client doesn't run it |
| Needs human approval before running | packages/builtin-tool-local-system/src/client/Intervention/ — per-API approval components |
Advanced
- Item type
- skill
- Key
builtin-tool-lobehub- Source
- github.com/lobehub/lobehub
Related picks
Skill · mattpocock
The pick for TypeScripttypescript-pro
Skill · jeffallan
The pick for TypeScriptnodejs-backend-patterns
Skill · wshobson
The pick for Noderun-node-tests
Skill · hiroro-work
The pick for Nodereact-component-performance
Skill · davila7
The pick for Reactreact-doctor
Skill · millionco
The pick for React