mcpbeat Sign in

Add Diagnostic Parser Agent Skill

> Use when adding a compiler or tool output parser for the Problems panel. Touches src/diagnostics/<name>.ts, src/diagnostics/build.ts, package.json "new diagnostic parser", "parse compiler output".

3k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
1680
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/microsoft/vscode-cmake-tools --skill add-diagnostic-parser

The instruction itself

15 sections, as written by the author

Adding a New Diagnostic / Output Parser

Recipe for adding a new compiler or tool output parser to CMake Tools. A parser extracts diagnostics (errors, warnings, notes) from build output and surfaces them in the VS Code Problems panel.

Overview

Adding a parser touches 4 files (plus tests and changelog):

| File | What to do |

|---|---|

| src/diagnostics/<name>.ts | Create the parser class |

| src/diagnostics/build.ts | Register the parser in Compilers |

| package.json | Add to cmake.enabledOutputParsers enum |

| package.nls.json | Update description if user-visible text changes |


Step 1: Create the parser file

Create src/diagnostics/<name>.ts. Every parser extends RawDiagnosticParser (defined in src/diagnostics/util.ts) and exports a class named Parser.

Base class contract

// src/diagnostics/util.ts (simplified)
export abstract class RawDiagnosticParser {
    get diagnostics(): readonly RawDiagnostic[] { /* accumulated results */ }

    /** Called by the build consumer for every line of output. */
    handleLine(line: string): boolean {
        const result = this.doHandleLine(line);
        if (result === FeedLineResult.Ok) return true;        // line consumed, no new diagnostic
        if (result === FeedLineResult.NotMine) return false;   // line not recognized
        // Otherwise result is a RawDiagnostic — it gets stored automatically
        this._diagnostics.push(result);
        return true;
    }

    /** Implement this. Return a RawDiagnostic to emit, or a FeedLineResult. */
    protected abstract doHandleLine(line: string): RawDiagnostic | FeedLineResult;
}

Minimal single-regex parser (like MSVC)

/**
 * Module for parsing <ToolName> diagnostics
 */ /** */

import * as vscode from 'vscode';
import { oneLess, RawDiagnosticParser, FeedLineResult } from '@cmt/diagnostics/util';

// Regex that captures: file, line, severity, code (optional), message
export const REGEX = /^(.+):(\d+):\s+(error|warning|info)\s+(\w+):\s+(.*)$/;

export class Parser extends RawDiagnosticParser {
    doHandleLine(line: string) {
        const mat = REGEX.exec(line);
        if (!mat) {
            return FeedLineResult.NotMine;
        }
        const [full, file, lineStr, severity, code, message] = mat;
        const lineno = oneLess(lineStr);   // convert 1-based to 0-based
        return {
            full,
            file,
            location: new vscode.Range(lineno, 0, lineno, 999),
            severity,
            message,
            code,
            related: []
        };
    }
}

Multi-line / stateful parser (like IAR)

For tools whose diagnostics span multiple lines, use internal state:

import { RawDiagnosticParser, RawDiagnostic, FeedLineResult, oneLess } from '@cmt/diagnostics/util';

enum ParserState { init, pending_message }

export class Parser extends RawDiagnosticParser {
    private state = ParserState.init;
    private pending: RawDiagnostic | null = null;

    doHandleLine(line: string): RawDiagnostic | FeedLineResult {
        switch (this.state) {
            case ParserState.init: {
                const mat = FIRST_LINE_REGEX.exec(line);
                if (!mat) return FeedLineResult.NotMine;
                this.pending = { /* ... build partial diagnostic ... */ };
                this.state = ParserState.pending_message;
                return FeedLineResult.Ok;  // consumed, but not complete yet
            }
            case ParserState.pending_message: {
                if (/* line completes the diagnostic */) {
                    const diag = this.pending!;
                    this.reset();
                    return diag;           // emits the diagnostic
                }
                return FeedLineResult.Ok;  // still accumulating
            }
        }
        return FeedLineResult.NotMine;
    }
}

Key types

// src/diagnostics/util.ts
interface RawDiagnostic {
    full: string;               // the full matched line(s)
    file: string;               // source file path
    location: vscode.Range;     // 0-based range (use oneLess() for 1-based input)
    severity: string;           // 'error' | 'warning' | 'note' | 'info' | 'fatal error' | 'remark'
    message: string;
    code?: string;              // optional diagnostic code (e.g. 'C4996', 'LNK2019')
    related: RawRelated[];      // related diagnostics (notes, template backtraces)
}

enum FeedLineResult {
    Ok,       // line was consumed (but no new diagnostic produced yet)
    NotMine,  // line not recognized by this parser
}

diagnosticSeverity() in util.ts maps the severity string to vscode.DiagnosticSeverity. Recognized values: 'error', 'fatal error', 'catastrophic error', 'warning', 'note', 'info', 'remark'.


Step 2: Register in src/diagnostics/build.ts

Import the new parser module and add an instance to the Compilers class. The property name becomes the parser identifier used in cmake.enabledOutputParsers.

// At the top — add import
import * as myparser from '@cmt/diagnostics/myparser';

// Inside the Compilers class — add property
export class Compilers {
    [compiler: string]: RawDiagnosticParser;

