skills/claudish-integration/SKILL.md
# Claudish Integration Skill **Version:** 1.0.0 **Purpose:** Guide agents on how to query Claudish for OpenRouter model recommendations **Status:** Production Ready ## Overview This skill provides **standardized patterns** for Claude Code agents and commands to query Claudish for model recommendations. Instead of maintaining duplicate model lists, agents should query Claudish as the **single source of truth** for OpenRouter model data. **Key Principle:** Claudish owns the model list, agents
npx skillsauth add madappgang/claude-code skills/claudish-integrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Version: 1.0.0 Purpose: Guide agents on how to query Claudish for OpenRouter model recommendations Status: Production Ready
This skill provides standardized patterns for Claude Code agents and commands to query Claudish for model recommendations. Instead of maintaining duplicate model lists, agents should query Claudish as the single source of truth for OpenRouter model data.
Key Principle: Claudish owns the model list, agents query it dynamically.
Use this skill when:
/review)Do NOT use this skill when:
Use Case: Get complete model list for selection UI
Implementation:
// Execute Claudish to get model list
const { stdout } = await Bash("claudish --top-models --json");
// Parse JSON output
const modelData = JSON.parse(stdout);
// Access models
const models = modelData.models; // Array of model objects
// Example: Extract model IDs
const modelIds = models.map(m => m.id);
// Result: ["x-ai/grok-code-fast-1", "minimax/minimax-m2", ...]
Expected Output:
{
"version": "1.1.5",
"lastUpdated": "2025-11-16",
"source": "shared/recommended-models.md",
"models": [
{
"id": "x-ai/grok-code-fast-1",
"name": "Grok Code Fast 1",
"description": "Ultra-fast agentic coding with visible reasoning traces",
"provider": "xAI",
"category": "coding",
"priority": 1,
"pricing": {
"input": "$0.20/1M",
"output": "$1.50/1M",
"average": "$0.85/1M"
},
"context": "256K",
"recommended": true
}
// ... more models
]
}
Use Case: Get models for specific use case (coding, reasoning, vision, budget)
Categories:
coding - Fast coding models (Grok, MiniMax)reasoning - Advanced reasoning models (GPT-5, Gemini)vision - Multimodal models (Qwen)budget - Free or low-cost models (Polaris)all - All models (default)Implementation:
// Get coding models only
const { stdout } = await Bash("claudish --models coding --json");
const modelData = JSON.parse(stdout);
// Models are pre-filtered by Claudish
const codingModels = modelData.models;
// Result: Only models with category === "coding"
Example: Get Best Coding Model
const { stdout } = await Bash("claudish --models coding --json");
const modelData = JSON.parse(stdout);
// First model is highest priority (sorted by priority field)
const bestCodingModel = modelData.models[0];
console.log(`Best coding model: ${bestCodingModel.id}`);
// Output: Best coding model: x-ai/grok-code-fast-1
Use Case: Allow users to specify preferred models in project configuration
CLAUDE.md Format:
## Claudish Configuration
**Recommended Models for Code Review:**
- x-ai/grok-code-fast-1
- google/gemini-2.5-flash
- openai/gpt-5.1-codex
**Model Categories:**
- coding: grok, minimax
- reasoning: gpt-5, gemini
Implementation:
async function getRecommendedModels() {
// 1. Check for user override in CLAUDE.md
const userModels = await readUserOverrideFromClaudeMd();
if (userModels) {
console.log("Using models from CLAUDE.md");
return userModels;
}
// 2. Query Claudish for defaults
const { stdout } = await Bash("claudish --models coding --json");
const modelData = JSON.parse(stdout);
return modelData.models;
}
async function readUserOverrideFromClaudeMd(): Promise<Model[] | null> {
try {
const claudeMd = await Read({ file_path: "/full/path/to/CLAUDE.md" });
// Look for "Recommended Models for Code Review:" section
const match = claudeMd.match(/Recommended Models for Code Review:(.*?)(?=\n\n|$)/s);
if (!match) return null;
// Extract model IDs
const modelIds = match[1]
.split("\n")
.filter(line => line.trim().startsWith("-"))
.map(line => line.replace(/^-\s*/, "").trim());
if (modelIds.length === 0) return null;
// Query Claudish for details on these specific models
const { stdout } = await Bash("claudish --top-models --json");
const modelData = JSON.parse(stdout);
// Filter to user-specified models
return modelData.models.filter(m => modelIds.includes(m.id));
} catch (error) {
console.warn("Could not read CLAUDE.md:", error.message);
return null;
}
}
Use Case: Handle errors when Claudish is not available
Implementation:
// Define embedded defaults as fallback
const EMBEDDED_DEFAULT_MODELS = [
{
id: "x-ai/grok-code-fast-1",
name: "Grok Code Fast 1",
description: "Ultra-fast agentic coding",
category: "coding",
priority: 1
},
{
id: "google/gemini-2.5-flash",
name: "Gemini 2.5 Flash",
description: "State-of-the-art reasoning and coding",
category: "reasoning",
priority: 2
},
{
id: "openai/gpt-5.1-codex",
name: "GPT-5.1 Codex",
description: "Specialized for software engineering",
category: "reasoning",
priority: 3
}
];
async function getRecommendedModels() {
// 1. Check for user override
const userModels = await readUserOverrideFromClaudeMd();
if (userModels) return userModels;
// 2. Try querying Claudish
try {
const { stdout } = await Bash("claudish --top-models --json");
const modelData = JSON.parse(stdout);
return modelData.models;
} catch (error) {
// 3. Graceful fallback
console.warn("Could not query Claudish, using embedded defaults");
console.warn(`Reason: ${error.message}`);
return EMBEDDED_DEFAULT_MODELS;
}
}
Use Case: Check if Claudish supports JSON output (v1.2.0+)
Implementation:
async function checkClaudishVersion(): Promise<{ major: number; minor: number; patch: number } | null> {
try {
const { stdout } = await Bash("claudish --version");
const match = stdout.match(/(\d+)\.(\d+)\.(\d+)/);
if (!match) return null;
return {
major: parseInt(match[1]),
minor: parseInt(match[2]),
patch: parseInt(match[3])
};
} catch {
return null;
}
}
async function isClaudishJsonSupported(): Promise<boolean> {
const version = await checkClaudishVersion();
if (!version) {
console.warn("Claudish not found");
return false;
}
// JSON support added in 1.2.0
const isSupported = version.major >= 1 && version.minor >= 2;
if (!isSupported) {
console.warn(`Claudish v${version.major}.${version.minor}.${version.patch} detected`);
console.warn("JSON output requires Claudish v1.2.0+");
console.warn("Upgrade: npm install -g claudish@latest");
}
return isSupported;
}
async function getRecommendedModels() {
// Check Claudish version before querying
const jsonSupported = await isClaudishJsonSupported();
if (!jsonSupported) {
console.warn("Falling back to embedded defaults");
return EMBEDDED_DEFAULT_MODELS;
}
// Proceed with JSON query
const { stdout } = await Bash("claudish --top-models --json");
return JSON.parse(stdout).models;
}
Use Case: /review command selects multiple models for parallel code review
Implementation:
async function selectModelsForReview() {
// Step 1: Get available models
const availableModels = await getRecommendedModels(); // Uses patterns above
// Step 2: Filter to coding/reasoning models
const suitableModels = availableModels.filter(m =>
m.category === "coding" || m.category === "reasoning"
);
// Step 3: Present selection UI to user (example)
console.log("\nAvailable models for code review:\n");
suitableModels.forEach((model, index) => {
console.log(`${index + 1}. ${model.name}`);
console.log(` ${model.description}`);
console.log(` Category: ${model.category} | Cost: ${model.pricing.average}\n`);
});
// Step 4: User selects models (implementation depends on command)
const selectedIndices = await promptUserForSelection();
// Step 5: Return selected models
return selectedIndices.map(i => suitableModels[i]);
}
async function getRecommendedModels() {
// 1. User override
const userModels = await readUserOverrideFromClaudeMd();
if (userModels) return userModels;
// 2. Claudish query (with version check)
const jsonSupported = await isClaudishJsonSupported();
if (jsonSupported) {
try {
const { stdout } = await Bash("claudish --top-models --json");
return JSON.parse(stdout).models;
} catch (error) {
console.warn("Claudish query failed:", error.message);
}
}
// 3. Fallback
console.warn("Using embedded default models");
return EMBEDDED_DEFAULT_MODELS;
}
Detection:
try {
await Bash("which claudish");
} catch {
console.warn("Claudish not installed");
}
Fallback:
console.warn("Claudish not found. Using embedded default models.");
console.warn("To use dynamic model lists, install: npm install -g claudish");
return EMBEDDED_DEFAULT_MODELS;
Detection:
const version = await checkClaudishVersion();
const isOld = version && (version.major < 1 || version.minor < 2);
Fallback:
console.warn(`Claudish v${version.major}.${version.minor}.${version.patch} detected`);
console.warn("JSON output requires v1.2.0+");
console.warn("Upgrade: npm install -g claudish@latest");
console.warn("Falling back to embedded defaults");
return EMBEDDED_DEFAULT_MODELS;
Detection:
try {
const data = JSON.parse(stdout);
} catch (error) {
console.error("Invalid JSON from Claudish:", error.message);
}
Fallback:
console.error("Could not parse Claudish output");
console.error("Expected JSON format from: claudish --top-models --json");
console.warn("Falling back to embedded defaults");
return EMBEDDED_DEFAULT_MODELS;
Detection:
const data = JSON.parse(stdout);
if (!data.models || data.models.length === 0) {
console.warn("No models returned from Claudish");
}
Fallback:
console.warn("Claudish returned empty model list");
console.warn("Try: claudish --models --force-update");
console.warn("Falling back to embedded defaults");
return EMBEDDED_DEFAULT_MODELS;
Detection:
try {
const { stdout } = await Bash("claudish --top-models --json");
} catch (error) {
console.error("Failed to execute Claudish:", error.message);
}
Fallback:
console.error("Could not execute: claudish --top-models --json");
console.error(`Error: ${error.message}`);
console.warn("Falling back to embedded defaults");
return EMBEDDED_DEFAULT_MODELS;
Why: Graceful degradation when Claudish unavailable
How:
const EMBEDDED_DEFAULT_MODELS = [
// Minimum viable model list
{ id: "x-ai/grok-code-fast-1", name: "Grok", category: "coding" },
{ id: "google/gemini-2.5-flash", name: "Gemini", category: "reasoning" },
{ id: "openai/gpt-5.1-codex", name: "GPT-5 Codex", category: "reasoning" }
];
Why: Avoid errors with old Claudish versions
How:
const jsonSupported = await isClaudishJsonSupported();
if (!jsonSupported) {
return EMBEDDED_DEFAULT_MODELS;
}
Why: Give users control over model selection
How:
// Always check CLAUDE.md first
const userModels = await readUserOverrideFromClaudeMd();
if (userModels) return userModels;
Why: Help users understand and fix issues
How:
console.warn("Could not query Claudish, using embedded defaults");
console.warn("To fix: npm install -g claudish@latest");
Why: Avoid repeated Claudish queries in same session
How:
let _cachedModels: Model[] | null = null;
async function getRecommendedModels() {
if (_cachedModels) {
return _cachedModels;
}
// Query Claudish...
const models = await queryClaudish();
_cachedModels = models;
return models;
}
Why: Get relevant models only, faster response
How:
// Get coding models only (don't filter manually)
const { stdout } = await Bash("claudish --models coding --json");
const models = JSON.parse(stdout).models;
// All models are already filtered to category === "coding"
Wrong:
// Parsing text output is fragile and error-prone
const { stdout } = await Bash("claudish --top-models");
const lines = stdout.split("\n");
// ... complex parsing logic ...
Right:
// Use JSON output instead
const { stdout } = await Bash("claudish --top-models --json");
const models = JSON.parse(stdout).models;
Wrong:
// No error handling - will crash if Claudish not found
const { stdout } = await Bash("claudish --top-models --json");
const models = JSON.parse(stdout).models;
Right:
// Graceful fallback
try {
const { stdout } = await Bash("claudish --top-models --json");
return JSON.parse(stdout).models;
} catch {
return EMBEDDED_DEFAULT_MODELS;
}
Wrong:
// Hardcoded list that duplicates Claudish data
const MODELS = [
"x-ai/grok-code-fast-1",
"minimax/minimax-m2",
"google/gemini-2.5-flash",
// ... 20 more models ...
];
Right:
// Query Claudish dynamically, with minimal embedded fallback
const models = await getRecommendedModels(); // Queries Claudish
// EMBEDDED_DEFAULT_MODELS is minimal (3-5 models max)
Wrong:
// Assumes --json flag exists (added in v1.2.0)
const { stdout } = await Bash("claudish --top-models --json");
Right:
// Check version first
const jsonSupported = await isClaudishJsonSupported();
if (!jsonSupported) {
return EMBEDDED_DEFAULT_MODELS;
}
const { stdout } = await Bash("claudish --top-models --json");
Wrong:
// Get all models, then filter manually (inefficient)
const { stdout } = await Bash("claudish --top-models --json");
const allModels = JSON.parse(stdout).models;
const codingModels = allModels.filter(m => m.category === "coding");
Right:
// Let Claudish filter (more efficient)
const { stdout } = await Bash("claudish --models coding --json");
const codingModels = JSON.parse(stdout).models;
import { describe, it, expect } from "bun:test";
describe("Claudish Integration", () => {
it("should query Claudish and parse JSON", async () => {
const models = await getRecommendedModels();
expect(models).toBeDefined();
expect(Array.isArray(models)).toBe(true);
expect(models.length).toBeGreaterThan(0);
const model = models[0];
expect(model).toHaveProperty("id");
expect(model).toHaveProperty("name");
expect(model).toHaveProperty("category");
});
it("should fall back to embedded defaults if Claudish fails", async () => {
// Mock Bash to throw error
const originalBash = global.Bash;
global.Bash = async () => { throw new Error("Command not found"); };
const models = await getRecommendedModels();
expect(models).toEqual(EMBEDDED_DEFAULT_MODELS);
// Restore
global.Bash = originalBash;
});
it("should filter by category", async () => {
const models = await getRecommendedModelsByCategory("coding");
expect(models.every(m => m.category === "coding")).toBe(true);
});
});
import { describe, it, expect } from "bun:test";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
describe("Claudish CLI Integration", () => {
it("should execute claudish --top-models --json", async () => {
const { stdout } = await execAsync("claudish --top-models --json");
const data = JSON.parse(stdout);
expect(data).toHaveProperty("models");
expect(data.models.length).toBeGreaterThan(0);
});
it("should filter by category via CLI", async () => {
const { stdout } = await execAsync("claudish --models coding --json");
const data = JSON.parse(stdout);
expect(data.models.every(m => m.category === "coding")).toBe(true);
});
});
// Old pattern: Hardcoded model list
const REVIEW_MODELS = [
"x-ai/grok-code-fast-1",
"google/gemini-2.5-flash",
"openai/gpt-5.1-codex"
];
function getModelsForReview() {
return REVIEW_MODELS;
}
// New pattern: Query Claudish dynamically
const EMBEDDED_DEFAULT_MODELS = [
{ id: "x-ai/grok-code-fast-1", name: "Grok", category: "coding" },
{ id: "google/gemini-2.5-flash", name: "Gemini", category: "reasoning" }
];
async function getModelsForReview() {
// 1. User override
const userModels = await readUserOverrideFromClaudeMd();
if (userModels) return userModels;
// 2. Claudish query
try {
const { stdout } = await Bash("claudish --models coding --json");
return JSON.parse(stdout).models;
} catch {
// 3. Fallback
return EMBEDDED_DEFAULT_MODELS;
}
}
Benefits:
Related Documents:
ai-docs/CLAUDISH_INTEGRATION_ARCHITECTURE.md - Overall architectureai-docs/CLAUDISH_ENHANCEMENT_PROPOSAL.md - Claudish feature specClaudish Version Requirements:
External Resources:
npm install -g claudishtesting
A test skill for validation testing. Use when testing skill parsing and validation logic.
tools
--- name: bad-skill description: This skill has invalid YAML in frontmatter allowed-tools: [invalid, array, syntax prerequisites: not-an-array --- # Bad Skill This skill has malformed frontmatter that should fail parsing. The YAML has: - Unclosed array bracket - Wrong type for prerequisites (should be array, not string)
tools
Plugin release process for MAG Claude Plugins marketplace. Covers version bumping, marketplace.json updates, git tagging, and common mistakes. Use when releasing new plugin versions or troubleshooting update issues.
testing
Fetch trending programming models from OpenRouter rankings. Use when selecting models for multi-model review, updating model recommendations, or researching current AI coding trends. Provides model IDs, context windows, pricing, and usage statistics from the most recent week.