From 013b98a53e387b09cc7b3c4d4fb094157c0f8945 Mon Sep 17 00:00:00 2001
From: Ajax Davis
Date: Mon, 1 Dec 2025 05:37:28 +1000
Subject: [PATCH] refactor: rename envVars to env and remove example field from
TPMJS spec
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Rename TpmjsEnvVarSchema to TpmjsEnvSchema
- Rename envVars field to env throughout codebase
- Remove example field from TpmjsMinimalSchema (no longer required)
- Update all documentation (spec page, publish page, HOW_TO_PUBLISH_A_TOOL.md)
- Update example tool package.json
- Simplify minimal tier requirements to only category and description
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude
---
HOW_TO_PUBLISH_A_TOOL.md | 16 ++--
apps/web/src/app/publish/page.tsx | 8 +-
apps/web/src/app/spec/page.tsx | 97 +++++++++-------------
packages/tools/createBlogPost/package.json | 1 -
packages/types/src/tpmjs.ts | 9 +-
5 files changed, 48 insertions(+), 83 deletions(-)
diff --git a/HOW_TO_PUBLISH_A_TOOL.md b/HOW_TO_PUBLISH_A_TOOL.md
index d7ae0bb..9a7b913 100644
--- a/HOW_TO_PUBLISH_A_TOOL.md
+++ b/HOW_TO_PUBLISH_A_TOOL.md
@@ -49,8 +49,7 @@ The bare minimum to get listed:
{
"tpmjs": {
"category": "text-analysis",
- "description": "A concise description of what your tool does",
- "example": "const result = await myTool({ input: 'hello' });"
+ "description": "A concise description of what your tool does"
}
}
```
@@ -58,7 +57,6 @@ The bare minimum to get listed:
**Required fields:**
- `category` - One of: `text-analysis`, `code-generation`, `data-processing`, `image-generation`, `audio-processing`, `search`, `integration`, `other`
- `description` - Clear description of what the tool does (1-3 sentences)
-- `example` - Simple code example showing how to use the tool
#### Tier 2: Basic (Recommended)
@@ -69,7 +67,6 @@ Add parameter and return type information:
"tpmjs": {
"category": "text-analysis",
"description": "Analyzes sentiment in text and returns a score",
- "example": "const result = await analyzeSentiment({ text: 'I love this!' });",
"parameters": [
{
"name": "text",
@@ -102,7 +99,6 @@ Complete metadata for maximum visibility:
"tpmjs": {
"category": "text-analysis",
"description": "Advanced sentiment analysis with emotion detection",
- "example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
"parameters": [
{
"name": "text",
@@ -129,7 +125,7 @@ Complete metadata for maximum visibility:
"type": "SentimentResult",
"description": "Object with score, label, and optional emotions array"
},
- "envVars": [
+ "env": [
{
"name": "SENTIMENT_API_KEY",
"description": "API key for sentiment analysis service",
@@ -266,7 +262,6 @@ Here's the complete `package.json` from the published example:
"tpmjs": {
"category": "text-analysis",
"description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
- "example": "const post = await createBlogPost({ title: 'My First Post', author: 'John Doe', content: 'Hello World!', tags: ['intro', 'blog'] });",
"parameters": [
{
"name": "title",
@@ -340,7 +335,6 @@ Here's the complete `package.json` from the published example:
|-------|------|-------------|
| `category` | string | Tool category (see categories below) |
| `description` | string | Clear description (1-3 sentences) |
-| `example` | string | Code example showing usage |
### Optional Fields (Tier 2 - Basic)
@@ -353,7 +347,7 @@ Here's the complete `package.json` from the published example:
| Field | Type | Description |
|-------|------|-------------|
-| `envVars` | array | Required environment variables |
+| `env` | array | Required environment variables |
| `frameworks` | array | Compatible frameworks |
| `links` | object | Related URLs |
| `tags` | array | Additional tags |
@@ -378,7 +372,7 @@ Choose one of these for the `category` field:
If your tool requires environment variables:
```json
-"envVars": [
+"env": [
{
"name": "OPENAI_API_KEY",
"description": "API key for OpenAI services",
@@ -426,7 +420,7 @@ Or manually check the structure matches the examples above.
**Tool not appearing after 15 minutes?**
- Check that you added `"tpmjs-tool"` to keywords
-- Verify your `tpmjs` field has required fields (category, description, example)
+- Verify your `tpmjs` field has required fields (category, description)
- Check the NPM package is public: `npm view yourpackage`
**Tool showing as "minimal" tier?**
diff --git a/apps/web/src/app/publish/page.tsx b/apps/web/src/app/publish/page.tsx
index 9cc7e85..882b98c 100644
--- a/apps/web/src/app/publish/page.tsx
+++ b/apps/web/src/app/publish/page.tsx
@@ -96,8 +96,7 @@ export default function PublishPage(): React.ReactElement {
code={`{
"tpmjs": {
"category": "text-analysis",
- "description": "A concise description of what your tool does",
- "example": "const result = await myTool({ input: 'hello' });"
+ "description": "A concise description of what your tool does"
}
}`}
/>
@@ -120,7 +119,6 @@ export default function PublishPage(): React.ReactElement {
"tpmjs": {
"category": "text-analysis",
"description": "Analyzes sentiment in text",
- "example": "const result = await analyzeSentiment({ text: 'I love this!' });",
"parameters": [
{
"name": "text",
@@ -162,10 +160,9 @@ export default function PublishPage(): React.ReactElement {
"tpmjs": {
"category": "text-analysis",
"description": "Advanced sentiment analysis with emotion detection",
- "example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
"parameters": [...],
"returns": {...},
- "envVars": [
+ "env": [
{
"name": "SENTIMENT_API_KEY",
"description": "API key for sentiment analysis service",
@@ -290,7 +287,6 @@ npm publish --access public
"tpmjs": {
"category": "text-analysis",
"description": "Creates structured blog posts with frontmatter and SEO metadata",
- "example": "const post = await createBlogPost({ title: 'My Post', author: 'John', content: 'Hello' });",
"parameters": [
{
"name": "title",
diff --git a/apps/web/src/app/spec/page.tsx b/apps/web/src/app/spec/page.tsx
index 988adc5..8d4d0ef 100644
--- a/apps/web/src/app/spec/page.tsx
+++ b/apps/web/src/app/spec/page.tsx
@@ -1,9 +1,9 @@
+import { TPMJS_CATEGORIES } from '@tpmjs/types/tpmjs';
import { Badge } from '@tpmjs/ui/Badge/Badge';
import { Button } from '@tpmjs/ui/Button/Button';
import { Card, CardContent, CardHeader, CardTitle } from '@tpmjs/ui/Card/Card';
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
import { Container } from '@tpmjs/ui/Container/Container';
-import { TPMJS_CATEGORIES } from '@tpmjs/types/tpmjs';
import Link from 'next/link';
import { AppHeader } from '~/components/AppHeader';
@@ -49,8 +49,8 @@ export default function SpecPage(): React.ReactElement {
specification for describing tool capabilities
- Quality Scoring - Algorithmic
- ranking based on documentation completeness and community adoption
+ Quality Scoring - Algorithmic ranking
+ based on documentation completeness and community adoption
AI Agent Integration - Structured
@@ -71,9 +71,11 @@ export default function SpecPage(): React.ReactElement {
- Add the tpmjs-tool keyword
- and a tpmjs metadata field
- to your package.json
+ Add the{' '}
+ tpmjs-tool{' '}
+ keyword and a{' '}
+ tpmjs metadata
+ field to your package.json
@@ -110,9 +112,10 @@ export default function SpecPage(): React.ReactElement {
The Specification
- The TPMJS specification defines a tpmjs field
- in package.json with three tiers of metadata. Higher tiers receive better visibility
- and quality scores.
+ The TPMJS specification defines a{' '}
+ tpmjs field in
+ package.json with three tiers of metadata. Higher tiers receive better visibility and
+ quality scores.
{/* Tier 1: Minimal */}
@@ -151,16 +154,6 @@ export default function SpecPage(): React.ReactElement {
appears in search results and tool listings.
-
-
-
- example *
-
-
- Code example showing basic usage. Minimum 10 characters. Helps developers
- understand how to use your tool.
-
-
@@ -170,8 +163,7 @@ export default function SpecPage(): React.ReactElement {
code={`{
"tpmjs": {
"category": "text-analysis",
- "description": "Analyzes sentiment in text and returns positive/negative/neutral classification",
- "example": "const result = await analyzeSentiment({ text: 'I love this!' });"
+ "description": "Analyzes sentiment in text and returns positive/negative/neutral classification"
}
}`}
/>
@@ -246,7 +238,6 @@ export default function SpecPage(): React.ReactElement {
"tpmjs": {
"category": "text-analysis",
"description": "Analyzes sentiment in text",
- "example": "const result = await analyzeSentiment({ text: 'I love this!' });",
"parameters": [
{
"name": "text",
@@ -289,7 +280,7 @@ export default function SpecPage(): React.ReactElement {
- envVars
+ env
Array of environment variables required by the tool. Each variable has:
@@ -297,11 +288,11 @@ export default function SpecPage(): React.ReactElement {
-
name - Environment variable name
- (e.g., "OPENAI_API_KEY")
+ (e.g., "OPENAI_API_KEY")
-
-
description - What the variable is
- used for
+ description - What the variable
+ is used for
-
required - Boolean (defaults to
@@ -322,13 +313,17 @@ export default function SpecPage(): React.ReactElement {
Array of compatible AI frameworks. Supported values:
- {['vercel-ai', 'langchain', 'llamaindex', 'haystack', 'semantic-kernel'].map(
- (fw) => (
-
- {fw}
-
- )
- )}
+ {[
+ 'vercel-ai',
+ 'langchain',
+ 'llamaindex',
+ 'haystack',
+ 'semantic-kernel',
+ ].map((fw) => (
+
+ {fw}
+
+ ))}
@@ -417,10 +412,9 @@ export default function SpecPage(): React.ReactElement {
"tpmjs": {
"category": "text-analysis",
"description": "Advanced sentiment analysis with emotion detection",
- "example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
"parameters": [...],
"returns": {...},
- "envVars": [
+ "env": [
{
"name": "SENTIMENT_API_KEY",
"description": "API key for sentiment analysis service",
@@ -499,21 +493,6 @@ export default function SpecPage(): React.ReactElement {
Tool description (20-500 chars) |
-
-
- example
- |
- string |
-
-
- Minimal
-
- |
-
- Yes
- |
- Usage example code (min 10 chars) |
-
parameters
@@ -542,7 +521,7 @@ export default function SpecPage(): React.ReactElement {
|
- envVars
+ env
|
array |
@@ -708,7 +687,7 @@ export default function SpecPage(): React.ReactElement {
- Monitors NPM's real-time changes feed every 2 minutes
+ Monitors NPM's real-time changes feed every 2 minutes
Real-time
@@ -722,8 +701,9 @@ export default function SpecPage(): React.ReactElement {
- Searches for tpmjs-tool keyword
- every 15 minutes
+ Searches for{' '}
+ tpmjs-tool{' '}
+ keyword every 15 minutes
Every 15 min
@@ -778,11 +758,7 @@ export default function SpecPage(): React.ReactElement {
Description must be 20-500 characters
- Example too short: Example must be
- at least 10 characters
-
-
- Invalid envVar: Each environment
+ Invalid env: Each environment
variable must have a name and description
@@ -809,7 +785,8 @@ export default function SpecPage(): React.ReactElement {
1️⃣
- Add tpmjs-tool keyword
+ Add tpmjs-tool{' '}
+ keyword
diff --git a/packages/tools/createBlogPost/package.json b/packages/tools/createBlogPost/package.json
index b347894..0714f28 100644
--- a/packages/tools/createBlogPost/package.json
+++ b/packages/tools/createBlogPost/package.json
@@ -35,7 +35,6 @@
"tpmjs": {
"category": "text-analysis",
"description": "Creates structured blog posts with customizable frontmatter, content sections, and SEO metadata. Supports multiple output formats including Markdown and MDX.",
- "example": "const post = await createBlogPost({ title: 'My First Post', author: 'John Doe', content: 'Hello World!', tags: ['intro', 'blog'] });",
"parameters": [
{
"name": "title",
diff --git a/packages/types/src/tpmjs.ts b/packages/types/src/tpmjs.ts
index 57d25b0..7c5d182 100644
--- a/packages/types/src/tpmjs.ts
+++ b/packages/types/src/tpmjs.ts
@@ -46,14 +46,14 @@ export type TpmjsReturns = z.infer;
/**
* Environment variable schema
*/
-export const TpmjsEnvVarSchema = z.object({
+export const TpmjsEnvSchema = z.object({
name: z.string().min(1),
description: z.string().min(1),
required: z.boolean().default(true),
default: z.string().optional(),
});
-export type TpmjsEnvVar = z.infer;
+export type TpmjsEnv = z.infer;
/**
* External links schema
@@ -87,7 +87,6 @@ export const TpmjsMinimalSchema = z.object({
message: `Category must be one of: ${TPMJS_CATEGORIES.join(', ')}`,
}),
description: z.string().min(20, 'Description must be at least 20 characters').max(500),
- example: z.string().min(10, 'Example must be at least 10 characters'),
});
export type TpmjsMinimal = z.infer;
@@ -99,7 +98,7 @@ export type TpmjsMinimal = z.infer;
export const TpmjsRichSchema = TpmjsMinimalSchema.extend({
parameters: z.array(TpmjsParameterSchema).optional(),
returns: TpmjsReturnsSchema.optional(),
- envVars: z.array(TpmjsEnvVarSchema).optional(),
+ env: z.array(TpmjsEnvSchema).optional(),
frameworks: z
.array(z.enum(['vercel-ai', 'langchain', 'llamaindex', 'haystack', 'semantic-kernel']))
.optional(),
@@ -138,7 +137,7 @@ export function validateTpmjsField(tpmjs: unknown): ValidationResult {
const hasRichFields =
data.parameters ||
data.returns ||
- data.envVars ||
+ data.env ||
data.frameworks ||
data.links ||
data.tags ||
|