diff --git a/.claude/commands/blocks-develop.md b/.claude/commands/blocks-develop.md new file mode 100644 index 0000000..45ee336 --- /dev/null +++ b/.claude/commands/blocks-develop.md @@ -0,0 +1,102 @@ +--- +description: Develop and validate TPMJS tools using the blocks CLI +--- + +Help the user develop new tools for the TPMJS registry using the blocks CLI. This workflow covers defining tools in blocks.yml, implementing them with AI SDK v6, validating with the blocks CLI, and publishing to npm. + +## Development Workflow + +### 1. Define Tool in blocks.yml + +Add tool definition to `packages/tools/official/blocks.yml`: + +```yaml +blocks: + category.toolName: + type: utility + description: "Clear description for LLMs" + path: "tool-directory-name" + domain_rules: + - id: rule_name + description: "Implementation requirement" + inputs: + - name: paramName + type: string + description: "Parameter description" + outputs: + - name: result + type: ResultType + description: "Output description" + measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance] +``` + +### 2. Create Package Structure + +``` +packages/tools/official/tool-name/ +├── package.json # npm package with tpmjs field +├── tsconfig.json # Extends @tpmjs/tsconfig +├── tsup.config.ts # Build config +├── block.ts # REQUIRED by validator +├── index.ts # Re-export from src +└── src/index.ts # Main implementation +``` + +### 3. Implement with AI SDK v6 + +```typescript +import { jsonSchema, tool } from 'ai'; + +export const myTool = tool({ + description: 'Description for LLMs', + parameters: jsonSchema({ + type: 'object', + properties: { /* ... */ }, + required: ['field1'], + }), + async execute(input): Promise { + // REAL implementation - no stubs + return result; + }, +}); + +export default myTool; +``` + +### 4. Run Validation + +```bash +cd packages/tools/official +pnpm blocks run tool-name # Validate single tool +pnpm blocks run tool-name --force # Force full validation +pnpm blocks run --all # Validate all tools +``` + +### 5. Build and Publish + +```bash +pnpm build +npm publish --access public + +# Trigger sync to tpmjs.com +source apps/web/.env.local +curl -X POST https://tpmjs.com/api/sync/keyword -H "Authorization: Bearer $CRON_SECRET" +``` + +## Valid Categories + +For `tpmjs.category` in package.json: `research`, `web`, `data`, `documentation`, `engineering`, `security`, `statistics`, `ops`, `agent`, `sandbox`, `utilities`, `html`, `compliance` + +## Required Files + +- **block.ts** at root: `export const block = { name: 'tool-name', tools: { myTool } };` +- **index.ts** at root: `export * from './src/index.js';` +- Both are required for the validator to find the tool + +## Common Issues + +- "invalid tpmjs field" during sync = Invalid category or missing tools array +- "Tool not found in exports" = Export name must match blocks.yml +- "Required file not found" = Need index.ts and block.ts at package root + +When helping the user, read the full skill documentation at `.claude/skills/blocks-develop.md` for comprehensive details on entities, measures, and multi-tool packages. diff --git a/.claude/pipelines/tool-request.md b/.claude/pipelines/tool-request.md new file mode 100644 index 0000000..16a8359 --- /dev/null +++ b/.claude/pipelines/tool-request.md @@ -0,0 +1,248 @@ +# Tool Request Pipeline Specification + +Automated pipeline for creating TPMJS tools from GitHub issues using Claude. + +## Overview + +When a maintainer applies the `tool-request` label to an issue, Claude automatically: +1. Analyzes the tool idea and designs the implementation +2. Determines the best package (existing or new) +3. Implements the tool with AI SDK v6 +4. Validates using blocks CLI +5. Creates an auto-merge PR +6. Publishes to npm +7. Syncs to tpmjs.com registry + +## Trigger + +| Setting | Value | +|---------|-------| +| Label | `tool-request` | +| Who can apply | Maintainers only | +| Trigger mechanism | Label application triggers workflow, which comments `@claude` | +| Concurrency | Parallel execution allowed | +| Rate limit | None (trust maintainers) | + +## Input Requirements + +| Setting | Value | +|---------|-------| +| Input format | Accept vague ideas - Claude designs autonomously | +| Structured template | Not required | +| Clarification | Claude fills gaps autonomously, doesn't ask first | +| Mid-flight edits | Incorporate edits - check for changes at each step | + +## Package Organization + +| Setting | Value | +|---------|-------| +| Strategy | Hybrid - default to categories, allow functional cohesion exceptions | +| Package selection | Analyze all existing tools in candidate packages to find best fit | +| New vs existing | Claude decides based on functional cohesion analysis | +| blocks.yml access | Full access - Claude adds entries as part of workflow | + +### Decision Logic for Package Selection + +1. Search existing packages for functionally related tools +2. If strong match found (>70% conceptual overlap), add to existing package +3. If no match or tool is foundational for a new domain, create new package +4. Exception: tightly coupled tools (e.g., e2b-*) stay together regardless of category + +## Validation & Iteration + +| Setting | Value | +|---------|-------| +| Max attempts | 3 before escalating to human review | +| On failure | Iterate in-issue - Claude fixes and retries | +| Runtime test | Execute with sample inputs, capture output as screenshot | +| Tool restrictions | None - any valid tool that passes validation is allowed | + +### Validation Steps + +1. `pnpm blocks run ` - domain rules and output measures +2. TypeScript compilation check +3. Execute tool with generated sample inputs +4. Verify output structure matches schema +5. Capture execution output as proof in issue comment + +## Publishing + +| Setting | Value | +|---------|-------| +| Branch strategy | Auto-merge PR - create for visibility, auto-merge if CI passes | +| Version bump | Minor (0.X.0) - new functionality = minor version | +| NPM auth | Use existing `NPM_TOKEN` secret | +| On publish failure | Comment explaining failure, wait for human to fix and re-trigger | + +### PR Template + +```markdown +## Tool: `` + +**Package:** `@tpmjs/tools-` +**Version:** `0.X.0` -> `0.Y.0` + +### Description + + +### Implementation +- [ ] blocks.yml entry added +- [ ] Package files created +- [ ] Validation passed +- [ ] Runtime test passed + +### Test Output + + +--- +Auto-generated by Claude from # +``` + +## Post-Publish + +| Setting | Value | +|---------|-------| +| Registry sync | Auto-sync - call `/api/sync/keyword` after publish | +| Verify listing | Confirm tool appears on tpmjs.com before reporting success | +| Collections | Standalone only - no auto-add | +| Duplicates | Propose enhancement to existing tool if duplicate detected | + +## Status Tracking + +### Labels (managed by Claude) + +| Label | Meaning | +|-------|---------| +| `tool-request` | Initial trigger (applied by maintainer) | +| `claude-working` | Claude is actively processing | +| `validation-failed` | Validation failed, iterating | +| `published` | Successfully published to npm | +| `escalated` | Requires human intervention | + +### Issue Lifecycle + +1. Maintainer applies `tool-request` label +2. Workflow triggers, adds `claude-working` label +3. On validation failure: add `validation-failed`, retry (max 3x) +4. On success: remove other labels, add `published` +5. Keep issue open 24h for feedback +6. Auto-close after 24h + +## Success Report + +Full changelog posted to issue: + +```markdown +## Tool Published Successfully + +**Package:** `@tpmjs/tools-@` +**NPM:** https://www.npmjs.com/package/@tpmjs/tools- +**Registry:** https://tpmjs.com/tool/@tpmjs/tools-/ + +### Changes +- Added `` tool +- Updated blocks.yml +- Bumped version from X.Y.Z to X.Y+1.0 + +### Validation Results + + +### Test Execution + + +### Files Changed + + +--- +This issue will auto-close in 24 hours. Reply if you have feedback. +``` + +## Error Handling + +| Scenario | Action | +|----------|--------| +| Validation fails 3x | Add `escalated` label, assign to maintainer with diagnostic info | +| NPM publish fails | Comment explaining failure, wait for human fix | +| Duplicate detected | Comment explaining existing tool, propose enhancement instead | +| blocks.yml conflict | Rebase and retry automatically | +| Issue edited mid-work | Detect changes, incorporate into implementation | + +## Context & Memory + +| Setting | Value | +|---------|-------| +| State tracking | Full conversation - Claude remembers entire issue thread | +| Previous attempts | Tracked within issue context | +| Cross-issue | No memory between different issues | + +## Workflow File Structure + +```yaml +name: Tool Request Pipeline + +on: + issues: + types: [labeled] + +jobs: + trigger-claude: + if: github.event.label.name == 'tool-request' + runs-on: ubuntu-latest + steps: + - name: Add working label + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['claude-working'] + }); + + - name: Comment to trigger Claude + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '@claude Please implement this tool request following the tool-request pipeline specification at `.claude/pipelines/tool-request.md`.' + }); +``` + +## Claude Instructions + +When triggered, Claude should: + +1. **Read this spec** at `.claude/pipelines/tool-request.md` +2. **Analyze the issue** - extract tool name, description, intended functionality +3. **Check for duplicates** - search existing tools for similar functionality +4. **Select package** - analyze existing packages, decide new vs existing +5. **Design the tool** - define inputs, outputs, implementation approach +6. **Implement** - create/update blocks.yml, create package files +7. **Validate** - run `pnpm blocks run ` in packages/tools/official +8. **Test** - execute with sample inputs, capture output +9. **Create PR** - feature branch, include all changes +10. **Publish** - after CI passes, `npm publish` +11. **Sync** - trigger registry sync +12. **Report** - full changelog to issue +13. **Cleanup** - update labels, schedule auto-close + +## Security Considerations + +- Only maintainers can apply trigger label +- NPM_TOKEN is existing secret, not exposed in logs +- Tool code is reviewed via PR (even if auto-merged) +- No restrictions on tool types - trust validation + maintainer judgment +- Full audit trail in issue comments + +## Dry Run + +No dry run mode. Validation is sufficient safeguard. If testing needed, create a test issue and manually delete artifacts after. + +--- + +*Specification created: 2026-01-19* +*Interview conducted with: @ajax* diff --git a/.claude/plugins/ralph-wiggum/commands/cancel-ralph.md b/.claude/plugins/ralph-wiggum/commands/cancel-ralph.md new file mode 100644 index 0000000..471a78b --- /dev/null +++ b/.claude/plugins/ralph-wiggum/commands/cancel-ralph.md @@ -0,0 +1,16 @@ +--- +description: Cancel the active Ralph loop +command: rm -f .claude/ralph-loop.local.md && echo "Ralph loop cancelled" +--- + +# Cancel Ralph Loop + +Immediately cancel any active Ralph loop and allow normal session exit. + +## Usage + +``` +/cancel-ralph +``` + +This removes the state file that drives the loop, allowing the session to exit normally. diff --git a/.claude/plugins/ralph-wiggum/commands/ralph-loop.md b/.claude/plugins/ralph-wiggum/commands/ralph-loop.md new file mode 100644 index 0000000..ce3e94b --- /dev/null +++ b/.claude/plugins/ralph-wiggum/commands/ralph-loop.md @@ -0,0 +1,43 @@ +--- +description: Start Ralph Wiggum loop in current session +command: "${CLAUDE_PLUGIN_ROOT}/scripts/setup-ralph-loop.sh" $ARGUMENTS +--- + +# Ralph Loop + +Start an iterative development loop that continues until the task is complete. + +## Usage + +``` +/ralph-loop "Your task description" [--max-iterations N] [--validation-script PATH] [--completion-promise TEXT] +``` + +## How It Works + +1. You provide a task and optional validation criteria +2. Claude works on the task +3. When Claude tries to exit, the stop hook intercepts +4. If validation fails OR completion promise not met, the loop continues +5. Claude sees previous work and continues iterating +6. Loop ends when validation passes or max iterations reached + +## Important Rules + +- If a completion promise is set, you may ONLY output it when the statement is completely and unequivocally TRUE +- Do NOT use false completion promises as an exit strategy +- The loop persists until genuine completion is achieved +- Use validation scripts for programmatic verification + +## Examples + +```bash +# With validation script only +/ralph-loop "Build the SDK package" --validation-script ./scripts/validate-sdk.sh + +# With completion promise +/ralph-loop "Fix all type errors" --completion-promise "ALL_TYPES_PASS" + +# With both +/ralph-loop "Complete feature X" --max-iterations 15 --validation-script ./validate.sh --completion-promise "FEATURE_COMPLETE" +``` diff --git a/.claude/plugins/ralph-wiggum/hooks/hooks.json b/.claude/plugins/ralph-wiggum/hooks/hooks.json new file mode 100644 index 0000000..2e5f697 --- /dev/null +++ b/.claude/plugins/ralph-wiggum/hooks/hooks.json @@ -0,0 +1,15 @@ +{ + "description": "Ralph Wiggum plugin stop hook for self-referential loops", + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh" + } + ] + } + ] + } +} diff --git a/.claude/plugins/ralph-wiggum/hooks/stop-hook.sh b/.claude/plugins/ralph-wiggum/hooks/stop-hook.sh new file mode 100755 index 0000000..bfbfece --- /dev/null +++ b/.claude/plugins/ralph-wiggum/hooks/stop-hook.sh @@ -0,0 +1,111 @@ +#!/bin/bash +# Ralph Wiggum Stop Hook - Self-referential loop for iterative development +# This hook intercepts the Stop event and decides whether to continue the loop + +set -euo pipefail + +STATE_FILE=".claude/ralph-loop.local.md" +TRANSCRIPT_FILE="${CLAUDE_TRANSCRIPT:-}" + +# Check if ralph loop is active +if [[ ! -f "$STATE_FILE" ]]; then + # No active loop, allow normal exit + exit 0 +fi + +# Parse the state file frontmatter +parse_frontmatter() { + local key="$1" + sed -n '/^---$/,/^---$/p' "$STATE_FILE" | grep "^${key}:" | sed "s/^${key}: *//" | tr -d '"' +} + +iteration=$(parse_frontmatter "iteration") +max_iterations=$(parse_frontmatter "max_iterations") +completion_promise=$(parse_frontmatter "completion_promise") +prompt=$(parse_frontmatter "prompt") +validation_script=$(parse_frontmatter "validation_script") + +# Validate numeric fields +if ! [[ "$iteration" =~ ^[0-9]+$ ]]; then + echo "Error: Invalid iteration count in state file" >&2 + rm -f "$STATE_FILE" + exit 0 +fi + +if ! [[ "$max_iterations" =~ ^[0-9]+$ ]]; then + echo "Error: Invalid max_iterations in state file" >&2 + rm -f "$STATE_FILE" + exit 0 +fi + +# Check if max iterations reached +if [[ "$max_iterations" -gt 0 ]] && [[ "$iteration" -ge "$max_iterations" ]]; then + echo "Ralph loop reached max iterations ($max_iterations). Exiting." >&2 + rm -f "$STATE_FILE" + exit 0 +fi + +# Run validation script if provided +validation_passed=false +if [[ -n "$validation_script" ]] && [[ -f "$validation_script" ]]; then + echo "Running validation script: $validation_script" >&2 + if bash "$validation_script" 2>&1; then + validation_passed=true + echo "Validation PASSED!" >&2 + else + echo "Validation FAILED. Continuing loop..." >&2 + fi +fi + +# Check for completion promise in transcript +if [[ -n "$completion_promise" ]] && [[ -n "$TRANSCRIPT_FILE" ]] && [[ -f "$TRANSCRIPT_FILE" ]]; then + # Get the last assistant message + last_message=$(tail -100 "$TRANSCRIPT_FILE" | grep -o '[^<]*' | tail -1 | sed 's/\(.*\)<\/promise>/\1/' || true) + + if [[ "$last_message" == "$completion_promise" ]]; then + # Also check if validation passed (if validation script exists) + if [[ -z "$validation_script" ]] || [[ "$validation_passed" == "true" ]]; then + echo "Completion promise matched and validation passed. Ralph loop complete!" >&2 + rm -f "$STATE_FILE" + exit 0 + else + echo "Completion promise matched but validation failed. Continuing..." >&2 + fi + fi +fi + +# If validation passed without explicit promise, we can exit +if [[ "$validation_passed" == "true" ]] && [[ -z "$completion_promise" ]]; then + echo "Validation passed. Ralph loop complete!" >&2 + rm -f "$STATE_FILE" + exit 0 +fi + +# Increment iteration +new_iteration=$((iteration + 1)) + +# Update state file +sed -i.bak "s/^iteration: .*/iteration: $new_iteration/" "$STATE_FILE" +rm -f "${STATE_FILE}.bak" + +# Build the continuation message +cat << EOF +{ + "decision": "block", + "reason": "Ralph loop iteration $new_iteration of $max_iterations", + "message": " +--- +RALPH LOOP - Iteration $new_iteration / $max_iterations +--- + +Continue working on the task. Your previous iteration's work is preserved in the codebase. + +TASK: $prompt + +$(if [[ -n "$validation_script" ]]; then echo "VALIDATION: Run the validation to check progress. Script: $validation_script"; fi) +$(if [[ -n "$completion_promise" ]]; then echo "COMPLETION: Output $completion_promise ONLY when the task is completely done AND validation passes."; fi) + +Review what you've done so far and continue from where you left off. +" +} +EOF diff --git a/.claude/plugins/ralph-wiggum/scripts/setup-ralph-loop.sh b/.claude/plugins/ralph-wiggum/scripts/setup-ralph-loop.sh new file mode 100755 index 0000000..8be7780 --- /dev/null +++ b/.claude/plugins/ralph-wiggum/scripts/setup-ralph-loop.sh @@ -0,0 +1,120 @@ +#!/bin/bash +# Setup Ralph Loop - Initialize the iterative development loop +# Usage: setup-ralph-loop.sh "PROMPT" [--max-iterations N] [--completion-promise TEXT] [--validation-script PATH] + +set -euo pipefail + +STATE_FILE=".claude/ralph-loop.local.md" + +# Default values +MAX_ITERATIONS=20 +COMPLETION_PROMISE="" +VALIDATION_SCRIPT="" +PROMPT="" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --max-iterations) + MAX_ITERATIONS="$2" + shift 2 + ;; + --completion-promise) + COMPLETION_PROMISE="$2" + shift 2 + ;; + --validation-script) + VALIDATION_SCRIPT="$2" + shift 2 + ;; + --help|-h) + cat << EOF +Ralph Loop Setup + +Usage: setup-ralph-loop.sh "PROMPT" [OPTIONS] + +Options: + --max-iterations N Maximum iterations before stopping (default: 20, 0 = unlimited) + --completion-promise TXT Phrase to output when complete (use TXT) + --validation-script PATH Script to run for validation (exit 0 = pass) + --help, -h Show this help + +Example: + setup-ralph-loop.sh "Build the SDK package" --max-iterations 10 --validation-script ./validate.sh +EOF + exit 0 + ;; + *) + if [[ -z "$PROMPT" ]]; then + PROMPT="$1" + else + PROMPT="$PROMPT $1" + fi + shift + ;; + esac +done + +# Validate prompt +if [[ -z "$PROMPT" ]]; then + echo "Error: PROMPT is required" >&2 + exit 1 +fi + +# Validate max iterations +if ! [[ "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then + echo "Error: --max-iterations must be a number" >&2 + exit 1 +fi + +# Validate validation script exists if provided +if [[ -n "$VALIDATION_SCRIPT" ]] && [[ ! -f "$VALIDATION_SCRIPT" ]]; then + echo "Error: Validation script not found: $VALIDATION_SCRIPT" >&2 + exit 1 +fi + +# Create state directory +mkdir -p "$(dirname "$STATE_FILE")" + +# Create state file +cat << EOF > "$STATE_FILE" +--- +iteration: 1 +max_iterations: $MAX_ITERATIONS +completion_promise: "$COMPLETION_PROMISE" +validation_script: "$VALIDATION_SCRIPT" +prompt: "$PROMPT" +started_at: "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" +--- + +# Ralph Loop State + +This file tracks the state of an active Ralph loop. DO NOT DELETE while loop is running. + +## Configuration +- **Task**: $PROMPT +- **Max Iterations**: $MAX_ITERATIONS +- **Validation Script**: ${VALIDATION_SCRIPT:-"None"} +- **Completion Promise**: ${COMPLETION_PROMISE:-"None (validation only)"} + +## Progress Log + +Iteration logs will be appended below as the loop progresses. + +--- +EOF + +echo "Ralph loop initialized!" +echo " Task: $PROMPT" +echo " Max iterations: $MAX_ITERATIONS" +echo " Validation: ${VALIDATION_SCRIPT:-"None"}" +echo " Completion promise: ${COMPLETION_PROMISE:-"None"}" +echo "" +echo "The loop will continue until:" +if [[ -n "$VALIDATION_SCRIPT" ]]; then + echo " - Validation script passes ($VALIDATION_SCRIPT returns exit code 0)" +fi +if [[ -n "$COMPLETION_PROMISE" ]]; then + echo " - You output: $COMPLETION_PROMISE" +fi +echo " - OR max iterations ($MAX_ITERATIONS) is reached" diff --git a/.claude/skills/agentmail b/.claude/skills/agentmail new file mode 120000 index 0000000..63f635b --- /dev/null +++ b/.claude/skills/agentmail @@ -0,0 +1 @@ +../../.agents/skills/agentmail \ No newline at end of file diff --git a/.claude/skills/blocks-develop.md b/.claude/skills/blocks-develop.md new file mode 100644 index 0000000..ab9917c --- /dev/null +++ b/.claude/skills/blocks-develop.md @@ -0,0 +1,357 @@ +# TPMJS Tool Development with Blocks CLI + +Use this skill when developing new tools for the TPMJS registry. This covers the full workflow from defining a tool in blocks.yml through implementation, validation, and publishing. + +## Quick Start + +```bash +# Navigate to official tools directory +cd packages/tools/official + +# Run validation on a specific tool +pnpm blocks run + +# Run validation on all tools +pnpm blocks run --all + +# Force full validation (ignore cache) +pnpm blocks run --force +``` + +## Development Workflow + +### 1. Define the Tool Block in blocks.yml + +Add your tool definition to `packages/tools/official/blocks.yml` in the `blocks:` section: + +```yaml +blocks: + # Category.toolName format + sandbox.myTool: + type: utility + description: "Clear, LLM-friendly description of what the tool does" + path: "my-tool" # Directory name under packages/tools/official/ + 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: MyResultType + description: "What the tool returns" + measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance] +``` + +**Key Fields:** +- `type`: Usually `utility` for single-shot tools +- `path`: Directory name (kebab-case) +- `domain_rules`: Implementation requirements the validator checks +- `inputs/outputs`: Schema for validation +- `measures`: Quality constraints from the domain section + +### 2. Create the Tool Package + +Create the directory structure: + +``` +packages/tools/official/my-tool/ +├── package.json +├── tsconfig.json +├── tsup.config.ts +├── block.ts # Required by validator +├── index.ts # Re-export from src +└── src/ + └── index.ts # Main implementation +``` + +**package.json:** +```json +{ + "name": "@tpmjs/tools-my-tool", + "version": "0.1.0", + "description": "Short description for npm", + "type": "module", + "keywords": ["tpmjs", "category-name", "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.23" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/tpmjs/tpmjs.git", + "directory": "packages/tools/official/my-tool" + }, + "homepage": "https://tpmjs.com", + "license": "MIT", + "tpmjs": { + "category": "sandbox", + "frameworks": ["vercel-ai"], + "tools": [ + { + "name": "myTool", + "description": "Clear description (20+ chars) of what this tool does." + } + ] + } +} +``` + +**Valid categories for tpmjs.category:** +- `research`, `web`, `data`, `documentation`, `engineering` +- `security`, `statistics`, `ops`, `agent`, `sandbox`, `utilities` +- `html`, `compliance` + +**tsconfig.json:** +```json +{ + "extends": "@tpmjs/tsconfig/react-library.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} +``` + +**tsup.config.ts:** +```typescript +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + dts: true, + clean: true, + sourcemap: true, + target: 'es2022', +}); +``` + +**block.ts (Required by validator):** +```typescript +import { myTool } from './src/index.js'; + +export const block = { + name: 'my-tool', + description: 'Short description', + tools: { myTool }, +}; + +export default block; +``` + +**index.ts (Root re-export):** +```typescript +export * from './src/index.js'; +export { default } from './src/index.js'; +``` + +### 3. Implement the Tool + +**src/index.ts:** +```typescript +import { jsonSchema, tool } from 'ai'; + +// Define input/output types +interface MyToolInput { + param1: string; + param2?: number; +} + +interface MyToolResult { + data: string; + metadata: { + processedAt: string; + }; +} + +// Export the tool using AI SDK v6 pattern +export const myTool = tool({ + description: 'Clear description for LLMs explaining what this tool does and when to use it.', + parameters: jsonSchema({ + type: 'object', + properties: { + param1: { + type: 'string', + description: 'Description of param1', + }, + param2: { + type: 'number', + description: 'Optional description of param2', + }, + }, + required: ['param1'], + }), + async execute(input): Promise { + // REAL implementation - no stubs, no TODOs + const result = await doSomething(input.param1); + + return { + data: result, + metadata: { + processedAt: new Date().toISOString(), + }, + }; + }, +}); + +// Default export for compatibility +export default myTool; +``` + +### 4. Run Validation + +```bash +cd packages/tools/official + +# Validate your tool +pnpm blocks run my-tool + +# The validator runs 3 stages: +# 1. schema - Validates inputs/outputs match blocks.yml +# 2. shape - Verifies exports and structure +# 3. domain - Checks domain rules are satisfied +``` + +**Common validation errors:** +- `Required file "index.ts" not found` - Need index.ts at package root +- `Required file "block.ts" not found` - Need block.ts at package root +- `Tool "myTool" not found in exports` - Export name must match blocks.yml +- `invalid tpmjs field` - Category must be valid, tools array required + +### 5. Build and Publish + +```bash +# Build the package +pnpm build + +# Publish to npm +npm publish --access public + +# Trigger sync to tpmjs.com +source apps/web/.env.local +curl -X POST https://tpmjs.com/api/sync/keyword \ + -H "Authorization: Bearer $CRON_SECRET" +``` + +## Multi-Tool Packages + +For packages with multiple tools (like unsandbox): + +**blocks.yml:** +```yaml +blocks: + sandbox.executeCodeAsync: + type: utility + path: "unsandbox" # Same path for all tools in package + # ... + + sandbox.getJob: + type: utility + path: "unsandbox" # Same path + # ... +``` + +**block.ts:** +```typescript +import { executeCodeAsync, getJob, listJobs } from './src/index.js'; + +export const block = { + name: 'unsandbox', + tools: { executeCodeAsync, getJob, listJobs }, +}; + +export default block; +``` + +**package.json tpmjs field:** +```json +{ + "tpmjs": { + "category": "sandbox", + "frameworks": ["vercel-ai"], + "tools": [ + { "name": "executeCodeAsync", "description": "..." }, + { "name": "getJob", "description": "..." }, + { "name": "listJobs", "description": "..." } + ] + } +} +``` + +## Philosophy (from blocks.yml) + +- Every tool MUST be a working, production-ready implementation - no stubs, no TODOs +- Tools use AI SDK v6 `tool()` + `jsonSchema()` pattern exclusively +- Each tool does ONE thing exceptionally well (single-shot, one call in, one result out) +- Tools return structured, typed outputs that agents can reliably parse +- Error handling is explicit - throw meaningful errors, never silently fail +- Dependencies are minimal and production-stable + +## Domain Entities + +When defining outputs, reference existing entities from blocks.yml: + +```yaml +# Example entities available: +url: [href, domain, protocol, path, query, fragment] +webpage: [url, title, html, text, metadata] +text_content: [raw, sentences, paragraphs, wordCount] +claim: [statement, confidence, needsCitation, category] +timeline: [events, dateRange, gaps, eventCount] +``` + +Or define new entities in the `domain.entities` section if needed. + +## Quality Measures + +Reference these in your tool's `measures` array: + +- `working_implementation` - No stubs, TODOs, or placeholders +- `valid_output_structure` - Returns correct typed object +- `proper_error_handling` - Throws descriptive errors +- `ai_sdk_compliance` - Uses tool() and jsonSchema() +- `npm_publishable` - Valid package.json with tpmjs field +- `readme_documentation` - Has README with examples + +## Debugging Tips + +```bash +# Force rebuild without cache +pnpm blocks run my-tool --force --no-cache + +# See JSON output for debugging +pnpm blocks run my-tool --json + +# Check if validator finds your package +ls packages/tools/official/my-tool/ +# Must have: index.ts, block.ts at root level +``` diff --git a/.claude/skills/remotion-best-practices/SKILL.md b/.claude/skills/remotion-best-practices/SKILL.md new file mode 100644 index 0000000..80d72fe --- /dev/null +++ b/.claude/skills/remotion-best-practices/SKILL.md @@ -0,0 +1,43 @@ +--- +name: remotion-best-practices +description: Best practices for Remotion - Video creation in React +metadata: + tags: remotion, video, react, animation, composition +--- + +## When to use + +Use this skills whenever you are dealing with Remotion code to obtain the domain-specific knowledge. + +## How to use + +Read individual rule files for detailed explanations and code examples: + +- [rules/3d.md](rules/3d.md) - 3D content in Remotion using Three.js and React Three Fiber +- [rules/animations.md](rules/animations.md) - Fundamental animation skills for Remotion +- [rules/assets.md](rules/assets.md) - Importing images, videos, audio, and fonts into Remotion +- [rules/audio.md](rules/audio.md) - Using audio and sound in Remotion - importing, trimming, volume, speed, pitch +- [rules/calculate-metadata.md](rules/calculate-metadata.md) - Dynamically set composition duration, dimensions, and props +- [rules/can-decode.md](rules/can-decode.md) - Check if a video can be decoded by the browser using Mediabunny +- [rules/charts.md](rules/charts.md) - Chart and data visualization patterns for Remotion +- [rules/compositions.md](rules/compositions.md) - Defining compositions, stills, folders, default props and dynamic metadata +- [rules/display-captions.md](rules/display-captions.md) - Displaying captions in Remotion with TikTok-style pages and word highlighting +- [rules/extract-frames.md](rules/extract-frames.md) - Extract frames from videos at specific timestamps using Mediabunny +- [rules/fonts.md](rules/fonts.md) - Loading Google Fonts and local fonts in Remotion +- [rules/get-audio-duration.md](rules/get-audio-duration.md) - Getting the duration of an audio file in seconds with Mediabunny +- [rules/get-video-dimensions.md](rules/get-video-dimensions.md) - Getting the width and height of a video file with Mediabunny +- [rules/get-video-duration.md](rules/get-video-duration.md) - Getting the duration of a video file in seconds with Mediabunny +- [rules/gifs.md](rules/gifs.md) - Displaying GIFs synchronized with Remotion's timeline +- [rules/images.md](rules/images.md) - Embedding images in Remotion using the Img component +- [rules/import-srt-captions.md](rules/import-srt-captions.md) - Importing .srt subtitle files into Remotion using @remotion/captions +- [rules/lottie.md](rules/lottie.md) - Embedding Lottie animations in Remotion +- [rules/measuring-dom-nodes.md](rules/measuring-dom-nodes.md) - Measuring DOM element dimensions in Remotion +- [rules/measuring-text.md](rules/measuring-text.md) - Measuring text dimensions, fitting text to containers, and checking overflow +- [rules/sequencing.md](rules/sequencing.md) - Sequencing patterns for Remotion - delay, trim, limit duration of items +- [rules/tailwind.md](rules/tailwind.md) - Using TailwindCSS in Remotion +- [rules/text-animations.md](rules/text-animations.md) - Typography and text animation patterns for Remotion +- [rules/timing.md](rules/timing.md) - Interpolation curves in Remotion - linear, easing, spring animations +- [rules/transcribe-captions.md](rules/transcribe-captions.md) - Transcribing audio to generate captions in Remotion +- [rules/transitions.md](rules/transitions.md) - Scene transition patterns for Remotion +- [rules/trimming.md](rules/trimming.md) - Trimming patterns for Remotion - cut the beginning or end of animations +- [rules/videos.md](rules/videos.md) - Embedding videos in Remotion - trimming, volume, speed, looping, pitch diff --git a/.claude/skills/remotion-best-practices/rules/3d.md b/.claude/skills/remotion-best-practices/rules/3d.md new file mode 100644 index 0000000..31fa5c6 --- /dev/null +++ b/.claude/skills/remotion-best-practices/rules/3d.md @@ -0,0 +1,86 @@ +--- +name: 3d +description: 3D content in Remotion using Three.js and React Three Fiber. +metadata: + tags: 3d, three, threejs +--- + +# Using Three.js and React Three Fiber in Remotion + +Follow React Three Fiber and Three.js best practices. +Only the following Remotion-specific rules need to be followed: + +## Prerequisites + +First, the `@remotion/three` package needs to be installed. +If it is not, use the following command: + +```bash +npx remotion add @remotion/three # If project uses npm +bunx remotion add @remotion/three # If project uses bun +yarn remotion add @remotion/three # If project uses yarn +pnpm exec remotion add @remotion/three # If project uses pnpm +``` + +## Using ThreeCanvas + +You MUST wrap 3D content in `` and include proper lighting. +`` MUST have a `width` and `height` prop. + +```tsx +import { ThreeCanvas } from "@remotion/three"; +import { useVideoConfig } from "remotion"; + +const { width, height } = useVideoConfig(); + + + + + + + + + +``` + +## No animations not driven by `useCurrentFrame()` + +Shaders, models etc MUST NOT animate by themselves. +No animations are allowed unless they are driven by `useCurrentFrame()`. +Otherwise, it will cause flickering during rendering. + +Using `useFrame()` from `@react-three/fiber` is forbidden. + +## Animate using `useCurrentFrame()` + +Use `useCurrentFrame()` to perform animations. + +```tsx +const frame = useCurrentFrame(); +const rotationY = frame * 0.02; + + + + + +``` + +## Using `` inside `` + +The `layout` prop of any `` inside a `` must be set to `none`. + +```tsx +import { Sequence } from "remotion"; +import { ThreeCanvas } from "@remotion/three"; + +const { width, height } = useVideoConfig(); + + + + + + + + + +``` \ No newline at end of file diff --git a/.claude/skills/remotion-best-practices/rules/animations.md b/.claude/skills/remotion-best-practices/rules/animations.md new file mode 100644 index 0000000..7e15623 --- /dev/null +++ b/.claude/skills/remotion-best-practices/rules/animations.md @@ -0,0 +1,29 @@ +--- +name: animations +description: Fundamental animation skills for Remotion +metadata: + tags: animations, transitions, frames, useCurrentFrame +--- + +All animations MUST be driven by the `useCurrentFrame()` hook. +Write animations in seconds and multiply them by the `fps` value from `useVideoConfig()`. + +```tsx +import { useCurrentFrame } from "remotion"; + +export const FadeIn = () => { + const frame = useCurrentFrame(); + const { fps } = useVideoConfig(); + + const opacity = interpolate(frame, [0, 2 * fps], [0, 1], { + extrapolateRight: 'clamp', + }); + + return ( +
Hello World!
+ ); +}; +``` + +CSS transitions or animations are FORBIDDEN - they will not render correctly. +Tailwind animation class names are FORBIDDEN - they will not render correctly. \ No newline at end of file diff --git a/.claude/skills/remotion-best-practices/rules/assets.md b/.claude/skills/remotion-best-practices/rules/assets.md new file mode 100644 index 0000000..04c8ad5 --- /dev/null +++ b/.claude/skills/remotion-best-practices/rules/assets.md @@ -0,0 +1,78 @@ +--- +name: assets +description: Importing images, videos, audio, and fonts into Remotion +metadata: + tags: assets, staticFile, images, fonts, public +--- + +# Importing assets in Remotion + +## The public folder + +Place assets in the `public/` folder at your project root. + +## Using staticFile() + +You MUST use `staticFile()` to reference files from the `public/` folder: + +```tsx +import {Img, staticFile} from 'remotion'; + +export const MyComposition = () => { + return ; +}; +``` + +The function returns an encoded URL that works correctly when deploying to subdirectories. + +## Using with components + +**Images:** + +```tsx +import {Img, staticFile} from 'remotion'; + +; +``` + +**Videos:** + +```tsx +import {Video} from '@remotion/media'; +import {staticFile} from 'remotion'; + +