Skip to main content
ClaudeWave
Skill78.6k repo starsupdated today

builtin-tool

The builtin-tool skill guides development of callable agent packages in LobeHub that expose tools across five layers: LLM-facing manifests and types, server-side execution runtimes, frontend executors wrapping stores, chat UI components (Inspector/Render/Placeholder/Streaming/Intervention/Portal), and registry wiring. Use this when creating new tool packages, adding API methods, building client surfaces, wiring tools into registries, or debugging tool visibility and execution issues.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/lobehub/lobehub /tmp/builtin-tool && cp -r /tmp/builtin-tool/.agents/skills/builtin-tool ~/.claude/skills/builtin-tool
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Builtin Tool Authoring Guide

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](references/architecture.md) |
| How do I name the tool, design APIs, write the manifest, executor, ExecutionRuntime? | [tool-design.md](references/tool-design.md)   |
| How do I build Inspector / Render / Placeholder / Streaming / Intervention / Portal? | [ui/](references/ui/README.md)                |

---

## 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

1. **`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.
2. **ApiName is an `as const` object**, not a TS enum. It doubles as the runtime list `BaseExecutor` iterates over.
3. **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
4. **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).
5. **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.
6. **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.
7. **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.

`package.json` exports map:

```json
"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>ApiName` value has: a manifest `api[]` entry, an executor method, an Inspector, an i18n `apiName.*` key.
- [ ] `Params` interfaces match the JSON Schema; `State` interfaces match what the