create-client-tool — Claude Code skill: what it does, how to install
Scaffolds an AtlasTool for web apps using useAtlasChat. It generates TypeBox parameter validation, handles in-browser execution, and connects tools to the chat hook.
npx skills add cognitedata/builder-skills --skill create-client-tool -a claude-codeWhat create-client-tool does
This skill creates an AtlasTool definition so an Atlas agent can trigger browser-side tasks, such as updating state or plotting charts. It writes schemas using @sinclair/typebox for static typing and runtime checks. Each generated tool returns an output string to the agent and an optional details object for UI components.
The skill inspects existing source files. It locates the useAtlasChat hook call and registers the new tool in its tools array. When tools run, the UI receives data through message.toolCalls for custom rendering.
Without vendored src/atlas-agent/ files and @sinclair/typebox in the project, the generated code fails to compile. For EOS sidebar tooling, the skill instructions direct you to integrate-fusion-agent instead.
What it helps with
- scaffold an
AtlasTooldefinition with TypeBox schemas - wire browser-side tools into the
useAtlasChatconfiguration - return structured UI payloads via
message.toolCalls - provide text summaries back to the Atlas agent
Example prompts for the agent
- Create a client tool named export_report to download reports in CSV format
- Scaffold an AtlasTool filter_table to update UI filter parameters
- Add a client tool navigate_to_asset to redirect the user to a chosen asset
How to install create-client-tool
1Skills CLI (Vercel)
npx skills add cognitedata/builder-skills --skill create-client-tool -a claude-code2Manually: put the files in place
~/.claude/skills/create-client-tool/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/create-client-tool/
1Skills CLI (Vercel)
npx skills add cognitedata/builder-skills --skill create-client-tool -a codex2Manually: put the files in place
.agents/skills/create-client-tool/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add cognitedata/builder-skills --skill create-client-tool -a cursor2Manually: put the files in place
.cursor/skills/create-client-tool/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install cognitedata/builder-skills create-client-tool2Manually: put the files in place
.github/skills/create-client-tool/SKILL.md1Skills CLI (Vercel)
npx skills add cognitedata/builder-skills --skill create-client-tool -a gemini-cli2Platform CLI
gemini skills install https://github.com/cognitedata/builder-skills --path skills/create-client-toolManually: put the files in place
.devin/skills/create-client-tool/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add cognitedata/builder-skills --skill create-client-tool -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about create-client-tool
How to install create-client-tool in Claude Code?
Run npx skills add cognitedata/builder-skills --skill create-client-tool -a claude-code.
What does create-client-tool do?
It builds an AtlasTool with TypeBox validation schemas, browser-side execute handlers, and integrates it into the useAtlasChat call.
What dependencies are required for create-client-tool?
The project requires @sinclair/typebox and the vendored src/atlas-agent/ directory, set up during the integrate-atlas-chat step.
Source text
SKILL.md · Apache-2.0
---
name: create-client-tool
description: "Scaffolds an AtlasTool for an already-approved in-app useAtlasChat UI. For EOS sidebar tools, use integrate-fusion-agent (createAgentAction) instead. Triggers: AtlasTool, useAtlasChat tool, in-app atlas client tool."
allowed-tools: Read, Glob, Grep, Edit, Write
metadata:
argument-hint: "[tool-name] [brief description of what it does]"
---
# Create a Client Tool
Scaffold an `AtlasTool` named **$ARGUMENTS**. If the app has no approved in-app `useAtlasChat`, implement a Fusion **action** via **`integrate-fusion-agent`** instead.
**Prerequisite:** vendored `src/atlas-agent/` and `@sinclair/typebox` from `integrate-atlas-chat`.
## Background
Client tools let the Atlas Agent invoke browser-side logic — charts, local state, UI panels, navigation. The agent decides when to call; the app executes and returns a result.
1. Agent responds with a `clientTool` action
2. TypeBox validates the arguments
3. `execute()` runs in the browser and returns `{ output, details }`
4. `output` (string) is sent back to the agent
5. `details` is available on `message.toolCalls` for the UI to render
---
## Step 1 — Understand the codebase
Before writing anything, read:
- The file where `useAtlasChat` is called (often `src/App.tsx` or a chat hook) to find where `tools` is passed — imports are typically from `./atlas-agent/react` after **`integrate-atlas-chat`**
- Any existing tool definitions to match the file/naming conventions
---
## Step 2 — Define the tool
Use `Type` from `@sinclair/typebox` for the parameters schema (compile-time types + runtime validation).
```ts
import { Type } from "@sinclair/typebox";
import type { AtlasTool } from "./atlas-agent/types";
export const myTool: AtlasTool = {
name: "my_tool", // snake_case — this is what the agent uses to invoke it
description:
"One sentence describing what this tool does and when the agent should call it.",
parameters: Type.Object({
exampleParam: Type.String({ description: "What this param is for" }),
optionalNum: Type.Optional(Type.Number({ description: "..." })),
}),
execute: async (args) => {
return {
output: "Plain text summary sent back to the agent",
details: {
// Any structured data you want available in the UI via message.toolCalls
},
};
},
};
```
Adjust the `./atlas-agent/...` path if the tool file is not directly under `src/` next to the `atlas-agent` folder (for example `../atlas-agent/types` from `src/tools/`).
### TypeBox quick reference
| Schema | Usage |
|---|---|
| `Type.String()` | string |
| `Type.Number()` | number |
| `Type.Boolean()` | boolean |
| `Type.Literal("foo")` | exact value |
| `Type.Union([Type.Literal("a"), Type.Literal("b")])` | enum |
| `Type.Array(Type.String())` | string[] |
| `Type.Object({ ... })` | object |
| `Type.Optional(...)` | mark any field optional |
Always add a `description` on the tool and on each parameter — the agent uses those strings.
---
## Step 3 — Wire into useAtlasChat
Find the `useAtlasChat` call and add the tool to the `tools` array:
```ts
const { messages, send, ... } = useAtlasChat({
client: isLoading ? null : sdk,
agentExternalId: AGENT_EXTERNAL_ID,
tools: [myTool], // add here
});
```
---
## Step 4 — Render tool results (if needed)
If the tool returns structured `details`, render them in the message list.
`message.toolCalls` is a `ToolCall[]` — one entry per tool call (client-side and server-side) in call order.
```tsx
{msg.toolCalls?.map((tc, i) => (
// tc.name — tool name
// tc.output — the string sent back to the agent
// tc.details — your structured data (cast to your known shape)
<MyToolOutput key={i} data={tc.details as MyToolDetails} />
))}
```
© cognitedata · Apache-2.0 · cognitedata/builder-skills