Source profileQuality 91/100

travisjneuman/.claude/skills/llm-app-development/SKILL.md

llm-app-development

LLM app development with RAG, prompt engineering, vector databases, and AI agents

Source repository stars
94
Declared platforms
0
Static risk flags
1
Last source update
2026-08-13
Source checked
2026-08-25

Decision brief

What it does: where it fits

LLM app development with RAG, prompt engineering, vector databases, and AI agents

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/travisjneuman/.claude --skill "skills/llm-app-development"
    Safe inspection promptEditorial

    Inspect the Agent Skill "llm-app-development" from https://github.com/travisjneuman/.claude/blob/b8b4dd55d61b9f25d33e3b5427870641a1c8c39c/skills/llm-app-development/SKILL.md at commit b8b4dd55d61b9f25d33e3b5427870641a1c8c39c. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Core Principles

      1. Retrieval over memorization - Use RAG to ground LLM responses in real data rather than relying on model parametric memory. This reduces hallucination and keeps answers current. 2. Structured I/O boundaries - Define strict schemas for both inputs (system prompts, context) and…

      Retrieval over memorization - Use RAG to ground LLM responses in real data rather than relying on model parametric memory. This reduces hallucination and keeps answers current.Structured I/O boundaries - Define strict schemas for both inputs (system prompts, context) and outputs (typed responses via function calling or Zod schemas). Never trust raw LLM text for downstream logic.Evaluate before shipping - Every LLM feature needs automated evaluation. Model outputs are non-deterministic; without eval, you cannot measure regressions or improvements.
    2. 02

      Key Patterns

      When to use: When the LLM needs access to private, large, or frequently updated knowledge that exceeds context window limits.

      When to use: When the LLM needs access to private, large, or frequently updated knowledge that exceeds context window limits.Why: RAG separates knowledge storage from reasoning. The LLM focuses on synthesizing answers while the vector database handles retrieval at scale. This architecture supports updating knowledge without retraining and kee…When to use: When LLM output feeds into downstream logic, APIs, or UI rendering that requires typed, validated data.
    3. 03

      Pattern 1: RAG Pipeline Architecture

      When to use: When the LLM needs access to private, large, or frequently updated knowledge that exceeds context window limits.

      When to use: When the LLM needs access to private, large, or frequently updated knowledge that exceeds context window limits.Why: RAG separates knowledge storage from reasoning. The LLM focuses on synthesizing answers while the vector database handles retrieval at scale. This architecture supports updating knowledge without retraining and kee…
    4. 04

      Pattern 2: Structured Output with Zod Schemas

      When to use: When LLM output feeds into downstream logic, APIs, or UI rendering that requires typed, validated data.

      When to use: When LLM output feeds into downstream logic, APIs, or UI rendering that requires typed, validated data.Why: Structured outputs eliminate brittle regex parsing of LLM text. The model is constrained to produce valid JSON matching your schema, giving you type-safe data for rendering UI components, storing in databases, or p…
    5. 05

      Pattern 3: Tool Use and AI Agents

      When to use: When the LLM needs to take actions (search, calculate, call APIs, modify data) rather than just generate text.

      When to use: When the LLM needs to take actions (search, calculate, call APIs, modify data) rather than just generate text.Why: Tool use transforms LLMs from text generators into actors that can query databases, call APIs, and orchestrate workflows. The agentic loop pattern gives the model autonomy to decide which tools to use and when, whi…

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 426

    The documentation includes network, browsing, or remote request actions.

    const response = await fetch("/api/chat", {

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score91/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars94SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    travisjneuman/.claude
    Skill path
    skills/llm-app-development/SKILL.md
    Commit
    b8b4dd55d61b9f25d33e3b5427870641a1c8c39c
    License
    MIT
    Collected
    2026-08-25
    Default branch
    master
    View the original SKILL.md

    LLM Application Development

    Overview

    This skill covers the full spectrum of building applications powered by large language models. It addresses retrieval-augmented generation (RAG) pipelines, vector database integration, prompt engineering techniques, structured output generation, tool use and agentic patterns, evaluation frameworks, cost optimization, and streaming response handling.

    Use this skill when building chatbots, AI assistants, knowledge retrieval systems, content generation tools, autonomous agents, or any application that integrates LLM capabilities into its core functionality.


    Core Principles

    1. Retrieval over memorization - Use RAG to ground LLM responses in real data rather than relying on model parametric memory. This reduces hallucination and keeps answers current.
    2. Structured I/O boundaries - Define strict schemas for both inputs (system prompts, context) and outputs (typed responses via function calling or Zod schemas). Never trust raw LLM text for downstream logic.
    3. Evaluate before shipping - Every LLM feature needs automated evaluation. Model outputs are non-deterministic; without eval, you cannot measure regressions or improvements.
    4. Cost-aware architecture - Token usage drives cost. Cache aggressively, choose the smallest model that meets quality requirements, and batch where possible.
    5. Fail gracefully - LLMs can refuse, hallucinate, or timeout. Every call path needs fallback behavior, retry logic, and user-visible error states.

    Key Patterns

    Pattern 1: RAG Pipeline Architecture

    When to use: When the LLM needs access to private, large, or frequently updated knowledge that exceeds context window limits.

    Implementation:

    import { OpenAIEmbeddings } from "@langchain/openai";
    import { PGVectorStore } from "@langchain/community/vectorstores/pgvector";
    import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
    
    // 1. Chunking - Split documents into retrieval-friendly segments
    const splitter = new RecursiveCharacterTextSplitter({
      chunkSize: 1000,
      chunkOverlap: 200,
      separators: ["\n\n", "\n", ". ", " "],
    });
    
    const chunks = await splitter.splitDocuments(documents);
    
    // 2. Embedding - Convert chunks to vectors
    const embeddings = new OpenAIEmbeddings({
      model: "text-embedding-3-small",
      dimensions: 1536,
    });
    
    // 3. Storage - Index in vector database
    const vectorStore = await PGVectorStore.fromDocuments(chunks, embeddings, {
      postgresConnectionOptions: {
        connectionString: process.env.DATABASE_URL,
      },
      tableName: "documents",
      columns: {
        idColumnName: "id",
        vectorColumnName: "embedding",
        contentColumnName: "content",
        metadataColumnName: "metadata",
      },
    });
    
    // 4. Retrieval - Find relevant context for a query
    async function retrieve(query: string, k: number = 5) {
      const results = await vectorStore.similaritySearchWithScore(query, k);
    
      // Filter by relevance threshold
      return results
        .filter(([_, score]) => score > 0.7)
        .map(([doc]) => doc);
    }
    
    // 5. Generation - Augment prompt with retrieved context
    async function generateAnswer(query: string): Promise<string> {
      const context = await retrieve(query);
    
      const contextText = context
        .map((doc) => doc.pageContent)
        .join("\n---\n");
    
      const response = await openai.chat.completions.create({
        model: "gpt-4o",
        messages: [
          {
            role: "system",
            content: `Answer questions using ONLY the provided context. If the context doesn't contain the answer, say "I don't have information about that."
    
    Context:
    ${contextText}`,
          },
          { role: "user", content: query },
        ],
        temperature: 0.1,
      });
    
      return response.choices[0].message.content ?? "";
    }
    

    Why: RAG separates knowledge storage from reasoning. The LLM focuses on synthesizing answers while the vector database handles retrieval at scale. This architecture supports updating knowledge without retraining and keeps token costs manageable by only including relevant context.


    Pattern 2: Structured Output with Zod Schemas

    When to use: When LLM output feeds into downstream logic, APIs, or UI rendering that requires typed, validated data.

    Implementation:

    import { z } from "zod";
    import OpenAI from "openai";
    import { zodResponseFormat } from "openai/helpers/zod";
    
    // Define the output schema
    const ProductReviewAnalysis = z.object({
      sentiment: z.enum(["positive", "negative", "neutral", "mixed"]),
      confidence: z.number().min(0).max(1),
      themes: z.array(z.object({
        name: z.string(),
        sentiment: z.enum(["positive", "negative", "neutral"]),
        mentions: z.number(),
      })),
      summary: z.string().max(200),
      actionItems: z.array(z.string()),
    });
    
    type ProductReviewAnalysis = z.infer<typeof ProductReviewAnalysis>;
    
    const openai = new OpenAI();
    
    async function analyzeReviews(
      reviews: string[]
    ): Promise<ProductReviewAnalysis> {
      const response = await openai.beta.chat.completions.parse({
        model: "gpt-4o-2024-08-06",
        messages: [
          {
            role: "system",
            content: "Analyze product reviews and extract structured insights.",
          },
          {
            role: "user",
            content: `Analyze these reviews:\n${reviews.join("\n---\n")}`,
          },
        ],
        response_format: zodResponseFormat(ProductReviewAnalysis, "review_analysis"),
      });
    
      const parsed = response.choices[0].message.parsed;
      if (!parsed) {
        throw new Error("Failed to parse structured output");
      }
      return parsed;
    }
    

    Why: Structured outputs eliminate brittle regex parsing of LLM text. The model is constrained to produce valid JSON matching your schema, giving you type-safe data for rendering UI components, storing in databases, or passing to other services.


    Pattern 3: Tool Use and AI Agents

    When to use: When the LLM needs to take actions (search, calculate, call APIs, modify data) rather than just generate text.

    Implementation:

    import OpenAI from "openai";
    
    const tools: OpenAI.Chat.Completions.ChatCompletionTool[] = [
      {
        type: "function",
        function: {
          name: "search_knowledge_base",
          description: "Search the internal knowledge base for relevant articles",
          parameters: {
            type: "object",
            properties: {
              query: { type: "string", description: "Search query" },
              category: {
                type: "string",
                enum: ["billing", "technical", "account"],
                description: "Category to filter by",
              },
            },
            required: ["query"],
          },
        },
      },
      {
        type: "function",
        function: {
          name: "create_support_ticket",
          description: "Create a support ticket for unresolved issues",
          parameters: {
            type: "object",
            properties: {
              title: { type: "string" },
              description: { type: "string" },
              priority: { type: "string", enum: ["low", "medium", "high", "urgent"] },
            },
            required: ["title", "description", "priority"],
          },
        },
      },
    ];
    
    // Tool implementations
    const toolHandlers: Record<string, (args: unknown) => Promise<string>> = {
      search_knowledge_base: async (args) => {
        const { query, category } = args as { query: string; category?: string };
        const results = await knowledgeBase.search(query, { category });
        return JSON.stringify(results);
      },
      create_support_ticket: async (args) => {
        const ticket = args as { title: string; description: string; priority: string };
        const created = await ticketSystem.create(ticket);
        return JSON.stringify({ ticketId: created.id, status: "created" });
      },
    };
    
    // Agentic loop - let the model decide which tools to call
    async function agentLoop(
      messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[]
    ): Promise<string> {
      const MAX_ITERATIONS = 10;
    
      for (let i = 0; i < MAX_ITERATIONS; i++) {
        const response = await openai.chat.completions.create({
          model: "gpt-4o",
          messages,
          tools,
          tool_choice: "auto",
        });
    
        const message = response.choices[0].message;
        messages.push(message);
    
        // If no tool calls, we have the final answer
        if (!message.tool_calls || message.tool_calls.length === 0) {
          return message.content ?? "";
        }
    
        // Execute each tool call
        for (const toolCall of message.tool_calls) {
          const handler = toolHandlers[toolCall.function.name];
          if (!handler) {
            throw new Error(`Unknown tool: ${toolCall.function.name}`);
          }
    
          const args = JSON.parse(toolCall.function.arguments);
          const result = await handler(args);
    
          messages.push({
            role: "tool",
            tool_call_id: toolCall.id,
            content: result,
          });
        }
      }
    
      throw new Error("Agent exceeded maximum iterations");
    }
    

    Why: Tool use transforms LLMs from text generators into actors that can query databases, call APIs, and orchestrate workflows. The agentic loop pattern gives the model autonomy to decide which tools to use and when, while the iteration limit prevents runaway execution.


    Pattern 4: Semantic Caching for Cost Optimization

    When to use: When similar queries are common and freshness requirements allow caching.

    Implementation:

    import { Redis } from "ioredis";
    import { createHash } from "crypto";
    
    interface CacheEntry {
      response: string;
      embedding: number[];
      createdAt: number;
    }
    
    class SemanticCache {
      private redis: Redis;
      private ttlSeconds: number;
      private similarityThreshold: number;
    
      constructor(options: {
        redisUrl: string;
        ttlSeconds?: number;
        similarityThreshold?: number;
      }) {
        this.redis = new Redis(options.redisUrl);
        this.ttlSeconds = options.ttlSeconds ?? 3600;
        this.similarityThreshold = options.similarityThreshold ?? 0.95;
      }
    
      // Exact match cache (fast, cheap)
      private exactKey(prompt: string): string {
        const hash = createHash("sha256").update(prompt).digest("hex");
        return `llm:exact:${hash}`;
      }
    
      // Check exact cache first, then semantic similarity
      async get(prompt: string): Promise<string | null> {
        // 1. Try exact match
        const exact = await this.redis.get(this.exactKey(prompt));
        if (exact) return exact;
    
        // 2. Try semantic match (more expensive, but catches paraphrases)
        const embedding = await getEmbedding(prompt);
        const candidates = await this.redis.smembers("llm:semantic:keys");
    
        for (const candidateKey of candidates) {
          const raw = await this.redis.get(`llm:semantic:${candidateKey}`);
          if (!raw) continue;
    
          const entry: CacheEntry = JSON.parse(raw);
          const similarity = cosineSimilarity(embedding, entry.embedding);
    
          if (similarity >= this.similarityThreshold) {
            return entry.response;
          }
        }
    
        return null;
      }
    
      async set(prompt: string, response: string): Promise<void> {
        const embedding = await getEmbedding(prompt);
        const key = createHash("sha256").update(prompt).digest("hex");
    
        // Store exact match
        await this.redis.setex(this.exactKey(prompt), this.ttlSeconds, response);
    
        // Store semantic entry
        const entry: CacheEntry = {
          response,
          embedding,
          createdAt: Date.now(),
        };
        await this.redis.setex(
          `llm:semantic:${key}`,
          this.ttlSeconds,
          JSON.stringify(entry)
        );
        await this.redis.sadd("llm:semantic:keys", key);
      }
    }
    
    function cosineSimilarity(a: number[], b: number[]): number {
      let dot = 0, magA = 0, magB = 0;
      for (let i = 0; i < a.length; i++) {
        dot += a[i] * b[i];
        magA += a[i] * a[i];
        magB += b[i] * b[i];
      }
      return dot / (Math.sqrt(magA) * Math.sqrt(magB));
    }
    

    Why: LLM API calls are expensive and slow. Semantic caching catches not just identical queries but paraphrased ones, dramatically reducing costs for applications with repetitive query patterns (FAQ bots, customer support, search).


    Pattern 5: Streaming Responses

    When to use: Any user-facing LLM interaction where perceived latency matters.

    Implementation:

    // Server - Next.js Route Handler with streaming
    import { OpenAI } from "openai";
    import { NextRequest } from "next/server";
    
    export async function POST(req: NextRequest) {
      const { messages } = await req.json();
      const openai = new OpenAI();
    
      const stream = await openai.chat.completions.create({
        model: "gpt-4o",
        messages,
        stream: true,
      });
    
      // Convert OpenAI stream to ReadableStream
      const encoder = new TextEncoder();
      const readable = new ReadableStream({
        async start(controller) {
          for await (const chunk of stream) {
            const text = chunk.choices[0]?.delta?.content ?? "";
            if (text) {
              controller.enqueue(encoder.encode(`data: ${JSON.stringify({ text })}\n\n`));
            }
          }
          controller.enqueue(encoder.encode("data: [DONE]\n\n"));
          controller.close();
        },
      });
    
      return new Response(readable, {
        headers: {
          "Content-Type": "text/event-stream",
          "Cache-Control": "no-cache",
          Connection: "keep-alive",
        },
      });
    }
    
    // Client - React hook for consuming streams
    function useStreamingChat() {
      const [messages, setMessages] = useState<Message[]>([]);
      const [isStreaming, setIsStreaming] = useState(false);
    
      const sendMessage = async (content: string) => {
        const userMessage = { role: "user" as const, content };
        const updatedMessages = [...messages, userMessage];
        setMessages(updatedMessages);
        setIsStreaming(true);
    
        const response = await fetch("/api/chat", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ messages: updatedMessages }),
        });
    
        const reader = response.body?.getReader();
        const decoder = new TextDecoder();
        let assistantContent = "";
    
        setMessages((prev) => [...prev, { role: "assistant", content: "" }]);
    
        while (reader) {
          const { done, value } = await reader.read();
          if (done) break;
    
          const text = decoder.decode(value);
          const lines = text.split("\n").filter((line) => line.startsWith("data: "));
    
          for (const line of lines) {
            const data = line.slice(6);
            if (data === "[DONE]") break;
    
            const parsed = JSON.parse(data);
            assistantContent += parsed.text;
    
            setMessages((prev) => {
              const updated = [...prev];
              updated[updated.length - 1] = {
                role: "assistant",
                content: assistantContent,
              };
              return updated;
            });
          }
        }
    
        setIsStreaming(false);
      };
    
      return { messages, sendMessage, isStreaming };
    }
    

    Why: Without streaming, users stare at a blank screen for 2-10 seconds. Streaming shows tokens as they arrive, reducing perceived latency to under 500ms for first token. This is table stakes for any user-facing LLM feature.


    Pattern 6: LLM Output Evaluation

    When to use: Before deploying any LLM feature to production, and as ongoing regression testing.

    Implementation:

    import { evaluate } from "braintrust";
    
    // Define evaluation dataset
    const dataset = [
      {
        input: "What is our refund policy?",
        expected: "30-day money-back guarantee",
        tags: ["policy", "refund"],
      },
      {
        input: "How do I reset my password?",
        expected: "Go to Settings > Security > Reset Password",
        tags: ["account", "password"],
      },
    ];
    
    // Custom scoring functions
    function factualAccuracy(output: string, expected: string): number {
      const expectedFacts = expected.toLowerCase().split(/[,.]/).map((s) => s.trim());
      const matchedFacts = expectedFacts.filter((fact) =>
        output.toLowerCase().includes(fact)
      );
      return matchedFacts.length / expectedFacts.length;
    }
    
    function answerRelevance(output: string, input: string): number {
      // Use an LLM as a judge
      // Returns 0-1 score for how relevant the answer is to the question
      return llmJudge(input, output, "relevance");
    }
    
    // Run evaluation
    const results = await evaluate("support-bot-v2", {
      data: dataset,
      task: async (input) => {
        return await generateAnswer(input.input);
      },
      scores: [
        {
          name: "factual_accuracy",
          scorer: (args) => factualAccuracy(args.output, args.expected),
        },
        {
          name: "answer_relevance",
          scorer: (args) => answerRelevance(args.output, args.input),
        },
        {
          name: "no_hallucination",
          scorer: (args) => {
            const hallucinationCheck = detectHallucination(args.output, args.context);
            return hallucinationCheck ? 0 : 1;
          },
        },
      ],
    });
    
    console.log(`Average factual accuracy: ${results.scores.factual_accuracy}`);
    console.log(`Average relevance: ${results.scores.answer_relevance}`);
    

    Why: LLM outputs are probabilistic. Without evaluation, you cannot measure whether prompt changes, model upgrades, or context modifications improve or degrade quality. Evals are the tests of LLM engineering.


    Vector Database Selection Guide

    DatabaseBest ForScalingManagedLocal Dev
    pgvectorExisting Postgres users, < 10M vectorsVerticalVia Supabase/NeonDocker
    PineconeServerless, large-scale productionHorizontalYes (only)Mock client
    ChromaPrototyping, small datasetsLimitedChroma CloudIn-memory
    WeaviateHybrid search (vector + BM25)HorizontalYes + self-hostDocker
    QdrantPerformance-critical, filteringHorizontalYes + self-hostDocker

    Prompt Engineering Quick Reference

    TechniqueWhen to UseExample Prefix
    Zero-shotSimple, well-defined tasks"Classify this email as spam or not:"
    Few-shotPattern demonstration needed"Here are examples:\n..."
    Chain-of-thoughtReasoning tasks"Think step by step:"
    System promptPersistent behavior rulesrole: "system" message
    DelimitersSeparating context from instructions"""context""" or <context> tags

    Anti-Patterns

    Anti-PatternWhy It's BadBetter Approach
    Stuffing entire documents into contextWastes tokens, dilutes relevanceUse RAG with chunking and retrieval
    Parsing LLM text output with regexBrittle, breaks on format changesUse structured outputs (function calling, Zod)
    No evaluation before productionCannot measure quality or catch regressionsBuild eval suite with scoring functions
    Single huge prompt for everythingHard to debug, expensive, slowDecompose into smaller focused prompts
    Ignoring token costs during developmentSurprise bills at scaleTrack costs per query, set budgets, cache
    Synchronous LLM calls in request pathSlow user experience, timeout riskStream responses, use background jobs for heavy work
    Hardcoded model names everywherePainful to upgrade or A/B testConfig-driven model selection
    No retry logic on API callsTransient failures cause user-visible errorsExponential backoff with jitter

    Checklist

    • RAG pipeline: chunking strategy chosen and tested (size, overlap, separators)
    • Vector database selected and connection pooling configured
    • Embedding model chosen (dimension, cost, quality tradeoff)
    • Structured output schemas defined for all LLM-to-code boundaries
    • Streaming implemented for user-facing responses
    • Evaluation suite with at least 20 test cases per feature
    • Semantic or exact caching for repeated queries
    • Error handling: retries, fallbacks, user-visible error states
    • Cost tracking: per-query token usage logged
    • Rate limiting on LLM API calls
    • System prompts versioned and stored outside code
    • Prompt injection defenses (input validation, output filtering)

    Related Resources

    • Skills: application-security (prompt injection), monitoring-observability (LLM call tracing)
    • Rules: docs/reference/stacks/react-typescript.md (frontend patterns for chat UI)
    • Rules: docs/reference/checklists/verification-template.md (eval checklist)

    Frequently asked questions

    What to verify before installation and use

    What does the llm-app-development source document cover?

    LLM app development with RAG, prompt engineering, vector databases, and AI agents

    How do I install llm-app-development?

    The source record exposes this install command: npx skills add https://github.com/travisjneuman/.claude --skill "skills/llm-app-development". Inspect the command and pinned source before running it.

    Which permission-related actions were detected?

    Static rules flagged network in the source; the page lists the matching lines and excerpts.

    Alternatives

    Compare before choosing

    Computed 10045,511

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 10029,034

    garrytan/gbrain

    bulk-ingestion

    End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

    Computed 10024,921

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 1005,241

    dotnet/skills

    migrate-vstest-to-mtp

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing