---
title: Authoring Tools
description: Author tested source files and publish them as shadcn registry items
---

Author tools as real TypeScript files that you can import, type-check, and test.
In this repository, canonical implementations live in `packages/registry/src/tools/<id>/`.
The app consumes installed copies through normal local imports.

## Server and renderer

Use the AI SDK's `tool()` helper for the server implementation:

```ts
import { tool } from "ai";
import { z } from "zod";

export const wordCount = tool({
  description: "Count words in text",
  inputSchema: z.object({ text: z.string() }),
  execute: ({ text }) => ({
    words: text.trim() ? text.trim().split(/\s+/).length : 0,
  }),
});
```

The renderer exports a named React component. Use the source tool's inferred
input/output types and the shared `ToolPartFromTool` helper, keeping runtime imports of
server code out of the client bundle. See the existing word-count source for
loading, result, and error states.

## Item metadata

Declare standard shadcn files and dependencies in `packages/registry/registry.ts`.
ChatJS metadata describes only registration and environment requirements:

```json
{
  "contractVersion": 1,
  "kind": "tool",
  "id": "word-count",
  "toolExport": "wordCount",
  "rendererExport": "WordCountRenderer",
  "envRequirements": []
}
```

The same metadata is emitted as `meta.chatjs` in the registry item and as an
installed `tools/chatjs/word-count/chatjs.json` descriptor. Each item targets
`tool.ts`, `renderer.tsx`, and `chatjs.json` under `~/tools/chatjs/<id>/`.
Shared helpers use standard `registryDependencies`. npm packages use
`dependencies` or `devDependencies`.

For credentials, declare environment alternatives in the typed item metadata:

```ts
const envRequirements = [{ options: [["FIRECRAWL_API_KEY"]] }];
```

Every outer requirement must be satisfied. Within one requirement, `options`
contains alternatives, and each alternative lists variables needed together.
The build serializes this data into the descriptor. The installed app's
`check-env` command reads it without evaluating remote source. The old
`toolEnvVars` source parser and registry authoring-type npm exports are removed.

## Build and verify

```bash
bun run --cwd packages/registry test:types
bun run --cwd packages/registry test:unit
bun run --cwd packages/registry build
```

The small build script emits `registry.json`, then pinned `shadcn@4.21.0 build`
reads the actual sources and generates `dist/r/*.json`. Do not hand-maintain JSON
source strings. Publish those generated files from your registry endpoint.

Install the built item into an independent ChatJS app and type-check it. Source
tests validate execution logic, while installation tests catch missing files,
dependencies, incorrect targets, and renderer registration problems.

```bash
npx @chat-js/cli@latest add https://example.com/r/word-count.json
```

Third-party registries use the same standard item format and descriptor contract.
There is no runtime plugin loader or general compatibility solver. The installed
app's TypeScript checks validate composition against its actual local contracts.

## Related

- [Tool Registry](./overview) for ownership and namespaces
- [Adding Tools](./install) for installation and sync
- [Tool Part](../cookbook/tool-part) for rendering tool results