    gcc = new gcc.Parser();
    gnuld = new gnu_ld.Parser();
    ghs = new ghs.Parser();
    diab = new diab.Parser();
    msvc = new mvsc.Parser();
    iar = new iar.Parser();
    iwyu = new iwyu.Parser();
    myparser = new myparser.Parser();   // ← new parser
}

The CompileOutputConsumer.error() method iterates over all Compilers properties in declaration order, calling parser.handleLine(line). The first parser to return true claims the line — order matters if your parser's regex could match lines from another compiler.

The resolveDiagnostics() method filters diagnostics by config.enableOutputParsers — only parsers whose name appears in that array will have their diagnostics shown in the Problems panel.


Step 3: Update package.json

Add the parser name to the cmake.enabledOutputParsers enum. Decide whether it should be default-enabled or opt-in.

// package.json → contributes.configuration → cmake.enabledOutputParsers
"cmake.enabledOutputParsers": {
    "type": "array",
    "items": {
        "type": "string",
        "enum": [
            "cmake",
            "gcc",
            "gnuld",
            "msvc",
            "ghs",
            "diab",
            "iar",
            "iwyu",
            "myparser"     // ← add to enum
        ]
    },
    "default": [
        "cmake",
        "gcc",
        "gnuld",
        "msvc",
        "ghs",
        "diab"
        // only add here if default-enabled
    ]
}

Step 4: Update package.nls.json

If any user-visible setting descriptions changed, update the localization key in package.nls.json. The cmake.enabledOutputParsers description uses the key cmake-tools.configuration.cmake.enabledOutputParsers.description.


Step 5: Write tests

Add tests in test/unit-tests/diagnostics.test.ts. The test pattern:

test('Parse <tool> error', () => {
    const build_consumer = new diags.CompileOutputConsumer(
        new ConfigurationReader({} as ExtensionConfigurationSettings)
    );
    // Feed real compiler output lines
    build_consumer.error('<tool-specific output line>');

    // Verify diagnostics
    const parser = build_consumer.compilers.myparser;
    expect(parser.diagnostics).to.have.length(1);
    expect(parser.diagnostics[0].severity).to.eq('error');
    expect(parser.diagnostics[0].file).to.eq('expected/file.cpp');
});

Step 6: CHANGELOG.md

Add an entry under the current version:

Features:
- Add `myparser` diagnostic parser for <ToolName> compiler output. [PR #XXXX](https://github.com/microsoft/vscode-cmake-tools/pull/XXXX)

Currently registered parsers

| Property in Compilers | Module file | Default-enabled |

|---|---|---|

| gcc | src/diagnostics/gcc.ts | ✅ |

| gnuld | src/diagnostics/gnu-ld.ts | ✅ |

| ghs | src/diagnostics/ghs.ts | ✅ |

| diab | src/diagnostics/diab.ts | ✅ |

| msvc | src/diagnostics/msvc.ts | ✅ |

| iar | src/diagnostics/iar.ts | ❌ opt-in |

| iwyu | src/diagnostics/iwyu.ts | ❌ opt-in |

The cmake parser (in src/diagnostics/cmake.ts) is separate — it handles CMake's own configure/generate output via CMakeOutputConsumer, not build compiler output. It is listed in the enabledOutputParsers default array but is not part of the Compilers class.


Default-enabled vs opt-in

  • Default-enabled parsers (cmake, gcc, gnuld, msvc, ghs, diab) are included in the "default" array in package.json. Users get them automatically.
  • Opt-in parsers (iar, iwyu) are in the "enum" but not in "default". Users must add them to their cmake.enabledOutputParsers setting.
  • Use opt-in for parsers with aggressive regexes that might false-positive on common output, or for niche toolchains.

Verification checklist

  • [ ] Parser class extends RawDiagnosticParser and exports as Parser
  • [ ] doHandleLine() returns FeedLineResult.NotMine for unrecognized lines
  • [ ] doHandleLine() returns a RawDiagnostic (not FeedLineResult.Ok) when a diagnostic is complete
  • [ ] Line/column numbers converted from 1-based to 0-based with oneLess()
  • [ ] Registered in Compilers class in src/diagnostics/build.ts
  • [ ] Added to cmake.enabledOutputParsers enum in package.json
  • [ ] Default array updated (or deliberately left opt-in)
  • [ ] Unit tests in test/unit-tests/diagnostics.test.ts pass
  • [ ] yarn compile succeeds
  • [ ] CHANGELOG.md entry added

See also: .github/copilot-instructions.md for project-wide conventions.

Other skills for the same job

different authors, same section of the catalogue
MCP Builder
by anthropics
vendor ×13

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

30k tokens scripts
Changelog Generator
by frostant
×9

Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.

774 tokens
Finishing A Development Branch
by ZhanlinCui
×7

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup

1k tokens
MCP Builder
by JayZeeDesign
×7

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

37k tokens scripts
Vercel React Native Skills
by vercel-labs
vendor ×6

React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.

39k tokens
Vercel React Best Practices
by ratacat
×5

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

34k tokens
Next Best Practices
by vercel-labs
vendor ×4

Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling

20k tokens
Using Git Worktrees
by ZhanlinCui
×4

Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification

1k tokens

How to use it

Copy the folder

Take microsoft/add-diagnostic-parser from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.