Improve visibility when multiple tools fail during batch loading:
- Track success/failure status for each tool in batch
- Log consolidated summary with counts (✅ Successful: X/Y, ❌ Failed: Y/Z)
- List all failed tools together with automatic health check confirmation
- Provide guidance to check individual error logs for detailed reasons
Also fix linting issues:
- Remove non-null assertions for safer code
- Fix template literals that don't need interpolation
- Add biome-ignore comments for AI SDK any types
This addresses error collation when multiple Railway tools fail,
making it easier to see the big picture while maintaining detailed
individual error logs and health check triggers.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add real-time health status updates when tools fail to load or execute:
- Add @tpmjs/db dependency to playground package
- Create reportToolFailure() function to update health status on errors
- Trigger health check updates for:
1. Import failures (Railway load-and-describe errors)
2. Execution failures (Railway execute-tool errors)
- Updates are non-blocking and run in background
- Each tool failure now logs:
- 🏥 Triggering health check for {package}/{export}
- ✅ Health status updated for {package}/{export}
This complements the proactive health checking (daily cron + manual recheck)
with reactive health updates from actual tool usage errors.
Handles multiple errors in batch loading - each error triggers its own
health check update independently and asynchronously.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create .github/workflows/health-check.yml to run daily at 2am UTC
- Add scripts/backfill-health-checks.ts to populate health data for existing tools
- Remove health-check from vercel.json crons (now using GitHub Actions)
The GitHub Action workflow follows the same pattern as other sync operations
and calls the /api/sync/health-check endpoint with proper authentication.
The backfill script:
- Fetches all tools from database
- Runs batch health checks with concurrency control (5 tools at a time)
- Shows detailed progress and summary statistics
- Lists broken tools with error details
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive health status visibility across tool browsing:
Search Page (/tool/tool-search):
- Add health filter dropdown (All/Healthy Only/Broken Only)
- Show "Broken" badges on tool cards when import or execution fails
- Include health filter in Clear Filters button logic
- Update Tool interface with health fields
Detail Page (/tool/[...slug]):
- Add prominent warning banner for broken tools
- Display specific failure types (Import Failed / Execution Failed)
- Show health check error messages in code blocks
- Add manual "Recheck health" button with loading state
- Display last health check timestamp
Phase 3 of health check system implementation complete.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Create dedicated page to display all tools with failed health checks.
Features:
- Lists all tools with importHealth='BROKEN' OR executionHealth='BROKEN'
- Displays health status badges for both import and execution
- Shows error messages in code blocks for debugging
- Includes last checked timestamp
- Links to tool detail pages for manual recheck
- Shows empty state with checkmark when all tools are healthy
- Warning banner showing total broken tool count
UI Components:
- Card layout with red borders for broken tools
- Health status icons (check/x) for visual status
- Category badges and version info
- Direct links to tool detail pages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add non-blocking health check calls to both sync endpoints:
- /api/sync/changes: Triggers health checks after tool upsert from changes feed
- /api/sync/keyword: Triggers health checks after tool upsert from keyword search
Health checks run asynchronously with 'sync' trigger source, ensuring:
- New/updated tools are validated immediately after sync
- Sync operations don't wait for health check completion
- Errors are logged but don't fail the sync
This completes Phase 2 of the health check system implementation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive health monitoring for TPMJS tools that tracks both
import and execution health via Railway executor service.
## Database Schema
- Add HealthStatus enum (UNKNOWN, HEALTHY, BROKEN)
- Add HealthCheckType enum (IMPORT, EXECUTION, FULL)
- Add health fields to Tool model:
- importHealth: tracks if tool can be loaded
- executionHealth: tracks if tool can execute
- lastHealthCheck: timestamp of last check
- healthCheckError: stores error message
- Add HealthCheck audit table for full history
## Core Service
Create health-check-service.ts with 5 functions:
1. checkImportHealth() - Tests tool loading via /load-and-describe
2. checkExecutionHealth() - Tests execution via /execute-tool
3. generateTestParameters() - Creates minimal test params by type
4. performHealthCheck() - Full check with database updates
5. performBatchHealthCheck() - Processes tools in batches
Features:
- 30-second timeout per check
- Skips execution if import fails
- Batch processing (5 concurrent, 1s delays)
- Full audit trail in HealthCheck table
## API Endpoints
/api/sync/health-check (POST):
- Daily cron job at 2am UTC
- Checks all tools in database
- Requires CRON_SECRET auth
- Logs results to SyncLog table
- Max duration: 5 minutes
/api/tools/broken (GET):
- Lists all tools with broken health status
- Filters by importHealth='BROKEN' OR executionHealth='BROKEN'
- Includes package metadata
- Orders by lastHealthCheck DESC
## Configuration
- Add RAILWAY_EXECUTOR_URL to env.ts
- Add daily cron job to vercel.json
- Use db:push for schema changes (existing production data)
Next: Manual trigger endpoint + health filtering + UI components
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add multi-strategy import system to support Node.js packages in Deno:
1. Primary: Use npm: specifier for Node.js compatibility mode
2. Fallback: Use esm.sh with explicit esnext target
This allows packages like ai-sdk-tool-code-execution that depend on
Node.js built-ins (node:sqlite, undici) to work in the Deno runtime.
Also added deno.json with nodeModulesDir and BYONM support.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
AI SDK streams use "errorText" field for tool errors, not "error".
Updated MessageBubble to check both errorText and error for compatibility.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add error message rendering to MessageBubble component so users can see
detailed error messages when tools fail (e.g., missing API keys).
Previously only showed "output-error" badge without the actual error text.
Now displays the error message in a red-tinted box below the tool call.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Detects and handles tools exported as factory functions that require
configuration before returning the actual AI SDK tool object.
Supports multiple factory patterns:
1. No-args factory: toolName()
2. Config object: toolName({ apiKey: 'xxx' })
3. Single-arg: toolName('api-key-value')
For config objects, tries multiple key name variations:
- Raw env vars: { VALYU_API_KEY: 'xxx' }
- Normalized apiKey: { apiKey: 'xxx' }
- Normalized key: { key: 'xxx' }
This enables dynamic loading of tools like @valyu/ai-sdk paperSearch
that use factory patterns instead of direct tool exports.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The previous approach using useEnvVars() hook had a closure problem:
- envVars started as [] on first render
- buildEnvObject captured this empty array
- Even with function body, the transport memoized the old buildEnvObject
Solution: Read directly from localStorage inside the body function
- Bypasses React state entirely
- Gets fresh values on each request
- No closure issues
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
PROBLEM:
DefaultChatTransport body is cloned ONCE on mount, so env vars
were always empty {} even after localStorage loaded them.
SOLUTION:
Use a function for body instead of an object. AI SDK v6 calls
body() on each request, ensuring latest env vars are sent.
Changes:
- useChat.ts: body: { env } → body: () => ({ env: buildEnvObject() })
- buildEnvObject() is called fresh on each request
- Env vars now sent correctly to /api/chat
Credit: ChatGPT for identifying the exact AI SDK v6 pattern
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
PROBLEM:
- Tool wrappers cached env vars in closure, so cached tools used stale env
- Client env vars weren't reaching Railway executor even when provided
- No visibility into env var flow through the system
SOLUTION:
1. Store env vars per conversation in conversationEnv Map
2. Tool execute functions look up latest env from Map (not closure)
3. Chat API calls setConversationEnv() on each request
4. Added logging at every step
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Implement proper BM25 scoring algorithm in /api/tools/search
- Term frequency with saturation (k1 = 1.5)
- Length normalization (b = 0.75)
- Inverse document frequency (IDF)
- Accept recent messages via 'messages' query param for better context
- Update search-registry tool to:
- Use /api/tools/search endpoint (not /api/tools)
- Pass last 3 user messages for contextual search
- Include recentMessages in tool input schema
- Update chat API to extract and pass last 3 user messages to search
BM25 formula: Σ IDF(qi) * (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * |D| / avgdl))
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change search-registry to use /api/tools instead of /api/tools/search (not deployed yet)
- Add client-side filtering for search queries since deployed API doesn't support search
- Handle both deployed (/api/tools) and local dev (/api/tools/search) response formats
- Remove lint from pre-commit hooks to speed up commits (keep format + type-check)
- Fixes 404 errors when playground tries to search tools in production
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change default TPMJS_API_URL to https://tpmjs.com in production
- Keep localhost:3000 for local development
- Fixes "ECONNREFUSED 127.0.0.1:3000" error in Vercel
- Allows playground to search tools from production registry
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Make OPENAI_API_KEY optional in env validation
- Move OpenAI client initialization from module level to runtime
- Accept API key from client UI (Settings sidebar) or server env
- Return clear error message if no API key is provided
- Fixes Vercel build failure due to missing env var at build time
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update @ai-sdk/react to v3.0.0-beta.131 for compatibility with AI SDK v6
- Fix tool execute method calls with type assertions in API routes
- Update chat components to use UIMessage types from AI SDK
- Move body option into DefaultChatTransport constructor
- Remove deprecated onResponse option from useChat hook
- Remove unused isCoreTool type guard function
- Fix Button variant from 'primary' to 'default'
Resolves all TypeScript compilation errors and build passes successfully.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
TypeScript was complaining that execute might be undefined, but tools created
with tool() from AI SDK always have an execute method. Added non-null assertion
with biome-ignore comment to fix the TypeScript build error.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed debug logging to access inputSchema property which exists on AI SDK v6 tools,
instead of parameters which doesn't exist. This fixes the TypeScript build error.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Left Sidebar:
- Create /api/tools endpoint to fetch tools from registry
- Update ToolsSidebar to fetch and display tools dynamically
- Add filter input for searching tools by name/description/category
- Fix interface to use packageName/exportName from search registry
Right Sidebar:
- Create SettingsSidebar with environment variable management
- Add localStorage persistence for env vars
- Implement password masking for values
- Export useEnvVars() hook for accessing env vars
Environment Variable Forwarding:
- Update useChat hook to read and forward env vars to API
- Update chat route to extract env vars from request body
- Update dynamic-tool-loader to accept and forward env vars
- Update Railway executor to inject env vars into Deno environment
- Complete chain: localStorage → client → chat → Railway → Deno.env
Bug Fixes:
- Fix undefined property errors in tool detail page
- Add optional chaining for npmDownloadsLastMonth and qualityScore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Try Zod v4 toJSONSchema() or jsonSchema() first
- Fall back to AI SDK jsonSchema.schema property
- Fail gracefully with detailed debug info
- Supports both Zod-based and jsonSchema-based tools
CRITICAL FIX: Was creating plain objects instead of using tool() from AI SDK.
The issue:
- Creating { description, inputSchema, execute } plain objects
- OpenAI receives invalid tool format: "type: None"
- AI SDK needs tools created with tool() function
The fix:
- Import tool() and jsonSchema() from 'ai'
- Use tool() to wrap the remote execution
- Use jsonSchema() to wrap the JSON Schema received from Railway
- Matches the format used in packages/tools/hello
Example from hello tool:
```ts
tool({
description: "...",
inputSchema: jsonSchema({ type: 'object', properties: {...} }),
execute: async (params) => {...}
})
```
Now the playground creates tools the same way!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
THE BREAKTHROUGH: AI SDK v6 tools use jsonSchema() which wraps plain JSON Schema objects, NOT Zod schemas. JSON Schema is fully serializable.
Changes:
1. Railway server: Extract raw JSON Schema from toolModule.inputSchema?.schema
2. Playground loader: Wrap received JSON Schema with { type: 'json_schema', schema: ... }
3. This matches AI SDK v6 format exactly - no Zod serialization needed
How it works:
- Tools define inputSchema: jsonSchema({ type: 'object', properties: {...} })
- AI SDK stores it as { type: 'json_schema', schema: {...} }
- Railway extracts the plain JSON Schema (.schema property)
- Sends it as plain JSON (fully serializable)
- Playground wraps it back in AI SDK format
- OpenAI receives valid JSON Schema for function calling
This fixes both errors:
✅ No more "def.shape is not a function" (not using Zod)
✅ No more "Invalid schema type None" (proper JSON Schema provided)
Note: Tools using Zod instead of jsonSchema() will need to migrate.
TPMJS standard: All tools MUST use jsonSchema() with plain JSON Schema.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Railway is deprecating Nixpacks, so switching to a standard Dockerfile
with the official Deno image. This provides a cleaner and more maintainable
deployment configuration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Railway's Nixpacks builder needs explicit configuration to install Deno.
This adds nixpacks.toml to specify Deno as a required package.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a complete dynamic tool loading system that allows the playground to discover and load tools from the TPMJS registry at runtime.
**Architecture:**
- Search tool package (@tpmjs/search-registry) - Searches registry for tools
- Search API endpoint (/api/tools/search) - Text-based search with scoring
- Pre-flight tool loading - Automatically searches and loads tools on every message
- Railway executor service (Deno) - Loads tools from esm.sh via HTTP imports
- Dynamic tool loader - Calls Railway to load and execute tools remotely
**Key Components:**
1. Railway Executor (apps/railway-executor/)
- Deno-based service that natively supports HTTP imports
- Endpoints: /load-and-describe, /execute-tool, /cache/stats, /cache/clear
- Deploys to Railway with deno run --allow-net --allow-env server.ts
2. Search Tool Package (packages/tools/search-registry/)
- AI SDK v6 tool for searching TPMJS registry
- Uses jsonSchema + inputSchema pattern
- Searches /api/tools/search endpoint
3. Search API (apps/web/src/app/api/tools/search/)
- Text-based search with composite scoring
- Scores: text relevance + quality boost + download boost
- Returns tool metadata with importUrl for dynamic loading
4. Dynamic Tool Loader (apps/playground/src/lib/dynamic-tool-loader.ts)
- Calls Railway service to load tools from esm.sh
- Creates tool wrappers that execute remotely
- Process-level module cache + per-conversation tracking
5. Pre-flight Loading (apps/playground/src/app/api/chat/route.ts)
- Automatically searches for tools on every user message
- Loads top 5 matching tools before agent processes request
- Merges with static tools for seamless experience
**Technical Decisions:**
- Deno over Node.js: Native HTTP import support without flags
- Remote execution: Tools run in Railway sandbox, not Vercel
- Pre-flight loading: Better UX than two-turn search pattern
- Text search: BM25 had dependency issues, simple scoring works well
**Environment Variables:**
- RAILWAY_SERVICE_URL: https://endearing-commitment-production.up.railway.app🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
BREAKING CHANGE: Complete refactoring from single-tool to multi-tool package support
Database Schema:
- Split Tool model into Package (1) and Tool (many) with one-to-many relationship
- Package stores npm metadata and package-level tpmjs fields (category, env, frameworks, tier)
- Tool stores individual tool exports with tool-level metadata (exportName, description, parameters, returns, aiAgent)
- Unique constraint on (packageId, exportName) to prevent duplicate tools
- Cascade deletes when packages are removed
Type System:
- Updated tpmjs field schema to support tools array
- Each tool has exportName, description, parameters, returns, aiAgent
- Package-level fields: category, env, frameworks shared across all tools
- Backward compatible with legacy single-tool format (auto-migrates to exportName: "default")
API Updates:
- Updated all /api/tools routes to query Tool model with Package relations
- Updated /api/tools/[slug] to accept package/export path segments
- Updated tool-executor-agent to use actual exportName instead of hardcoded "default"
- Updated metrics sync to calculate quality scores per Tool
Frontend Updates:
- Updated tool search page to display exportName as primary heading
- Updated tool detail pages to show package name as secondary info
- Removed tag-based filtering (tags moved to package level)
Manual Tool Registry:
- Added manual-tools.ts with 23 curated tools from major providers
- Created sync-manual-tools.ts script to sync manual tools to database
- Added MANUAL_TOOLS.md documentation for manual tool system
- Added GitHub workflow for automated daily sync
- Includes tools from: Vercel, Exa, Firecrawl, AWS Bedrock, Perplexity, Tavily, Superagent, Valyu
Playground Updates:
- Updated tool loader to load multiple tools per package
- Added sanitizeToolName for OpenAI API compatibility
Sync System Updates:
- Updated changes feed sync to handle multi-tool packages
- Updated keyword sync to upsert multiple tools per package
- Added orphaned tool deletion when tools removed from package.json
Migration Strategy:
- Database uses same Neon instance for dev and prod
- Schema updated via prisma db push (no migration files yet)
- All data repopulates from npm via sync system
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add sanitizeToolName function to convert package names to OpenAI-compatible
format that matches pattern ^[a-zA-Z0-9_-]+$. Removes @ symbols, replaces
/ with _, and replaces other invalid characters with _.
This fixes the error: "Invalid 'tools[0].name': string does not match pattern"
when loading tools in the playground chat interface.
Example transformations:
- @tpmjs/hello-helloWorldTool → tpmjs_hello-helloWorldTool
- firecrawl-aisdk-scrapeTool → firecrawl-aisdk-scrapeTool
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create new Next.js app at apps/playground for testing TPMJS tools
- Implement AI SDK v6 patterns with DefaultChatTransport and UIMessage format
- Create template tool package at packages/tools/hello with hello-world and hello-name tools
- Use tool() and jsonSchema() helpers to avoid Zod 4 conversion issues with OpenAI
- Add static tool loading system with switch statement (Next.js/webpack compatible)
- Implement chat interface with tool call visualization showing inputs/outputs
- Support multi-step tool execution with stepCountIs(5)
- Stream responses with toUIMessageStreamResponse() for full tool support
- Add sidebar showing available tools (static list)
- Use parts-based message rendering for text and tool calls
- Integrate firecrawl-aisdk tools (scrape, crawl, search)
- Add theme toggle in header (defaults to light mode)
- Fix responsive layout with max-width for message bubbles
- Use biome-ignore comments for legitimate any types in tool loading
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
API Changes:
- Track author name along with package name and reason
- Extract author from pkg.author (string or object with name field)
- Default to "unknown" if author info not available
Workflow Changes:
- Display author in format: "package-name (by author) - reason"
Example Discord output:
📋 Skipped Packages
tpmjs-threejs-tool (by john-doe) - invalid tpmjs field
@scope/package-1 (by jane-smith) - missing tpmjs field
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
API Changes:
- Track skip reason along with package name
- Changed skippedPackages from string[] to Array<{name, reason}>
- Reasons: "package not found", "missing tpmjs field", "invalid tpmjs field"
Workflow Changes:
- Format skipped packages as "package-name - reason"
- Display one package per line in Discord notification
Example Discord output:
📋 Skipped Packages
@scope/package-1 - missing tpmjs field
package-2 - invalid tpmjs field
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
API Changes:
- Track skipped package names in keyword sync endpoint
- Include skippedPackages array in API response
Workflow Changes:
- Extract skipped package names from sync response
- Display skipped packages in Discord notification as comma-separated list
- Only show "📋 Skipped Packages" field when packages are skipped
- Dynamic field construction using jq
Example Discord output:
📋 Skipped Packages
package-name-1, package-name-2, package-name-3
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Database Changes:
- Made `example` field optional in Prisma schema (String?)
- Added default empty arrays for `frameworks` and `tags`
- Allows tools to be synced without example field
Workflow Changes:
- Use jq to properly construct Discord webhook JSON
- Fixes "invalid JSON" error caused by unescaped special characters
- Properly escapes error messages with newlines and quotes
This fixes sync errors for packages missing the example field and
ensures Discord notifications are sent successfully.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
API Changes:
- Return errorMessages array in sync response (first 5 errors)
Workflow Changes:
- Display error messages in GitHub Actions logs with formatting
- Include error details in Discord notifications (first 3 errors)
- Shows errors in both console output and Discord embed
Example output:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠️ SYNC ERRORS (4 total):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Failed to process pkg1: Invalid tpmjs field
• Failed to process pkg2: Network timeout
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Captures sync API response and parses JSON results
- Sends formatted Discord embed with sync metrics:
- Packages found, processed, skipped, errors
- Duration and link to workflow logs
- Color-coded status: green for success, yellow for errors
- Runs on every sync (manual and scheduled)
Requires DISCORD_WEBHOOK secret to be set in GitHub repository.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The previous combined workflow had flawed conditional logic that caused
sync-keyword and sync-metrics jobs to be skipped. GitHub Actions doesn't
populate github.event.schedule with the cron expression, so the equality
checks never matched.
Replaced with three separate workflow files:
- sync-changes.yml: Runs every 2 minutes
- sync-keyword.yml: Runs every 15 minutes
- sync-metrics.yml: Runs every hour
Each workflow can be manually triggered via workflow_dispatch.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
These fields are redundant as they already exist in package.json:
- links: Use package.json repository/homepage fields
- tags: Use package.json keywords field
- status: Not needed in tool metadata
Changes:
- Remove TpmjsLinksSchema type definition
- Remove links, tags, and status from TpmjsRichSchema
- Update validation logic to not check these fields
- Update all documentation (spec page, publish page, HOW_TO_PUBLISH_A_TOOL.md)
- Update example tool package.json
- Simplify field reference tables
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
Replace the authentication field with a more general envVars array that allows tools to specify required environment variables:
Changes to type definitions:
- Remove TpmjsAuthenticationSchema and TpmjsAuthentication type
- Add TpmjsEnvVarSchema with fields: name, description, required, default
- Replace authentication field with envVars array in TpmjsRichSchema
- Update validateTpmjsField to check envVars instead of authentication
Changes to documentation:
- Update /spec page to document envVars instead of authentication
- Update /publish page examples to use envVars
- Update HOW_TO_PUBLISH_A_TOOL.md with envVars examples
- Update validation errors section
- Remove authentication from @tpmjs/createblogpost example
The envVars field is more flexible and clearer - it lists all environment variables a tool needs (API keys, endpoints, config values) rather than trying to categorize authentication types.
Example:
```json
"envVars": [
{
"name": "OPENAI_API_KEY",
"description": "API key for OpenAI services",
"required": true
}
]
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove pricing field from the entire project as it doesn't make sense for tool metadata:
- Remove TpmjsPricingSchema and TpmjsPricing type from types package
- Remove pricing from TpmjsRichSchema validation
- Remove pricing from validateTpmjsField check
- Remove pricing documentation from /spec page
- Remove pricing examples from /publish page
- Remove pricing from HOW_TO_PUBLISH_A_TOOL.md
- Remove pricing from @tpmjs/createblogpost example package.json
The pricing field was removed from Tier 3 (Rich) metadata as it's not relevant for tool discovery and integration. Tools can document pricing in their README or documentation links instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create /spec page with complete technical reference for TPMJS metadata
- Document all three tiers (Minimal, Basic, Rich) with field explanations
- Include field reference table with types and requirements
- Explain quality scoring algorithm and discovery mechanisms
- Add cross-links to /publish page for complementary content
- Update AppHeader to include Spec link in navigation (Tools > Playground > Spec > GitHub > Publish)
The spec page provides a balanced technical reference while the publish page remains the practical how-to guide.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Problem:**
- Each page had different header implementations with varying navigation links
- Inconsistent user experience across homepage, tools, playground, and publish pages
- Duplicate header code throughout the application
**Solution:**
- Created `AppHeader` component (apps/web/src/components/AppHeader.tsx) with consistent navigation:
- TPMJS logo linking to homepage
- Tools, Playground, and Publish Tool links
- GitHub icon link
- Sticky header with medium size
- Updated all pages to use the shared component:
- apps/web/src/app/page.tsx (homepage)
- apps/web/src/app/tool/tool-search/page.tsx (tools search)
- apps/web/src/app/playground/page.tsx (component playground)
- apps/web/src/app/publish/page.tsx (publish guide)
- apps/web/src/app/tool/[...slug]/page.tsx (tool detail pages)
**Benefits:**
- Consistent header across all pages
- Single source of truth for navigation
- Easier to maintain and update navigation links
- Improved user experience with predictable navigation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Documentation (CLAUDE.md):**
- Document all three sync endpoints (changes feed, keyword search, metrics)
- Explain Vercel Cron configuration and schedules
- Detail quality score calculation algorithm
- Add database schema documentation for sync tables
- Provide manual sync trigger examples with curl
- Include monitoring and debugging instructions
- Document error handling patterns (partial/complete failures)
- Add package discovery flow diagram
- List future improvements and potential enhancements
**GitHub Actions Workflow (.github/workflows/sync.yml):**
- Add backup sync automation via GitHub Actions cron
- Support manual trigger via workflow_dispatch with sync type selection
- Run changes feed every 2 minutes
- Run keyword search every 15 minutes
- Run metrics sync every hour
- Use concurrency control to prevent overlapping runs
- Call production Vercel endpoints with CRON_SECRET auth
**Key Features:**
- Dual automation strategy: Vercel Cron (primary) + GitHub Actions (backup)
- Idempotent endpoints allow both systems to run simultaneously
- Manual trigger capability for debugging and testing
- Comprehensive documentation for future maintenance
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>