Get the FREE Ultimate OpenClaw Setup Guide →

dev-buddy-manage-presets

npx machina-cli add skill Z-M-Huang/vcp/dev-buddy-manage-presets --openclaw
Files (1)
SKILL.md
5.9 KB

Manage AI Provider Presets

Manage the AI provider presets stored at ~/.vcp/ai-presets.json. Presets configure which AI providers are used for each pipeline stage in dev-buddy.

Supported Operations

List Presets

Read and display all configured presets. Provider credentials are shown masked (last 4 characters only).

bun -e "
const { readPresets, maskPresetKeys } = await import('${CLAUDE_PLUGIN_ROOT}/scripts/preset-utils.ts');
const config = readPresets();
for (const [name, preset] of Object.entries(config.presets)) {
  const masked = maskPresetKeys(preset);
  console.log(JSON.stringify({ name, ...masked }, null, 2));
}
"

Add a Preset

Add a new preset by name. The type determines which fields are required:

  • api: base_url, api_key (provider credential), models (array) are required
  • subscription: Only name is required (uses Task tool)
  • cli: command, args_template (must contain {model}, {prompt}, {output_file}), and models are required. Optional: one_shot_args_template (for /dev-buddy-once, must contain {model} and {prompt})

Example — add an API preset. Replace YOUR_PROVIDER_KEY with your actual credential:

bun -e "
const { readPresets, writePresets, validatePreset } = await import('${CLAUDE_PLUGIN_ROOT}/scripts/preset-utils.ts');
const config = readPresets();
const newPreset = {
  type: 'api',
  name: 'OpenRouter',
  description: 'OpenRouter API gateway',
  base_url: 'https://openrouter.ai/api/v1',
  api_key: process.env.OPENROUTER_KEY || 'YOUR_PROVIDER_KEY',
  models: ['anthropic/claude-sonnet-4-5', 'anthropic/claude-opus-4']
};
validatePreset(newPreset);
config.presets['openrouter'] = newPreset;
writePresets(config);
console.log('Preset added: openrouter');
"

Example — add a subscription preset:

bun -e "
const { readPresets, writePresets } = await import('${CLAUDE_PLUGIN_ROOT}/scripts/preset-utils.ts');
const config = readPresets();
config.presets['my-subscription'] = { type: 'subscription', name: 'My Claude Subscription' };
writePresets(config);
console.log('Preset added: my-subscription');
"

Example — add a CLI preset:

bun -e "
const { readPresets, writePresets, validatePreset } = await import('${CLAUDE_PLUGIN_ROOT}/scripts/preset-utils.ts');
const config = readPresets();
const newPreset = {
  type: 'cli',
  name: 'OpenAI Codex CLI',
  command: 'codex',
  args_template: 'exec --full-auto -m {model} -o {output_file} --output-schema {schema_path} \"{prompt}\"',
  one_shot_args_template: 'exec --full-auto -m {model} \"{prompt}\"',
  models: ['o3', 'o4-mini']
};
validatePreset(newPreset);
config.presets['codex-cli'] = newPreset;
writePresets(config);
console.log('Preset added: codex-cli');
"

Update a Preset

Modify fields on an existing preset. Always reads first, merges, then writes.

bun -e "
const { readPresets, writePresets, validatePreset } = await import('${CLAUDE_PLUGIN_ROOT}/scripts/preset-utils.ts');
const config = readPresets();
const presetName = 'openrouter';
if (!config.presets[presetName]) {
  console.error('Preset not found: ' + presetName);
  process.exit(1);
}
config.presets[presetName] = { ...config.presets[presetName], description: 'Updated description' };
validatePreset(config.presets[presetName]);
writePresets(config);
console.log('Preset updated: ' + presetName);
"

Remove a Preset

Delete a preset by name. Before removing, check if it is referenced in the pipeline config.

bun -e "
import { readPresets, writePresets } from '${CLAUDE_PLUGIN_ROOT}/scripts/preset-utils.ts';
import fs from 'fs';
import os from 'os';
import path from 'path';

const presetName = 'openrouter';

