Skip to content
Merged
79 changes: 70 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ The recommended way to create new provider skills is using our AI-powered genera

- **Node.js 18+**
- **Python 3.9+** (for FastAPI examples)
- **[Claude CLI](https://docs.anthropic.com/en/docs/claude-cli)** — Install and authenticate with `claude login`
- **AI CLI Tool** — One of the following:
- [Claude CLI](https://docs.anthropic.com/en/docs/claude-cli) — Install and authenticate with `claude login` (default)
- [Copilot CLI](https://docs.github.com/en/copilot/how-tos/use-copilot-for-common-tasks/use-copilot-in-the-cli) — GitHub Copilot command-line tool
- **GITHUB_TOKEN** — For PR creation (optional but recommended)

```bash
Expand Down Expand Up @@ -182,13 +184,20 @@ providers:

By default, all providers run in parallel. Use `--parallel <n>` to limit concurrency.

### 4. Preview What Would Happen (Dry Run)
### 4. Use a Different CLI Tool

```bash
# Use Copilot instead of Claude
./scripts/generate-skills.sh generate "twilio" --cli copilot --create-pr
```

### 5. Preview What Would Happen (Dry Run)

```bash
./scripts/generate-skills.sh generate "linear" --dry-run
```

### 5. Resume After a Failed Generation
### 6. Resume After a Failed Generation

If generation fails (tests won't pass, API timeout, etc.), the worktree is preserved:

Expand All @@ -208,7 +217,7 @@ The review command will:
3. AI reviews and fixes any issues
4. If within thresholds, pushes and creates PR

### 6. Update an Existing Skill
### 7. Update an Existing Skill

Use the review command to improve skills already in the repository:

Expand Down Expand Up @@ -236,7 +245,7 @@ providers:
Verify signature verification is current with latest SDK.
```

### 7. Manual Review and PR Creation
### 8. Manual Review and PR Creation

```bash
# Generate without PR - inspect results first
Expand All @@ -256,7 +265,7 @@ gh pr create --title "feat: add clerk-webhooks skill"

When creating or updating a PR, use the title and description format in the next section.

### 8. Pull Request Title and Description
### 9. Pull Request Title and Description

Use these conventions so PRs are consistent and easy to review.

Expand Down Expand Up @@ -284,7 +293,7 @@ Use these conventions so PRs are consistent and easy to review.

For generator-created PRs, the body may also include **Generation details** (provider, tests passed, review passed, iterations, issues found/fixed). When editing an existing PR (e.g. after review), update the title and description to match these conventions if they don't already.

### 9. Clean Up Worktrees
### 10. Clean Up Worktrees

```bash
# List all worktrees
Expand Down Expand Up @@ -316,11 +325,12 @@ rm -rf .worktrees && git worktree prune

| Option | Description | Default |
|--------|-------------|---------|
| `--cli <tool>` | CLI tool to use (`claude`, `copilot`) | claude |
| `--working-dir <path>` | Generate in specific directory (skip worktree) | Creates worktree |
| `--no-worktree` | Generate in current directory (shorthand for `--working-dir .`) | Creates worktree |
| `--create-pr [type]` | Push and create PR (`true` or `draft`) | No PR |
| `--parallel <n>` | Max concurrent generations | All providers |
| `--model <model>` | Claude model | claude-opus-4-20250514 |
| `--model <model>` | Model to use | claude-opus-4-20250514 |
| `--max-iterations <n>` | Max test/fix cycles | 3 |
| `--base-branch <branch>` | Branch to create from | main |
| `--skip-tests` | Skip test execution | false |
Expand All @@ -338,18 +348,69 @@ rm -rf .worktrees && git worktree prune

| Option | Description | Default |
|--------|-------------|---------|
| `--cli <tool>` | CLI tool to use (`claude`, `copilot`) | claude |
| `--working-dir <path>` | Review in specific directory (skip worktree) | Creates worktree |
| `--no-worktree` | Review in current directory (shorthand for `--working-dir .`) | Creates worktree |
| `--create-pr [type]` | Create PR with fixes | No PR |
| `--max-iterations <n>` | Max fix cycles | 3 |
| `--parallel <n>` | Max concurrent reviews | All providers |
| `--model <model>` | Claude model | claude-opus-4-20250514 |
| `--model <model>` | Model to use | claude-opus-4-20250514 |
| `--branch-prefix <prefix>` | Branch name prefix | improve |
| `--config <file>` | YAML config file | — |
| `--dry-run` | Preview without executing | false |

---

## Adding New CLI Tools

The generator supports a pluggable CLI adapter system. To add support for a new AI CLI tool:

1. **Create an adapter file** at `scripts/skill-generator/lib/cli-adapters/<tool>.ts`:

```typescript
import type { CliAdapter, CliAdapterOptions, CliCommandConfig } from './types';

const DEFAULT_MODEL = 'your-model-name-here';
export const myToolAdapter: CliAdapter = {
name: 'mytool',

buildCommand(options: CliAdapterOptions): CliCommandConfig {
const model = options.model ?? DEFAULT_MODEL;

return {
command: 'mytool', // The CLI command to execute
args: [
// Arguments specific to this CLI tool
'--model', model,
'--some-flag',
],
};
},
};
```

2. **Register the adapter** in `scripts/skill-generator/lib/cli-adapters/index.ts`:

```typescript
import { myToolAdapter } from './mytool';

const adapters: Map<string, CliAdapter> = new Map([
['claude', claudeAdapter],
['copilot', copilotAdapter],
['mytool', myToolAdapter], // Add your adapter here
]);
```

3. **Use it** with the `--cli` flag:

```bash
./scripts/generate-skills.sh generate stripe --cli mytool
```

The adapter interface is simple — it just needs to return the command name and arguments. The generator handles stdin prompt passing, timeout, progress display, and output capture.

---

## Manual Contribution

Prefer to write code yourself? Follow these steps.
Expand Down
18 changes: 14 additions & 4 deletions scripts/skill-generator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import type {
import { mergeProviderConfigs, skillExists } from './lib/config';
import { generateSkill } from './lib/generator';
import { reviewExistingSkill } from './lib/reviewer';
import { DEFAULT_MODEL, setCachedVersions } from './lib/claude';
import { setCachedVersions } from './lib/cli';
import { DEFAULT_CLI_TOOL, AVAILABLE_CLI_TOOLS } from './lib/cli-adapters';
import { getLatestVersions } from './lib/versions';
import {
createWorktree,
Expand Down Expand Up @@ -143,6 +144,7 @@ async function handleGenerate(
maxIterations: string;
createPr: boolean | string;
model: string;
cli: string;
workingDir?: string; // Generate in this directory (skip worktree creation)
worktree?: boolean; // Set to false by --no-worktree flag
}
Expand Down Expand Up @@ -186,6 +188,7 @@ async function handleGenerate(
: providerConfigs.length;

console.log(chalk.blue(`Providers (${providerConfigs.length}): ${providerConfigs.map(p => p.name).join(', ')}`));
console.log(chalk.blue(`CLI tool: ${options.cli}`));
console.log(chalk.blue(`Model: ${options.model}`));
if (!useProvidedDir && providerConfigs.length > 1) {
console.log(chalk.blue(`Parallel: ${parallelCount}`));
Expand All @@ -206,6 +209,7 @@ async function handleGenerate(
maxIterations: parseInt(options.maxIterations, 10),
createPr: normalizeCreatePr(options.createPr),
model: options.model,
cliTool: options.cli,
};

const { dir: resultsDir } = createResultsDir();
Expand Down Expand Up @@ -398,6 +402,7 @@ async function handleReview(
createPr: boolean | string;
branchPrefix: string;
model: string;
cli: string;
workingDir?: string; // Review in this directory (any git checkout, worktree, or local path)
worktree?: boolean; // Set to false by --no-worktree flag
}
Expand Down Expand Up @@ -473,6 +478,7 @@ async function handleReview(
: existingProviders.length;

console.log(chalk.blue(`Providers: ${existingProviders.map(p => p.name).join(', ')}`));
console.log(chalk.blue(`CLI tool: ${options.cli}`));
console.log(chalk.blue(`Model: ${options.model}`));
if (!useProvidedDir && existingProviders.length > 1) {
console.log(chalk.blue(`Parallel: ${parallelCount}`));
Expand All @@ -488,6 +494,7 @@ async function handleReview(
createPr: normalizeCreatePr(options.createPr),
branchPrefix: options.branchPrefix,
model: options.model,
cliTool: options.cli,
};

const { dir: resultsDir } = createResultsDir();
Expand Down Expand Up @@ -664,6 +671,7 @@ async function handleReview(
dryRun: reviewOptions.dryRun,
maxIterations: reviewOptions.maxIterations,
model: reviewOptions.model,
cliTool: reviewOptions.cliTool,
parallel: existingProviders.length > 1,
});

Expand Down Expand Up @@ -825,15 +833,16 @@ const program = new Command();

program
.name('skill-generator')
.description('Generate and review webhook skills using Claude CLI')
.description('Generate and review webhook skills using AI CLI tools')
.version('1.0.0');

program
.command('generate')
.description('Generate new webhook skills')
.argument('[providers...]', 'Provider names, or provider=url, or provider=url|notes (e.g. elevenlabs=https://github.com/elevenlabs/elevenlabs-js|Official SDK supports webhook verification)')
.option('--config <file>', 'Load provider configs from YAML file')
.option('--model <model>', 'Claude model to use', DEFAULT_MODEL)
.option('--cli <tool>', `CLI tool to use (${AVAILABLE_CLI_TOOLS.join(', ')})`, DEFAULT_CLI_TOOL)
.option('--model <model>', "Model to use (defaults to CLI tool's default model)", undefined)
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The help text states 'defaults to CLI tool's default model', but doesn't indicate what those defaults are. Consider mentioning that Claude defaults to 'claude-opus-4-20250514' and Copilot to 'gpt-4o', or link to documentation where users can find this information.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can assume folks know how to find the model for their given CLI.

.option('--parallel <n>', 'Max concurrent agents (default: all providers)')
.option('--dry-run', 'Show what would be done without executing', false)
.option('--base-branch <branch>', 'Branch to create from', 'main')
Expand All @@ -850,7 +859,8 @@ program
.description('Review and improve existing webhook skills')
.argument('[providers...]', 'Provider names, or provider=url, or provider=url|notes (e.g. elevenlabs=https://.../elevenlabs-js|Prefer SDK verification in skill)')
.option('--config <file>', 'Load provider configs from YAML file')
.option('--model <model>', 'Claude model to use', DEFAULT_MODEL)
.option('--cli <tool>', `CLI tool to use (${AVAILABLE_CLI_TOOLS.join(', ')})`, DEFAULT_CLI_TOOL)
.option('--model <model>', "Model to use (defaults to CLI tool's default model)", undefined)
.option('--parallel <n>', 'Max concurrent agents (default: all providers)')
.option('--dry-run', 'Show what would be done without executing', false)
.option('--max-iterations <n>', 'Max review/fix cycles', '3')
Expand Down
27 changes: 27 additions & 0 deletions scripts/skill-generator/lib/cli-adapters/claude.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Claude CLI adapter
*
* Supports the Anthropic Claude CLI tool
* https://github.com/anthropics/claude-cli
*/

import type { CliAdapter, CliAdapterOptions, CliCommandConfig } from './types';

const DEFAULT_MODEL = 'claude-opus-4-20250514';
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFAULT_MODEL needs to be exported from this file since it's imported by cli-adapters/index.ts. Change const DEFAULT_MODEL to export const DEFAULT_MODEL to fix the import error.

Suggested change
const DEFAULT_MODEL = 'claude-opus-4-20250514';
export const DEFAULT_MODEL = 'claude-opus-4-20250514';

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not applicable any more.


export const claudeAdapter: CliAdapter = {
name: 'claude',

buildCommand(options: CliAdapterOptions): CliCommandConfig {
const model = options.model ?? DEFAULT_MODEL;

return {
command: 'claude',
args: [
'-p',
'--model', model,
'--dangerously-skip-permissions',
],
};
},
};
27 changes: 27 additions & 0 deletions scripts/skill-generator/lib/cli-adapters/copilot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copilot CLI adapter
*
* Supports the GitHub Copilot CLI tool
*/

import type { CliAdapter, CliAdapterOptions, CliCommandConfig } from './types';

// Default model for the GitHub Copilot CLI; can be overridden via options.model
const DEFAULT_MODEL = 'gpt-4o';

export const copilotAdapter: CliAdapter = {
name: 'copilot',

buildCommand(options: CliAdapterOptions): CliCommandConfig {
const model = options.model ?? DEFAULT_MODEL;

return {
command: 'copilot',
args: [
// Note: copilot does not use -p flag
'--model', model,
'--allow-all-tools',
],
};
},
};
48 changes: 48 additions & 0 deletions scripts/skill-generator/lib/cli-adapters/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* CLI Adapter factory
*
* Registry and factory for CLI adapters
*/

import type { CliAdapter } from './types';
import { claudeAdapter } from './claude';
import { copilotAdapter } from './copilot';

// Re-export types
export type { CliAdapter, CliAdapterOptions, CliCommandConfig } from './types';

/**
* Registry of available CLI adapters
*/
const adapters: Map<string, CliAdapter> = new Map([
['claude', claudeAdapter],
['copilot', copilotAdapter],
]);

/**
* List of available CLI tool names (for help text and validation)
*/
export const AVAILABLE_CLI_TOOLS = Array.from(adapters.keys());

/**
* Default CLI tool to use
*/
export const DEFAULT_CLI_TOOL = 'claude';

/**
* Get a CLI adapter by name
*
* @param name - The name of the CLI tool (e.g., 'claude', 'copilot')
* @returns The CLI adapter
* @throws Error if the adapter is not found
*/
export function getCliAdapter(name: string): CliAdapter {
const adapter = adapters.get(name);

if (!adapter) {
const available = AVAILABLE_CLI_TOOLS.join(', ');
throw new Error(`Unknown CLI tool: '${name}'. Available tools: ${available}`);
}

return adapter;
}
29 changes: 29 additions & 0 deletions scripts/skill-generator/lib/cli-adapters/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* CLI Adapter types for supporting multiple AI CLI tools
*/

/**
* Options passed to the adapter when building the command
*/
export interface CliAdapterOptions {
model?: string;
}

/**
* The command configuration returned by an adapter
*/
export interface CliCommandConfig {
command: string;
args: string[];
}

/**
* Interface that all CLI adapters must implement
*/
export interface CliAdapter {
/** Unique identifier for this CLI tool */
name: string;

/** Build the command and arguments for executing the CLI */
buildCommand(options: CliAdapterOptions): CliCommandConfig;
}
Loading