
Create Client Tool
Scaffold a browser-executed AtlasTool with TypeBox schema, execute(), and useAtlasChat wiring so your Atlas agent can call client-side actions.
Install
npx skills add https://github.com/cognitedata/builder-skills --skill create-client-toolWhat is this skill?
- MUST-use skill for any new AtlasTool—blocks hand-written schemas and manual useAtlasChat wiring
- Generates TypeBox schema, AJV validation path, execute(), and registration in the Atlas chat hook
- Covers browser-side tools: charts, local state, navigation, API calls from the client
- Hard prerequisite: integrate-atlas-chat with vendored src/atlas-agent and TypeBox/AJV deps
Adoption & trust: 1k installs on skills.sh; 4 GitHub stars; 3/3 security scanners passed (skills.sh audits); trending (+100% hot-view momentum).
Recommended Skills
Journey fit
Build is where you extend the in-app agent with new callable tools after the chat integration exists. Agent-tooling is the precise shelf for AtlasTool definitions, validation, and hook wiring—not backend APIs or generic frontend pages.
Common Questions / FAQ
Is Create Client Tool safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Create Client Tool
# Create a Client Tool Scaffold a new `AtlasTool` named **$ARGUMENTS** and wire it into the app. ## Prerequisite **`integrate-atlas-chat`** must already be complete: the app should vend the atlas-agent sources under `src/atlas-agent/` (including `react.ts`) and have `@sinclair/typebox`, `ajv`, and `ajv-formats` installed as in that skill. ## Background Client tools let the Atlas Agent invoke logic that runs in the browser — rendering charts, querying local state, showing UI panels, triggering navigation, etc. The agent decides when to call the tool; the app executes it and returns a result. The flow is: 1. Agent responds with a `clientTool` action 2. The library validates the arguments against the TypeBox schema 3. `execute()` runs in the browser and returns `{ output, details }` 4. `output` (string) is sent back to the agent as the tool result 5. `details` (any shape) 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 Create the tool as a typed constant. Use `Type` from `@sinclair/typebox` to define the parameters schema — this gives both compile-time types and runtime validation (same stack as the vendored atlas-agent from **`integrate-atlas-chat`**). ```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) => { // args is fully typed from the schema above // Do the work here — call APIs, update state, render UI, etc. 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` to each field — the agent uses these to understand what to pass. --- ## 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,