// Check format: feature_pipeline and bugfix_pipeline are arrays of {type, provider, model}
const pipelineConfigPath = path.join(os.homedir(), '.vcp', 'dev-buddy.json');
if (fs.existsSync(pipelineConfigPath)) {
  const pipelineConfig = JSON.parse(fs.readFileSync(pipelineConfigPath, 'utf-8'));
  const usedIn: string[] = [];
  const featurePipeline = pipelineConfig?.feature_pipeline || [];
  featurePipeline.forEach((stage: any, i: number) => {
    if (stage?.provider === presetName) usedIn.push('feature_pipeline[' + i + '] (' + stage.type + ')');
  });
  const bugfixPipeline = pipelineConfig?.bugfix_pipeline || [];
  bugfixPipeline.forEach((stage: any, i: number) => {
    if (stage?.provider === presetName) usedIn.push('bugfix_pipeline[' + i + '] (' + stage.type + ')');
  });
  if (usedIn.length > 0) {
    console.warn('WARNING: Preset is referenced in pipeline stages: ' + usedIn.join(', '));
    console.warn('Update the pipeline config before removing this preset.');
  }
}

const config = readPresets();
if (!config.presets[presetName]) {
  console.error('Preset not found: ' + presetName);
  process.exit(1);
}
delete config.presets[presetName];
writePresets(config);
console.log('Preset removed: ' + presetName);
"

Preset Types

TypeRequired FieldsUsage
subscriptiontype, nameUses Claude Task tool (default)
apitype, name, base_url, api_key, modelsDirect API provider
clitype, name, command, args_template, modelsCLI tool like Codex CLI. Optional: one_shot_args_template for /dev-buddy-once

Config Location

Presets are stored at: ~/.vcp/ai-presets.json

On first run, a default anthropic-subscription preset is automatically created.

Security Notes

  • Provider credentials are masked in all log output and web portal display (showing only the last 4 characters).
  • Use the web portal (/dev-buddy:config) for a visual interface with secure credential reveal functionality.
  • Prefer providing credentials via environment variables (e.g., process.env.OPENROUTER_KEY) rather than hardcoding them.

Source

git clone https://github.com/Z-M-Huang/vcp/blob/main/plugins/dev-buddy/skills/dev-buddy-manage-presets/SKILL.mdView on GitHub

Overview

This skill lets you manage the Dev Buddy AI provider presets stored at ~/.vcp/ai-presets.json. Presets determine which AI providers are used for each pipeline stage and include credentials, models, and CLI templates.

How This Skill Works

The tool reads presets with readPresets(), applies changes via writePresets() and optionally validates them with validatePreset(). Updates merge into existing presets, and removals require a safety check against pipeline references. Supported preset types (api, subscription, cli) define their required fields and usage.

When to Use It

  • Need to display all presets with credentials masked so teammates can audit configurations
  • Add a new API-based preset with base_url, api_key, and models
  • Create a subscription preset for a named plan to drive a pipeline stage
  • Modify an existing preset by merging changes and re-validating
  • Safely remove a preset after confirming it is not referenced by any pipeline

Quick Start

  1. Step 1: Use readPresets() to load current presets
  2. Step 2: Create or modify a preset object (api, subscription, or cli) and run validatePreset()
  3. Step 3: Use writePresets(config) to save changes (optionally after a merge)

Best Practices

  • Always mask credentials when listing presets (last 4 chars shown)
  • Validate new or updated presets before writing to disk using validatePreset
  • Choose clear, descriptive preset names that map to their use case
  • Before removing, check pipeline configs to avoid broken pipelines
  • Follow type-specific required fields to avoid incomplete presets (api, subscription, cli)

Example Use Cases

  • List all presets and inspect masked outputs for OpenRouter and Codex CLI
  • Add an API preset named OpenRouter with base_url, api_key, and models
  • Add a subscription preset like 'My Claude Subscription' with type 'subscription'
  • Add a CLI preset with a command, args_template containing {model}, {prompt}, {output_file}, and required models
  • Update a preset's description or fields and save with writePresets

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers