name: tpmjs-tool-creator
description: Guide for creating official TPMJS tools using the blocks CLI. Use when a user wants to create a new tool for the TPMJS registry, add a tool to packages/tools/official/, implement an AI SDK v6 tool, define a block in blocks.yml, validate a tool with pnpm blocks run, or publish a tool to npm with the tpmjs keyword.
TPMJS Tool Creator
Create production-ready tools for the TPMJS registry using the blocks CLI. Tools are npm packages following the AI SDK v6 pattern, validated by blocks, and automatically synced to tpmjs.com.
Workflow
- Define the tool block in
packages/tools/official/blocks.yml - Create the tool package directory
- Implement the tool using AI SDK v6
tool()+jsonSchema() - Validate with
pnpm blocks run <tool-name> - Build and publish to npm
Step 1: Define in blocks.yml
Add to the blocks: section of packages/tools/official/blocks.yml:
blocks:
category.toolName:
type: utility
description: "LLM-friendly description of what the tool does"
path: "tool-directory-name"
domain_rules:
- id: rule_name
description: "What this implementation must do"
inputs:
- name: inputName
type: string
description: "Description for LLMs"
- name: optionalInput
type: number
optional: true
description: "Optional parameter"
outputs:
- name: result
type: ResultType
description: "What the tool returns"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
Category prefix (before the dot): research, web, data, documentation, engineering, security, statistics, ops, agent, sandbox, utilities, html, compliance, finance, legal, hr, marketing, cx, edu, sales.
For domain entities and quality measures, see references/domain.md.
Step 2: Create Package Directory
Create packages/tools/official/<tool-name>/:
<tool-name>/
├── package.json
├── tsconfig.json
├── tsup.config.ts
├── README.md
└── src/
└── index.ts
package.json:
{
"name": "@tpmjs/official-<tool-name>",
"version": "0.1.0",
"description": "Short description",
"type": "module",
"keywords": ["tpmjs", "<category>", "ai"],
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"files": ["dist"],
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist .turbo"
},
"devDependencies": {
"@tpmjs/tsconfig": "workspace:*",
"tsup": "^8.5.1",
"typescript": "^5.9.3"
},
"dependencies": {
"ai": "6.0.49"
},
"publishConfig": { "access": "public" },
"repository": {
"type": "git",
"url": "https://github.com/tpmjs/tpmjs.git",
"directory": "packages/tools/official/<tool-name>"
},
"homepage": "https://tpmjs.com",
"license": "MIT",
"tpmjs": {
"category": "<category>",
"frameworks": ["vercel-ai"],
"tools": [
{
"name": "toolName",
"description": "Clear description (20+ chars)."
}
]
}
}
tsconfig.json:
{
"extends": "@tpmjs/tsconfig/react-library.json",
"compilerOptions": { "outDir": "dist", "rootDir": "src" },
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"]
}
tsup.config.ts:
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
sourcemap: true,
target: 'es2022',
});
Step 3: Implement the Tool
Every tool follows this AI SDK v6 pattern in src/index.ts:
import { jsonSchema, tool } from 'ai';
interface MyToolInput {
param1: string;
param2?: number;
}
export interface MyToolResult {
data: string;
metadata: { processedAt: string };
}
export const myTool = tool({
description: 'Clear LLM-friendly description of what this tool does.',
parameters: jsonSchema<MyToolInput>({
type: 'object',
properties: {
param1: {
type: 'string',
description: 'What param1 is for',
},
param2: {
type: 'number',
description: 'Optional: what param2 is for',
},
},
required: ['param1'],
additionalProperties: false,
}),
execute: async (input): Promise<MyToolResult> => {
if (!input.param1) {
throw new Error('param1 is required and must be non-empty');
}
try {
const result = await processData(input.param1);
return {
data: result,
metadata: { processedAt: new Date().toISOString() },
};
} catch (error) {
throw new Error(
`Failed to process: ${error instanceof Error ? error.message : String(error)}`
);
}
},
});
export default myTool;
Hard rules:
- No stubs, TODOs, or placeholders — every tool must be fully working
- Single-shot: one call in, one structured result out
- Validate inputs before processing
- Try-catch with descriptive errors including context
additionalProperties: falseon jsonSchema- Description on every schema property
- Export as both named and default export
- Output interface must be exported
Multi-Tool Packages
For packages with multiple tools, add root-level files:
block.ts:
import { toolA, toolB } from './src/index.js';
export const block = { name: 'package-name', tools: { toolA, toolB } };
export default block;
index.ts (root):
export * from './src/index.js';
export { default } from './src/index.js';
Each tool gets its own entry in blocks.yml (same path) and in tpmjs.tools array.
Step 4: Validate
The blocks CLI domain validator requires an OpenAI API key. Source it from .env.local before running:
cd packages/tools/official
# Load the OpenAI API key for domain validation
source ../../../.env.local
export OPENAI_API_KEY
pnpm blocks run <tool-name> # Validate (schema → shape → domain)
pnpm blocks run <tool-name> --force # Force full validation (skip cache)
pnpm blocks run <tool-name> --json # JSON output for debugging
pnpm blocks run --all # Validate all tools
Common errors:
Tool "X" not found in exports→ Export name must match blocks.ymlRequired file not found→ Check package root has all required filesinvalid tpmjs field→ Category must be valid, tools array required
Step 5: Build and Publish
pnpm --filter=@tpmjs/official-<tool-name> build
cd packages/tools/official/<tool-name> && npm publish --access public
The tool syncs to tpmjs.com automatically via the changes feed (every 2 min) and keyword search (every 15 min). To trigger immediately:
source apps/web/.env.local
curl -X POST https://tpmjs.com/api/sync/keyword \
-H "Authorization: Bearer $CRON_SECRET"
README Template
Every tool needs a README:
# @tpmjs/official-<tool-name>
Short description.
## Installation
npm install @tpmjs/official-<tool-name>
## Usage
\`\`\`typescript
import { myTool } from '@tpmjs/official-<tool-name>';
const result = await myTool.execute({ param1: 'example' });
\`\`\`
## Parameters
| Name | Type | Required | Description |
|--------|--------|----------|--------------------|
| param1 | string | Yes | What param1 is for |
## Output
| Field | Type | Description |
|-------|--------|----------------------|
| data | string | The processed result |
## License
MIT