diff --git a/.prettierignore b/.prettierignore
index 3b34afa1ed6..6aabe7366cb 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,6 +4,7 @@
 .vs/
 .ionide/
 
+testdata
 /arduino/libraries/librariesindex/testdata/invalid.json
 /arduino/security/testdata/
 /.licenses/
diff --git a/arduino/builder/builder.go b/arduino/builder/builder.go
index 51646bdcf48..c24bac47011 100644
--- a/arduino/builder/builder.go
+++ b/arduino/builder/builder.go
@@ -25,6 +25,7 @@ import (
 
 	"github.com/arduino/arduino-cli/arduino/builder/internal/compilation"
 	"github.com/arduino/arduino-cli/arduino/builder/internal/detector"
+	"github.com/arduino/arduino-cli/arduino/builder/internal/diagnostics"
 	"github.com/arduino/arduino-cli/arduino/builder/internal/logger"
 	"github.com/arduino/arduino-cli/arduino/builder/internal/progress"
 	"github.com/arduino/arduino-cli/arduino/builder/internal/utils"
@@ -36,6 +37,7 @@ import (
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	"github.com/arduino/go-paths-helper"
 	"github.com/arduino/go-properties-orderedmap"
+	"github.com/sirupsen/logrus"
 )
 
 // ErrSketchCannotBeLocatedInBuildPath fixdoc
@@ -90,6 +92,12 @@ type Builder struct {
 	buildOptions *buildOptions
 
 	libsDetector *detector.SketchLibrariesDetector
+
+	// This is a function used to parse the output of the compiler
+	// It is used to extract errors and warnings
+	compilerOutputParser diagnostics.CompilerOutputParserCB
+	// and here are the diagnostics parsed from the compiler
+	compilerDiagnostics diagnostics.Diagnostics
 }
 
 // buildArtifacts contains the result of various build
@@ -189,7 +197,7 @@ func NewBuilder(
 		logger.Warn(string(verboseOut))
 	}
 
-	return &Builder{
+	b := &Builder{
 		sketch:                        sk,
 		buildProperties:               buildProperties,
 		buildPath:                     buildPath,
@@ -226,7 +234,26 @@ func NewBuilder(
 			buildProperties.GetPath("runtime.platform.path"),
 			buildProperties.GetPath("build.core.path"), // TODO can we buildCorePath ?
 		),
-	}, nil
+	}
+
+	b.compilerOutputParser = func(cmdline []string, out []byte) {
+		compiler := diagnostics.DetectCompilerFromCommandLine(
+			cmdline,
+			false, // at the moment compiler-probing is not required
+		)
+		if compiler == nil {
+			logrus.Warnf("Could not detect compiler from: %s", cmdline)
+			return
+		}
+		diags, err := diagnostics.ParseCompilerOutput(compiler, out)
+		if err != nil {
+			logrus.Warnf("Error parsing compiler output: %s", err)
+			return
+		}
+		b.compilerDiagnostics = append(b.compilerDiagnostics, diags...)
+	}
+
+	return b, nil
 }
 
 // GetBuildProperties returns the build properties for running this build
@@ -249,6 +276,11 @@ func (b *Builder) ImportedLibraries() libraries.List {
 	return b.libsDetector.ImportedLibraries()
 }
 
+// CompilerDiagnostics returns the parsed compiler diagnostics
+func (b *Builder) CompilerDiagnostics() diagnostics.Diagnostics {
+	return b.compilerDiagnostics
+}
+
 // Preprocess fixdoc
 func (b *Builder) Preprocess() ([]byte, error) {
 	b.Progress.AddSubSteps(6)
diff --git a/arduino/builder/compilation.go b/arduino/builder/compilation.go
index e3c70900bf6..0d91f622579 100644
--- a/arduino/builder/compilation.go
+++ b/arduino/builder/compilation.go
@@ -166,6 +166,12 @@ func (b *Builder) compileFileWithRecipe(
 		}
 		b.logger.WriteStderr(commandStderr.Bytes())
 
+		// Parse the output of the compiler to gather errors and warnings...
+		if b.compilerOutputParser != nil {
+			b.compilerOutputParser(command.GetArgs(), commandStdout.Bytes())
+			b.compilerOutputParser(command.GetArgs(), commandStderr.Bytes())
+		}
+
 		// ...and then return the error
 		if err != nil {
 			return nil, errors.WithStack(err)
diff --git a/arduino/builder/internal/diagnostics/compiler_detection.go b/arduino/builder/internal/diagnostics/compiler_detection.go
new file mode 100644
index 00000000000..53b83a52bc1
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/compiler_detection.go
@@ -0,0 +1,85 @@
+// This file is part of arduino-cli.
+//
+// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
+//
+// This software is released under the GNU General Public License version 3,
+// which covers the main part of arduino-cli.
+// The terms of this license can be found at:
+// https://www.gnu.org/licenses/gpl-3.0.en.html
+//
+// You can be released from the requirements of the above licenses by purchasing
+// a commercial license. Buying such a license is mandatory if you want to
+// modify or otherwise use the software for commercial activities involving the
+// Arduino software without disclosing the source code of your own applications.
+// To purchase a commercial license, send an email to license@arduino.cc.
+
+package diagnostics
+
+import (
+	"bytes"
+	"path/filepath"
+	"strings"
+
+	"github.com/arduino/arduino-cli/executils"
+	semver "go.bug.st/relaxed-semver"
+)
+
+// DetectedCompiler represents a compiler detected from a given command line
+type DetectedCompiler struct {
+	Name            string
+	Family          string
+	Version         *semver.Version
+	DetailedVersion []string
+}
+
+// This function is overridden for mocking unit tests
+var runProcess = func(args ...string) []string {
+	if cmd, err := executils.NewProcess(nil, args...); err == nil {
+		out := &bytes.Buffer{}
+		cmd.RedirectStdoutTo(out)
+		cmd.Run()
+		return splitLines(out.Bytes())
+	}
+	return nil
+}
+
+// DetectCompilerFromCommandLine tries to detect a compiler from a given command line.
+// If probeCompiler is true, the compiler may be executed with different flags to
+// infer the version or capabilities.
+func DetectCompilerFromCommandLine(args []string, probeCompiler bool) *DetectedCompiler {
+	if len(args) == 0 {
+		return nil
+	}
+	basename := filepath.Base(args[0])
+	family := ""
+	if strings.Contains(basename, "g++") || strings.Contains(basename, "gcc") {
+		family = "gcc"
+	}
+	res := &DetectedCompiler{
+		Name:   basename,
+		Family: family,
+	}
+
+	if family == "gcc" && probeCompiler {
+		// Run "gcc --version" to obtain more info
+		res.DetailedVersion = runProcess(args[0], "--version")
+
+		// Usually on the first line we get the compiler architecture and
+		// version (as last field), followed by the compiler license, for
+		// example:
+		//
+		//   g++ (Ubuntu 12.2.0-3ubuntu1) 12.2.0
+		//   Copyright (C) 2022 Free Software Foundation, Inc.
+		//   This is free software; see the source for copying conditions.  There is NO
+		//   warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+		//
+		if len(res.DetailedVersion) > 0 {
+			split := strings.Split(res.DetailedVersion[0], " ")
+			if len(split) >= 3 {
+				res.Name = split[0]
+				res.Version, _ = semver.Parse(split[len(split)-1])
+			}
+		}
+	}
+	return res
+}
diff --git a/arduino/builder/internal/diagnostics/compiler_detection_test.go b/arduino/builder/internal/diagnostics/compiler_detection_test.go
new file mode 100644
index 00000000000..024c66868ed
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/compiler_detection_test.go
@@ -0,0 +1,79 @@
+// This file is part of arduino-cli.
+//
+// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
+//
+// This software is released under the GNU General Public License version 3,
+// which covers the main part of arduino-cli.
+// The terms of this license can be found at:
+// https://www.gnu.org/licenses/gpl-3.0.en.html
+//
+// You can be released from the requirements of the above licenses by purchasing
+// a commercial license. Buying such a license is mandatory if you want to
+// modify or otherwise use the software for commercial activities involving the
+// Arduino software without disclosing the source code of your own applications.
+// To purchase a commercial license, send an email to license@arduino.cc.
+
+package diagnostics
+
+import (
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func init() {
+	runProcess = mockedRunProcessToGetCompilerVersion
+}
+
+func mockedRunProcessToGetCompilerVersion(args ...string) []string {
+	if strings.HasSuffix(args[0], "7.3.0-atmel3.6.1-arduino7/bin/avr-g++") && args[1] == "--version" {
+		return []string{
+			"avr-g++ (GCC) 7.3.0",
+			"Copyright (C) 2017 Free Software Foundation, Inc.",
+			"This is free software; see the source for copying conditions.  There is NO",
+			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.",
+			"",
+		}
+	}
+	if strings.HasSuffix(args[0], "7.3.0-atmel3.6.1-arduino7/bin/avr-gcc") && args[1] == "--version" {
+		return []string{
+			"avr-gcc (GCC) 7.3.0",
+			"Copyright (C) 2017 Free Software Foundation, Inc.",
+			"This is free software; see the source for copying conditions.  There is NO",
+			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.",
+			"",
+		}
+	}
+	if strings.HasSuffix(args[0], "xtensa-esp32-elf-gcc/gcc8_4_0-esp-2021r2-patch3/bin/xtensa-esp32-elf-g++") && args[1] == "--version" {
+		return []string{
+			"xtensa-esp32-elf-g++ (crosstool-NG esp-2021r2-patch3) 8.4.0",
+			"Copyright (C) 2018 Free Software Foundation, Inc.",
+			"This is free software; see the source for copying conditions.  There is NO",
+			"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.",
+			"",
+		}
+	}
+
+	panic("missing mock for command line: " + strings.Join(args, " "))
+}
+
+func TestCompilerDetection(t *testing.T) {
+	comp := DetectCompilerFromCommandLine([]string{"~/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++"}, true)
+	require.NotNil(t, comp)
+	require.Equal(t, "gcc", comp.Family)
+	require.Equal(t, "avr-g++", comp.Name)
+	require.Equal(t, "7.3.0", comp.Version.String())
+
+	comp = DetectCompilerFromCommandLine([]string{"~/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-gcc"}, true)
+	require.NotNil(t, comp)
+	require.Equal(t, "gcc", comp.Family)
+	require.Equal(t, "avr-gcc", comp.Name)
+	require.Equal(t, "7.3.0", comp.Version.String())
+
+	comp = DetectCompilerFromCommandLine([]string{"/home/megabug/.arduino15/packages/esp32/tools/xtensa-esp32-elf-gcc/gcc8_4_0-esp-2021r2-patch3/bin/xtensa-esp32-elf-g++"}, true)
+	require.NotNil(t, comp)
+	require.Equal(t, "gcc", comp.Family)
+	require.Equal(t, "xtensa-esp32-elf-g++", comp.Name)
+	require.Equal(t, "8.4.0", comp.Version.String())
+}
diff --git a/arduino/builder/internal/diagnostics/parser.go b/arduino/builder/internal/diagnostics/parser.go
new file mode 100644
index 00000000000..5aafaa5072d
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/parser.go
@@ -0,0 +1,173 @@
+// This file is part of arduino-cli.
+//
+// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
+//
+// This software is released under the GNU General Public License version 3,
+// which covers the main part of arduino-cli.
+// The terms of this license can be found at:
+// https://www.gnu.org/licenses/gpl-3.0.en.html
+//
+// You can be released from the requirements of the above licenses by purchasing
+// a commercial license. Buying such a license is mandatory if you want to
+// modify or otherwise use the software for commercial activities involving the
+// Arduino software without disclosing the source code of your own applications.
+// To purchase a commercial license, send an email to license@arduino.cc.
+
+package diagnostics
+
+import (
+	"fmt"
+	"strings"
+
+	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
+)
+
+// CompilerOutputParserCB is a callback function that is called to feed a parser
+// with the plain-text compiler output.
+type CompilerOutputParserCB func(cmdline []string, out []byte)
+
+// Diagnostics represents a list of diagnostics
+type Diagnostics []*Diagnostic
+
+// Diagnostic represents a diagnostic (a compiler error, warning, note, etc.)
+type Diagnostic struct {
+	Severity    Severity    `json:"severity,omitempty"`
+	Message     string      `json:"message"`
+	File        string      `json:"file,omitempty"`
+	Line        int         `json:"line,omitempty"`
+	Column      int         `json:"col,omitempty"`
+	Context     FullContext `json:"context,omitempty"`
+	Suggestions Notes       `json:"suggestions,omitempty"`
+}
+
+// Severity is a diagnostic severity
+type Severity string
+
+const (
+	// SeverityUnspecified is the undefined severity
+	SeverityUnspecified Severity = ""
+	// SeverityWarning is a warning
+	SeverityWarning = "WARNING"
+	// SeverityError is an error
+	SeverityError = "ERROR"
+	// SeverityFatal is a fatal error
+	SeverityFatal = "FATAL"
+)
+
+// Notes represents a list of Note
+type Notes []*Note
+
+// Note represents a compiler annotation or suggestion
+type Note struct {
+	Message string `json:"message"`
+	File    string `json:"file,omitempty"`
+	Line    int    `json:"line,omitempty"`
+	Column  int    `json:"col,omitempty"`
+}
+
+// FullContext represents a list of Context
+type FullContext []*Context
+
+// Context represents a context, i.e. a reference to a file, line and column
+// or a part of the code that a Diagnostic refers to.
+type Context struct {
+	Message string `json:"message"`
+	File    string `json:"file,omitempty"`
+	Line    int    `json:"line,omitempty"`
+	Column  int    `json:"col,omitempty"`
+}
+
+// ParseCompilerOutput parses the output of a compiler and returns a list of
+// diagnostics.
+func ParseCompilerOutput(compiler *DetectedCompiler, out []byte) ([]*Diagnostic, error) {
+	lines := splitLines(out)
+	switch compiler.Family {
+	case "gcc":
+		return parseGccOutput(lines)
+	default:
+		return nil, fmt.Errorf("unsupported compiler: %s", compiler)
+	}
+}
+
+func splitLines(in []byte) []string {
+	res := strings.Split(string(in), "\n")
+	for i, line := range res {
+		res[i] = strings.TrimSuffix(line, "\r")
+	}
+	if l := len(res) - 1; res[l] == "" {
+		res = res[:l]
+	}
+	return res
+}
+
+// ToRPC converts a Diagnostics to a slice of rpc.CompileDiagnostic
+func (d Diagnostics) ToRPC() []*rpc.CompileDiagnostic {
+	if len(d) == 0 {
+		return nil
+	}
+	var res []*rpc.CompileDiagnostic
+	for _, diag := range d {
+		res = append(res, diag.ToRPC())
+	}
+	return res
+}
+
+// ToRPC converts a Diagnostic to a rpc.CompileDiagnostic
+func (d *Diagnostic) ToRPC() *rpc.CompileDiagnostic {
+	if d == nil {
+		return nil
+	}
+	return &rpc.CompileDiagnostic{
+		Severity: string(d.Severity),
+		Message:  d.Message,
+		File:     d.File,
+		Line:     int64(d.Line),
+		Column:   int64(d.Column),
+		Context:  d.Context.ToRPC(),
+		Notes:    d.Suggestions.ToRPC(),
+	}
+}
+
+// ToRPC converts a Notes to a slice of rpc.CompileDiagnosticNote
+func (s Notes) ToRPC() []*rpc.CompileDiagnosticNote {
+	var res []*rpc.CompileDiagnosticNote
+	for _, suggestion := range s {
+		res = append(res, suggestion.ToRPC())
+	}
+	return res
+}
+
+// ToRPC converts a Note to a rpc.CompileDiagnosticNote
+func (s *Note) ToRPC() *rpc.CompileDiagnosticNote {
+	if s == nil {
+		return nil
+	}
+	return &rpc.CompileDiagnosticNote{
+		File:    s.File,
+		Line:    int64(s.Line),
+		Column:  int64(s.Column),
+		Message: s.Message,
+	}
+}
+
+// ToRPC converts a FullContext to a slice of rpc.CompileDiagnosticContext
+func (t FullContext) ToRPC() []*rpc.CompileDiagnosticContext {
+	var res []*rpc.CompileDiagnosticContext
+	for _, trace := range t {
+		res = append(res, trace.ToRPC())
+	}
+	return res
+}
+
+// ToRPC converts a Context to a rpc.CompileDiagnosticContext
+func (d *Context) ToRPC() *rpc.CompileDiagnosticContext {
+	if d == nil {
+		return nil
+	}
+	return &rpc.CompileDiagnosticContext{
+		File:    d.File,
+		Line:    int64(d.Line),
+		Column:  int64(d.Column),
+		Message: d.Message,
+	}
+}
diff --git a/arduino/builder/internal/diagnostics/parser_gcc.go b/arduino/builder/internal/diagnostics/parser_gcc.go
new file mode 100644
index 00000000000..afc9ef40c41
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/parser_gcc.go
@@ -0,0 +1,193 @@
+// This file is part of arduino-cli.
+//
+// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
+//
+// This software is released under the GNU General Public License version 3,
+// which covers the main part of arduino-cli.
+// The terms of this license can be found at:
+// https://www.gnu.org/licenses/gpl-3.0.en.html
+//
+// You can be released from the requirements of the above licenses by purchasing
+// a commercial license. Buying such a license is mandatory if you want to
+// modify or otherwise use the software for commercial activities involving the
+// Arduino software without disclosing the source code of your own applications.
+// To purchase a commercial license, send an email to license@arduino.cc.
+
+package diagnostics
+
+import (
+	"strconv"
+	"strings"
+)
+
+// Parse output from gcc compiler and extract diagnostics
+func parseGccOutput(output []string) ([]*Diagnostic, error) {
+	// Output from gcc is a mix of diagnostics and other information.
+	//
+	// 1. include trace lines:
+	//
+	//   In file included from /home/megabug/Arduino/libraries/Audio/src/Audio.h:16:0,
+	//   ·················from /home/megabug/Arduino/Blink/Blink.ino:1:
+	//
+	// 2. in-file context lines:
+	//
+	//   /home/megabug/Arduino/libraries/Audio/src/DAC.h: In member function 'void DACClass::enableInterrupts()':
+	//
+	// 3. actual diagnostic lines:
+	//
+	//   /home/megabug/Arduino/libraries/Audio/src/DAC.h:31:44: fatal error: 'isrId' was not declared in this scope
+	//
+	//   /home/megabug/Arduino/libraries/Audio/src/DAC.h:31:44: error: 'isrId' was not declared in this scope
+	//
+	//   /home/megabug/Arduino/libraries/Audio/src/DAC.h:31:44: warning: 'isrId' was not declared in this scope
+	//
+	// 4. annotations or suggestions:
+	//
+	//   /home/megabug/Arduino/Blink/Blink.ino:4:1: note: suggested alternative: 'rand'
+	//
+	// 5. extra context lines with an extract of the code that errors refers to:
+	//
+	//   ·asd;
+	//   ·^~~
+	//   ·rand
+	//
+	//   ·void enableInterrupts()  { NVIC_EnableIRQ(isrId); };
+	//   ···········································^~~~~
+
+	var fullContext FullContext
+	var fullContextRefersTo string
+	var inFileContext *Context
+	var currentDiagnostic *Diagnostic
+	var currentMessage *string
+	var res []*Diagnostic
+
+	for _, in := range output {
+		isTrace := false
+		if strings.HasPrefix(in, "In file included from ") {
+			in = strings.TrimPrefix(in, "In file included from ")
+			// 1. include trace
+			isTrace = true
+			inFileContext = nil
+			fullContext = nil
+			fullContextRefersTo = ""
+		} else if strings.HasPrefix(in, "                 from ") {
+			in = strings.TrimPrefix(in, "                 from ")
+			// 1. include trace continuation
+			isTrace = true
+		}
+		if isTrace {
+			in = strings.TrimSuffix(in, ",")
+			file, line, col := extractFileLineAndColumn(in)
+			context := &Context{
+				File:    file,
+				Line:    line,
+				Column:  col,
+				Message: "included from here",
+			}
+			currentMessage = &context.Message
+			fullContext = append(fullContext, context)
+			continue
+		}
+
+		if split := strings.SplitN(in, ": ", 2); len(split) == 2 {
+			file, line, column := extractFileLineAndColumn(split[0])
+			msg := split[1]
+
+			if line == 0 && column == 0 {
+				// 2. in-file context
+				inFileContext = &Context{
+					Message: msg,
+					File:    file,
+				}
+				currentMessage = &inFileContext.Message
+				continue
+			}
+
+			if strings.HasPrefix(msg, "note: ") {
+				msg = strings.TrimPrefix(msg, "note: ")
+				// 4. annotations or suggestions
+				if currentDiagnostic != nil {
+					suggestion := &Note{
+						Message: msg,
+						File:    file,
+						Line:    line,
+						Column:  column,
+					}
+					currentDiagnostic.Suggestions = append(currentDiagnostic.Suggestions, suggestion)
+					currentMessage = &suggestion.Message
+				}
+				continue
+			}
+
+			severity := SeverityUnspecified
+			if strings.HasPrefix(msg, "error: ") {
+				msg = strings.TrimPrefix(msg, "error: ")
+				severity = SeverityError
+			} else if strings.HasPrefix(msg, "warning: ") {
+				msg = strings.TrimPrefix(msg, "warning: ")
+				severity = SeverityWarning
+			} else if strings.HasPrefix(msg, "fatal error: ") {
+				msg = strings.TrimPrefix(msg, "fatal error: ")
+				severity = SeverityFatal
+			}
+			if severity != SeverityUnspecified {
+				// 3. actual diagnostic lines
+				currentDiagnostic = &Diagnostic{
+					Severity: severity,
+					Message:  msg,
+					File:     file,
+					Line:     line,
+					Column:   column,
+				}
+				currentMessage = &currentDiagnostic.Message
+
+				if len(fullContext) > 0 {
+					if fullContextRefersTo == "" || fullContextRefersTo == file {
+						fullContextRefersTo = file
+						currentDiagnostic.Context = append(currentDiagnostic.Context, fullContext...)
+					}
+				}
+				if inFileContext != nil && inFileContext.File == file {
+					currentDiagnostic.Context = append(currentDiagnostic.Context, inFileContext)
+				}
+
+				res = append(res, currentDiagnostic)
+				continue
+			}
+		}
+
+		// 5. extra context lines
+		if strings.HasPrefix(in, " ") {
+			if currentMessage != nil {
+				*currentMessage += "\n" + in
+			}
+			continue
+		}
+	}
+	return res, nil
+}
+
+func extractFileLineAndColumn(file string) (string, int, int) {
+	split := strings.Split(file, ":")
+	file = split[0]
+	if len(split) == 1 {
+		return file, 0, 0
+	}
+
+	// Special case: handle Windows drive letter `C:\...`
+	if len(split) > 1 && len(file) == 1 && strings.HasPrefix(split[1], `\`) {
+		file += ":" + split[1]
+		split = split[1:]
+
+		if len(split) == 1 {
+			return file, 0, 0
+		}
+	}
+
+	line, err := strconv.Atoi(split[1])
+	if err != nil || len(split) == 2 {
+		return file, line, 0
+	}
+	column, _ := strconv.Atoi(split[2])
+	return file, line, column
+}
diff --git a/arduino/builder/internal/diagnostics/parser_test.go b/arduino/builder/internal/diagnostics/parser_test.go
new file mode 100644
index 00000000000..fe2b6cbed53
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/parser_test.go
@@ -0,0 +1,57 @@
+// This file is part of arduino-cli.
+//
+// Copyright 2023 ARDUINO SA (http://www.arduino.cc/)
+//
+// This software is released under the GNU General Public License version 3,
+// which covers the main part of arduino-cli.
+// The terms of this license can be found at:
+// https://www.gnu.org/licenses/gpl-3.0.en.html
+//
+// You can be released from the requirements of the above licenses by purchasing
+// a commercial license. Buying such a license is mandatory if you want to
+// modify or otherwise use the software for commercial activities involving the
+// Arduino software without disclosing the source code of your own applications.
+// To purchase a commercial license, send an email to license@arduino.cc.
+
+package diagnostics
+
+import (
+	"bytes"
+	"encoding/json"
+	"strings"
+	"testing"
+
+	"github.com/arduino/go-paths-helper"
+	"github.com/stretchr/testify/require"
+)
+
+func TestParser(t *testing.T) {
+	t.Run("Generic001", func(t *testing.T) { runParserTest(t, "test001.txt") })
+	t.Run("Generic002", func(t *testing.T) { runParserTest(t, "test002.txt") })
+	t.Run("Generic003", func(t *testing.T) { runParserTest(t, "test003.txt") })
+	t.Run("Generic004", func(t *testing.T) { runParserTest(t, "test004.txt") })
+}
+
+func runParserTest(t *testing.T, testFile string) {
+	testData, err := paths.New("testdata", "compiler_outputs", testFile).ReadFile()
+	require.NoError(t, err)
+	// The first line contains the compiler arguments
+	idx := bytes.Index(testData, []byte("\n"))
+	require.NotEqual(t, -1, idx)
+	args := strings.Split(string(testData[0:idx]), " ")
+	// The remainder of the file is the compiler output
+	data := testData[idx:]
+
+	// Run compiler detection and parse compiler output
+	detectedCompiler := DetectCompilerFromCommandLine(args, true)
+	require.NotNil(t, detectedCompiler)
+	diags, err := ParseCompilerOutput(detectedCompiler, data)
+	require.NoError(t, err)
+
+	// Check if the parsed data match the expected output
+	output, err := json.MarshalIndent(diags, "", "  ")
+	require.NoError(t, err)
+	golden, err := paths.New("testdata", "compiler_outputs", testFile+".json").ReadFile()
+	require.NoError(t, err)
+	require.Equal(t, string(golden), string(output))
+}
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test001.txt b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test001.txt
new file mode 100644
index 00000000000..a04874cd03c
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test001.txt
@@ -0,0 +1,12 @@
+/home/megabug/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++ -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega32u4 -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_LEONARDO -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x8036 "-DUSB_MANUFACTURER=\"Unknown\"" "-DUSB_PRODUCT=\"Arduino Leonardo\"" -I/home/megabug/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino -I/home/megabug/.arduino15/packages/arduino/hardware/avr/1.8.6/variants/leonardo /tmp/arduino/sketches/002050EAA7EFB9A4FC451CDFBC0FA2D3/sketch/Blink.ino.cpp -o /tmp/arduino/sketches/002050EAA7EFB9A4FC451CDFBC0FA2D3/sketch/Blink.ino.cpp.o
+/home/megabug/Arduino/Blink/Blink.ino:1:14: error: expected initializer before 'asd'
+ void setup() asd {
+              ^~~
+/home/megabug/Arduino/Blink/Blink.ino: In function 'void loop()':
+/home/megabug/Arduino/Blink/Blink.ino:6:1: error: 'asd' was not declared in this scope
+ asd
+ ^~~
+/home/megabug/Arduino/Blink/Blink.ino:6:1: note: suggested alternative: 'rand'
+ asd
+ ^~~
+ rand
\ No newline at end of file
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test001.txt.json b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test001.txt.json
new file mode 100644
index 00000000000..e1fd65d270d
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test001.txt.json
@@ -0,0 +1,30 @@
+[
+  {
+    "severity": "ERROR",
+    "message": "expected initializer before 'asd'\n void setup() asd {\n              ^~~",
+    "file": "/home/megabug/Arduino/Blink/Blink.ino",
+    "line": 1,
+    "col": 14
+  },
+  {
+    "severity": "ERROR",
+    "message": "'asd' was not declared in this scope\n asd\n ^~~",
+    "file": "/home/megabug/Arduino/Blink/Blink.ino",
+    "line": 6,
+    "col": 1,
+    "context": [
+      {
+        "message": "In function 'void loop()':",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino"
+      }
+    ],
+    "suggestions": [
+      {
+        "message": "suggested alternative: 'rand'\n asd\n ^~~\n rand",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 6,
+        "col": 1
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test002.txt b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test002.txt
new file mode 100644
index 00000000000..c0add91431e
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test002.txt
@@ -0,0 +1,34 @@
+/home/megabug/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-g++ -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -I/home/megabug/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino -I/home/megabug/.arduino15/packages/arduino/hardware/avr/1.8.6/variants/standard -I/home/megabug/Arduino/libraries/Audio/src /tmp/arduino/sketches/002050EAA7EFB9A4FC451CDFBC0FA2D3/sketch/Blink.ino.cpp -o /tmp/arduino/sketches/002050EAA7EFB9A4FC451CDFBC0FA2D3/sketch/Blink.ino.cpp.o
+In file included from /home/megabug/Arduino/libraries/Audio/src/Audio.h:16:0,
+                 from /home/megabug/Arduino/Blink/Blink.ino:1:
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:21:16: error: expected ')' before '*' token
+  DACClass(Dacc *_dac, uint32_t _dacId, IRQn_Type _isrId) :
+                ^
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:35:2: error: 'Dacc' does not name a type
+  Dacc *dac;
+  ^~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:37:2: error: 'IRQn_Type' does not name a type
+  IRQn_Type isrId;
+  ^~~~~~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h: In member function 'void DACClass::enableInterrupts()':
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:31:44: error: 'isrId' was not declared in this scope
+  void enableInterrupts()  { NVIC_EnableIRQ(isrId); };
+                                            ^~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:31:29: error: 'NVIC_EnableIRQ' was not declared in this scope
+  void enableInterrupts()  { NVIC_EnableIRQ(isrId); };
+                             ^~~~~~~~~~~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h: In member function 'void DACClass::disableInterrupts()':
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:32:45: error: 'isrId' was not declared in this scope
+  void disableInterrupts() { NVIC_DisableIRQ(isrId); };
+                                             ^~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:32:29: error: 'NVIC_DisableIRQ' was not declared in this scope
+  void disableInterrupts() { NVIC_DisableIRQ(isrId); };
+                             ^~~~~~~~~~~~~~~
+/home/megabug/Arduino/Blink/Blink.ino: In function 'void setup()':
+/home/megabug/Arduino/Blink/Blink.ino:4:1: error: 'asd' was not declared in this scope
+ asd;
+ ^~~
+/home/megabug/Arduino/Blink/Blink.ino:4:1: note: suggested alternative: 'rand'
+ asd;
+ ^~~
+ rand
\ No newline at end of file
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test002.txt.json b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test002.txt.json
new file mode 100644
index 00000000000..cd1a4c402a5
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test002.txt.json
@@ -0,0 +1,172 @@
+[
+  {
+    "severity": "ERROR",
+    "message": "expected ')' before '*' token\n  DACClass(Dacc *_dac, uint32_t _dacId, IRQn_Type _isrId) :\n                ^",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 21,
+    "col": 16,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'Dacc' does not name a type\n  Dacc *dac;\n  ^~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 35,
+    "col": 2,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'IRQn_Type' does not name a type\n  IRQn_Type isrId;\n  ^~~~~~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 37,
+    "col": 2,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'isrId' was not declared in this scope\n  void enableInterrupts()  { NVIC_EnableIRQ(isrId); };\n                                            ^~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 31,
+    "col": 44,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::enableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'NVIC_EnableIRQ' was not declared in this scope\n  void enableInterrupts()  { NVIC_EnableIRQ(isrId); };\n                             ^~~~~~~~~~~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 31,
+    "col": 29,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::enableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'isrId' was not declared in this scope\n  void disableInterrupts() { NVIC_DisableIRQ(isrId); };\n                                             ^~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 32,
+    "col": 45,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::disableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'NVIC_DisableIRQ' was not declared in this scope\n  void disableInterrupts() { NVIC_DisableIRQ(isrId); };\n                             ^~~~~~~~~~~~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 32,
+    "col": 29,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::disableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'asd' was not declared in this scope\n asd;\n ^~~",
+    "file": "/home/megabug/Arduino/Blink/Blink.ino",
+    "line": 4,
+    "col": 1,
+    "context": [
+      {
+        "message": "In function 'void setup()':",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino"
+      }
+    ],
+    "suggestions": [
+      {
+        "message": "suggested alternative: 'rand'\n asd;\n ^~~\n rand",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 4,
+        "col": 1
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test003.txt b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test003.txt
new file mode 100644
index 00000000000..1b8af0f22d6
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test003.txt
@@ -0,0 +1,40 @@
+/home/megabug/.arduino15/packages/esp32/tools/xtensa-esp32-elf-gcc/gcc8_4_0-esp-2021r2-patch3/bin/xtensa-esp32-elf-g++ -DHAVE_CONFIG_H "-DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\"" -DUNITY_INCLUDE_CONFIG_H -DWITH_POSIX -D_GNU_SOURCE "-DIDF_VER=\"v4.4.1-1-gb8050b365e\"" -DESP_PLATFORM -D_POSIX_READER_WRITER_LOCKS -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/config -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/newlib/platform_include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/freertos/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/freertos/include/esp_additions/freertos -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/freertos/port/xtensa/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/freertos/include/esp_additions -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_hw_support/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_hw_support/include/soc -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_hw_support/include/soc/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_hw_support/port/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_hw_support/port/esp32/private_include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/heap/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/log/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/lwip/include/apps -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/lwip/include/apps/sntp -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/lwip/lwip/src/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/lwip/port/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/lwip/port/esp32/include/arch -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/soc/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/soc/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/soc/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/hal/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/hal/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/hal/platform_port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_rom/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_rom/include/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_rom/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_common/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_system/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_system/port/soc -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_system/port/public_compat -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/xtensa/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/xtensa/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/driver/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/driver/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_pm/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_ringbuf/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/efuse/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/efuse/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/vfs/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_wifi/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_event/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_netif/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_eth/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/tcpip_adapter/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_phy/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_phy/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_ipc/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/app_trace/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_timer/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/mbedtls/port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/mbedtls/mbedtls/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/mbedtls/esp_crt_bundle/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/app_update/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/spi_flash/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/bootloader_support/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/nvs_flash/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/pthread/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_gdbstub/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_gdbstub/xtensa -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_gdbstub/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/espcoredump/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/espcoredump/include/port/xtensa -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/wpa_supplicant/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/wpa_supplicant/port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/wpa_supplicant/esp_supplicant/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/ieee802154/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/console -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/asio/asio/asio/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/asio/port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/bt/common/osi/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/bt/include/esp32/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/bt/common/api/include/api -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/bt/common/btc/profile/esp/blufi/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/bt/common/btc/profile/esp/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/bt/host/bluedroid/api/include/api -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/cbor/port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/unity/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/unity/unity/src -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/cmock/CMock/src -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/coap/port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/coap/libcoap/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/nghttp/port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/nghttp/nghttp2/lib/includes -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-tls -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-tls/esp-tls-crypto -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_adc_cal/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_hid/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/tcp_transport/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_http_client/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_http_server/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_https_ota/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_lcd/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_lcd/interface -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/protobuf-c/protobuf-c -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/protocomm/include/common -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/protocomm/include/security -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/protocomm/include/transports -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/mdns/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_local_ctrl/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/sdmmc/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_serial_slave_link/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_websocket_client/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/expat/expat/expat/lib -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/expat/port/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/wear_levelling/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/fatfs/diskio -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/fatfs/vfs -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/fatfs/src -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/freemodbus/common/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/idf_test/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/idf_test/include/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/jsmn/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/json/cJSON -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/libsodium/libsodium/src/libsodium/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/libsodium/port_include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/mqtt/esp-mqtt/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/openssl/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/perfmon/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/spiffs/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/ulp/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/wifi_provisioning/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/button/button/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/rmaker_common/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/json_parser/upstream/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/json_parser/upstream -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/json_generator/upstream -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_schedule/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_rainmaker/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/qrcode/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/ws2812_led -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/dotprod/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/support/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/windows/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/windows/hann/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/windows/blackman/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/windows/blackman_harris/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/windows/blackman_nuttall/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/windows/nuttall/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/windows/flat_top/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/iir/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/fir/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/math/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/math/add/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/math/sub/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/math/mul/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/math/addc/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/math/mulc/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/math/sqrt/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/matrix/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/fft/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/dct/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/conv/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/common/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/kalman/ekf/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dsp/modules/kalman/ekf_imu13states/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_littlefs/src -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp_littlefs/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/tool -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/typedef -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/image -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/math -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/nn -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/layer -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/detect -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-dl/include/model_zoo -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-sr/esp-tts/esp_tts_chinese/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp-sr/include/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp32-camera/driver/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/esp32-camera/conversions/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/include/fb_gfx/include -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/tools/sdk/esp32/qspi_qspi/include -mlongcalls -Wno-frame-address -ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -Os -freorder-blocks -Wwrite-strings -fstack-protector -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable -fno-jump-tables -fno-tree-switch-conversion -std=gnu++11 -fexceptions -fno-rtti -MMD -c -DF_CPU=240000000L -DARDUINO=10607 -DARDUINO_ESPino32 -DARDUINO_ARCH_ESP32 "-DARDUINO_BOARD=\"ESPino32\"" "-DARDUINO_VARIANT=\"espino32\"" -DARDUINO_PARTITION_default -DESP32 -DCORE_DEBUG_LEVEL=0 -DARDUINO_USB_CDC_ON_BOOT=0 @/tmp/arduino/sketches/002050EAA7EFB9A4FC451CDFBC0FA2D3/build_opt.h -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/cores/esp32 -I/home/megabug/.arduino15/packages/esp32/hardware/esp32/2.0.3/variants/espino32 -I/home/megabug/Arduino/libraries/Audio/src /tmp/arduino/sketches/002050EAA7EFB9A4FC451CDFBC0FA2D3/sketch/Blink.ino.cpp -o /tmp/arduino/sketches/002050EAA7EFB9A4FC451CDFBC0FA2D3/sketch/Blink.ino.cpp.o
+In file included from /home/megabug/Arduino/libraries/Audio/src/Audio.h:16,
+                 from /home/megabug/Arduino/Blink/Blink.ino:1:
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:21:15: error: expected ')' before '*' token
+  DACClass(Dacc *_dac, uint32_t _dacId, IRQn_Type _isrId) :
+          ~    ^~
+               )
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:35:2: error: 'Dacc' does not name a type
+  Dacc *dac;
+  ^~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:37:2: error: 'IRQn_Type' does not name a type
+  IRQn_Type isrId;
+  ^~~~~~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h: In member function 'void DACClass::enableInterrupts()':
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:31:43: error: 'isrId' was not declared in this scope
+ void enableInterrupts()  { NVIC_EnableIRQ(isrId); };
+                                           ^~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:31:28: error: 'NVIC_EnableIRQ' was not declared in this scope
+ void enableInterrupts()  { NVIC_EnableIRQ(isrId); };
+                            ^~~~~~~~~~~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h: In member function 'void DACClass::disableInterrupts()':
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:32:44: error: 'isrId' was not declared in this scope
+ void disableInterrupts() { NVIC_DisableIRQ(isrId); };
+                                            ^~~~~
+/home/megabug/Arduino/libraries/Audio/src/DAC.h:32:28: error: 'NVIC_DisableIRQ' was not declared in this scope
+ void disableInterrupts() { NVIC_DisableIRQ(isrId); };
+                            ^~~~~~~~~~~~~~~
+In file included from /home/megabug/Arduino/Blink/Blink.ino:1:
+/home/megabug/Arduino/libraries/Audio/src/Audio.h: In member function 'virtual size_t AudioClass::write(uint8_t)':
+/home/megabug/Arduino/libraries/Audio/src/Audio.h:25:82: warning: no return statement in function returning non-void [-Wreturn-type]
+  virtual size_t write(uint8_t c)                         { /* not implemented */ };
+                                                                                  ^
+/home/megabug/Arduino/Blink/Blink.ino: In function 'void setup()':
+/home/megabug/Arduino/Blink/Blink.ino:4:1: error: 'asd' was not declared in this scope
+ asd;
+ ^~~
+/home/megabug/Arduino/Blink/Blink.ino:4:1: note: suggested alternative: 'rand'
+ asd;
+ ^~~
+ rand
\ No newline at end of file
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test003.txt.json b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test003.txt.json
new file mode 100644
index 00000000000..5f9b36e4309
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test003.txt.json
@@ -0,0 +1,190 @@
+[
+  {
+    "severity": "ERROR",
+    "message": "expected ')' before '*' token\n  DACClass(Dacc *_dac, uint32_t _dacId, IRQn_Type _isrId) :\n          ~    ^~\n               )",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 21,
+    "col": 15,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'Dacc' does not name a type\n  Dacc *dac;\n  ^~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 35,
+    "col": 2,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'IRQn_Type' does not name a type\n  IRQn_Type isrId;\n  ^~~~~~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 37,
+    "col": 2,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'isrId' was not declared in this scope\n void enableInterrupts()  { NVIC_EnableIRQ(isrId); };\n                                           ^~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 31,
+    "col": 43,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::enableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'NVIC_EnableIRQ' was not declared in this scope\n void enableInterrupts()  { NVIC_EnableIRQ(isrId); };\n                            ^~~~~~~~~~~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 31,
+    "col": 28,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::enableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'isrId' was not declared in this scope\n void disableInterrupts() { NVIC_DisableIRQ(isrId); };\n                                            ^~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 32,
+    "col": 44,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::disableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'NVIC_DisableIRQ' was not declared in this scope\n void disableInterrupts() { NVIC_DisableIRQ(isrId); };\n                            ^~~~~~~~~~~~~~~",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h",
+    "line": 32,
+    "col": 28,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+        "line": 16
+      },
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'void DACClass::disableInterrupts()':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/DAC.h"
+      }
+    ]
+  },
+  {
+    "severity": "WARNING",
+    "message": "no return statement in function returning non-void [-Wreturn-type]\n  virtual size_t write(uint8_t c)                         { /* not implemented */ };\n                                                                                  ^",
+    "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h",
+    "line": 25,
+    "col": 82,
+    "context": [
+      {
+        "message": "included from here",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 1
+      },
+      {
+        "message": "In member function 'virtual size_t AudioClass::write(uint8_t)':",
+        "file": "/home/megabug/Arduino/libraries/Audio/src/Audio.h"
+      }
+    ]
+  },
+  {
+    "severity": "ERROR",
+    "message": "'asd' was not declared in this scope\n asd;\n ^~~",
+    "file": "/home/megabug/Arduino/Blink/Blink.ino",
+    "line": 4,
+    "col": 1,
+    "context": [
+      {
+        "message": "In function 'void setup()':",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino"
+      }
+    ],
+    "suggestions": [
+      {
+        "message": "suggested alternative: 'rand'\n asd;\n ^~~\n rand",
+        "file": "/home/megabug/Arduino/Blink/Blink.ino",
+        "line": 4,
+        "col": 1
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test004.txt b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test004.txt
new file mode 100644
index 00000000000..958800f68f5
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test004.txt
@@ -0,0 +1,5 @@
+C:\Users\runneradmin\AppData\Local\Temp\cli2123776893\A\packages\arduino\tools\avr-gcc\7.3.0-atmel3.6.1-arduino7/bin/avr-g++ -c -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10607 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -IC:\Users\runneradmin\AppData\Local\Temp\cli2123776893\A\packages\arduino\hardware\avr\1.8.5\cores\arduino -IC:\Users\runneradmin\AppData\Local\Temp\cli2123776893\A\packages\arduino\hardware\avr\1.8.5\variants\standard C:\Users\runneradmin\AppData\Local\Temp\arduino\sketches\BD9E9425D0ACEC4A9F5E44E2417C33A5\sketch\wrong.cpp -o C:\Users\runneradmin\AppData\Local\Temp\arduino\sketches\BD9E9425D0ACEC4A9F5E44E2417C33A5\sketch\wrong.cpp.o
+D:\a\arduino-cli\arduino-cli\internal\integrationtest\compile_3\testdata\blink_with_wrong_cpp\wrong.cpp: In function 'void wrong()':
+D:\a\arduino-cli\arduino-cli\internal\integrationtest\compile_3\testdata\blink_with_wrong_cpp\wrong.cpp:1:14: error: expected '}' at end of input
+ void wrong() {
+              ^
diff --git a/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test004.txt.json b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test004.txt.json
new file mode 100644
index 00000000000..e436025aee2
--- /dev/null
+++ b/arduino/builder/internal/diagnostics/testdata/compiler_outputs/test004.txt.json
@@ -0,0 +1,15 @@
+[
+  {
+    "severity": "ERROR",
+    "message": "expected '}' at end of input\n void wrong() {\n              ^",
+    "file": "D:\\a\\arduino-cli\\arduino-cli\\internal\\integrationtest\\compile_3\\testdata\\blink_with_wrong_cpp\\wrong.cpp",
+    "line": 1,
+    "col": 14,
+    "context": [
+      {
+        "message": "In function 'void wrong()':",
+        "file": "D:\\a\\arduino-cli\\arduino-cli\\internal\\integrationtest\\compile_3\\testdata\\blink_with_wrong_cpp\\wrong.cpp"
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/commands/compile/compile.go b/commands/compile/compile.go
index 604a7acb215..c168f27998a 100644
--- a/commands/compile/compile.go
+++ b/commands/compile/compile.go
@@ -177,6 +177,7 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
 	if pme.GetProfile() != nil {
 		libsManager = lm
 	}
+
 	sketchBuilder, err := builder.NewBuilder(
 		sk,
 		boardBuildProperties,
@@ -218,6 +219,10 @@ func Compile(ctx context.Context, req *rpc.CompileRequest, outStream, errStream
 		}
 	}()
 
+	defer func() {
+		r.Diagnostics = sketchBuilder.CompilerDiagnostics().ToRPC()
+	}()
+
 	defer func() {
 		buildProperties := sketchBuilder.GetBuildProperties()
 		if buildProperties == nil {
diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go
index 8f371d5b060..1204b529f17 100644
--- a/internal/cli/compile/compile.go
+++ b/internal/cli/compile/compile.go
@@ -348,6 +348,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) {
 			UpdatedUploadPort: result.NewPort(uploadRes.GetUpdatedUploadPort()),
 		},
 		ProfileOut:         profileOut,
+		Diagnostics:        result.NewCompileDiagnostics(compileRes.GetDiagnostics()),
 		Success:            compileError == nil,
 		showPropertiesMode: showProperties,
 		hideStats:          preprocess,
@@ -392,14 +393,14 @@ type updatedUploadPortResult struct {
 }
 
 type compileResult struct {
-	CompilerOut   string                  `json:"compiler_out"`
-	CompilerErr   string                  `json:"compiler_err"`
-	BuilderResult *result.CompileResponse `json:"builder_result"`
-	UploadResult  updatedUploadPortResult `json:"upload_result"`
-	Success       bool                    `json:"success"`
-	ProfileOut    string                  `json:"profile_out,omitempty"`
-	Error         string                  `json:"error,omitempty"`
-
+	CompilerOut        string                      `json:"compiler_out"`
+	CompilerErr        string                      `json:"compiler_err"`
+	BuilderResult      *result.CompileResponse     `json:"builder_result"`
+	UploadResult       updatedUploadPortResult     `json:"upload_result"`
+	Success            bool                        `json:"success"`
+	ProfileOut         string                      `json:"profile_out,omitempty"`
+	Error              string                      `json:"error,omitempty"`
+	Diagnostics        []*result.CompileDiagnostic `json:"diagnostics,omitempty"`
 	showPropertiesMode arguments.ShowPropertiesMode
 	hideStats          bool
 }
diff --git a/internal/cli/feedback/result/rpc.go b/internal/cli/feedback/result/rpc.go
index 6b19c138a6d..a632af7737c 100644
--- a/internal/cli/feedback/result/rpc.go
+++ b/internal/cli/feedback/result/rpc.go
@@ -18,6 +18,7 @@ package result
 import (
 	"cmp"
 
+	f "github.com/arduino/arduino-cli/internal/algorithms"
 	"github.com/arduino/arduino-cli/internal/orderedmap"
 	rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
 	semver "go.bug.st/relaxed-semver"
@@ -880,6 +881,7 @@ type CompileResponse struct {
 	BoardPlatform          *InstalledPlatformReference `json:"board_platform,omitempty"`
 	BuildPlatform          *InstalledPlatformReference `json:"build_platform,omitempty"`
 	BuildProperties        []string                    `json:"build_properties,omitempty"`
+	Diagnostics            []*CompileDiagnostic        `json:"diagnostics,omitempty"`
 }
 
 func NewCompileResponse(c *rpc.CompileResponse) *CompileResponse {
@@ -904,6 +906,7 @@ func NewCompileResponse(c *rpc.CompileResponse) *CompileResponse {
 		BoardPlatform:          NewInstalledPlatformReference(c.GetBoardPlatform()),
 		BuildPlatform:          NewInstalledPlatformReference(c.GetBuildPlatform()),
 		BuildProperties:        c.GetBuildProperties(),
+		Diagnostics:            NewCompileDiagnostics(c.GetDiagnostics()),
 	}
 }
 
@@ -959,3 +962,61 @@ func NewBoardListWatchResponse(r *rpc.BoardListWatchResponse) *BoardListWatchRes
 		Error:     r.Error,
 	}
 }
+
+type CompileDiagnostic struct {
+	Severity string                      `json:"severity,omitempty"`
+	Message  string                      `json:"message,omitempty"`
+	File     string                      `json:"file,omitempty"`
+	Line     int64                       `json:"line,omitempty"`
+	Column   int64                       `json:"column,omitempty"`
+	Context  []*CompileDiagnosticContext `json:"context,omitempty"`
+	Notes    []*CompileDiagnosticNote    `json:"notes,omitempty"`
+}
+
+func NewCompileDiagnostics(cd []*rpc.CompileDiagnostic) []*CompileDiagnostic {
+	return f.Map(cd, NewCompileDiagnostic)
+}
+
+func NewCompileDiagnostic(cd *rpc.CompileDiagnostic) *CompileDiagnostic {
+	return &CompileDiagnostic{
+		Severity: cd.GetSeverity(),
+		Message:  cd.GetMessage(),
+		File:     cd.GetFile(),
+		Line:     cd.GetLine(),
+		Column:   cd.GetColumn(),
+		Context:  f.Map(cd.GetContext(), NewCompileDiagnosticContext),
+		Notes:    f.Map(cd.GetNotes(), NewCompileDiagnosticNote),
+	}
+}
+
+type CompileDiagnosticContext struct {
+	Message string `json:"message,omitempty"`
+	File    string `json:"file,omitempty"`
+	Line    int64  `json:"line,omitempty"`
+	Column  int64  `json:"column,omitempty"`
+}
+
+func NewCompileDiagnosticContext(cdc *rpc.CompileDiagnosticContext) *CompileDiagnosticContext {
+	return &CompileDiagnosticContext{
+		Message: cdc.GetMessage(),
+		File:    cdc.GetFile(),
+		Line:    cdc.GetLine(),
+		Column:  cdc.GetColumn(),
+	}
+}
+
+type CompileDiagnosticNote struct {
+	Message string `json:"message,omitempty"`
+	File    string `json:"file,omitempty"`
+	Line    int64  `json:"line,omitempty"`
+	Column  int64  `json:"column,omitempty"`
+}
+
+func NewCompileDiagnosticNote(cdn *rpc.CompileDiagnosticNote) *CompileDiagnosticNote {
+	return &CompileDiagnosticNote{
+		Message: cdn.GetMessage(),
+		File:    cdn.GetFile(),
+		Line:    cdn.GetLine(),
+		Column:  cdn.GetColumn(),
+	}
+}
diff --git a/internal/cli/feedback/result/rpc_test.go b/internal/cli/feedback/result/rpc_test.go
index 46adbcd8acc..af5259d128e 100644
--- a/internal/cli/feedback/result/rpc_test.go
+++ b/internal/cli/feedback/result/rpc_test.go
@@ -205,6 +205,18 @@ func TestAllFieldAreMapped(t *testing.T) {
 	boardListWatchResponseRpc := &rpc.BoardListWatchResponse{}
 	boardListWatchResponseResult := result.NewBoardListWatchResponse(boardListWatchResponseRpc)
 	mustContainsAllPropertyOfRpcStruct(t, boardListWatchResponseRpc, boardListWatchResponseResult)
+
+	compileDiagnosticRpc := &rpc.CompileDiagnostic{}
+	compileDiagnosticResult := result.NewCompileDiagnostic(compileDiagnosticRpc)
+	mustContainsAllPropertyOfRpcStruct(t, compileDiagnosticRpc, compileDiagnosticResult)
+
+	compileDiagnosticContextRpc := &rpc.CompileDiagnosticContext{}
+	compileDiagnosticContextResult := result.NewCompileDiagnosticContext(compileDiagnosticContextRpc)
+	mustContainsAllPropertyOfRpcStruct(t, compileDiagnosticContextRpc, compileDiagnosticContextResult)
+
+	compileDiagnosticNoteRpc := &rpc.CompileDiagnosticNote{}
+	compileDiagnosticNoteResult := result.NewCompileDiagnosticNote(compileDiagnosticNoteRpc)
+	mustContainsAllPropertyOfRpcStruct(t, compileDiagnosticNoteRpc, compileDiagnosticNoteResult)
 }
 
 func TestEnumsMapsEveryRpcCounterpart(t *testing.T) {
diff --git a/internal/integrationtest/compile_3/compile_test.go b/internal/integrationtest/compile_3/compile_test.go
index 2df3d59f40d..2f9ba8e5306 100644
--- a/internal/integrationtest/compile_3/compile_test.go
+++ b/internal/integrationtest/compile_3/compile_test.go
@@ -113,10 +113,19 @@ func TestCompilerErrOutput(t *testing.T) {
 		require.NoError(t, err)
 
 		// Run compile and catch err stream
-		out, _, err := cli.Run("compile", "-b", "arduino:avr:uno", "--format", "json", sketch.String())
+		out, _, err := cli.Run("compile", "-b", "arduino:avr:uno", "-v", "--format", "json", sketch.String())
 		require.Error(t, err)
-		compilerErr := requirejson.Parse(t, out).Query(".compiler_err")
-		compilerErr.MustContain(`"error"`)
+		outJson := requirejson.Parse(t, out)
+		outJson.Query(`.compiler_err`).MustContain(`"error"`)
+		outJson.Query(`.diagnostics`).MustContain(`
+		[
+			{
+			  "severity": "ERROR",
+			  "line": 1,
+			  "column": 14,
+			  "context": [ { "message": "In function 'void wrong()':" } ]
+			}
+		]`)
 	}
 
 	// Check that library discover do not generate false errors
@@ -132,6 +141,7 @@ func TestCompilerErrOutput(t *testing.T) {
 		jsonOut := requirejson.Parse(t, out)
 		jsonOut.Query(".compiler_out").MustNotContain(`"fatal error"`)
 		jsonOut.Query(".compiler_err").MustNotContain(`"fatal error"`)
+		jsonOut.MustNotContain(`{ "diagnostics" : [] }`)
 	}
 }
 
diff --git a/rpc/cc/arduino/cli/commands/v1/compile.pb.go b/rpc/cc/arduino/cli/commands/v1/compile.pb.go
index 7f3a8c6801c..d5564454b25 100644
--- a/rpc/cc/arduino/cli/commands/v1/compile.pb.go
+++ b/rpc/cc/arduino/cli/commands/v1/compile.pb.go
@@ -343,6 +343,8 @@ type CompileResponse struct {
 	Progress *TaskProgress `protobuf:"bytes,8,opt,name=progress,proto3" json:"progress,omitempty"`
 	// Build properties used for compiling
 	BuildProperties []string `protobuf:"bytes,9,rep,name=build_properties,json=buildProperties,proto3" json:"build_properties,omitempty"`
+	// Compiler errors and warnings
+	Diagnostics []*CompileDiagnostic `protobuf:"bytes,10,rep,name=diagnostics,proto3" json:"diagnostics,omitempty"`
 }
 
 func (x *CompileResponse) Reset() {
@@ -440,6 +442,13 @@ func (x *CompileResponse) GetBuildProperties() []string {
 	return nil
 }
 
+func (x *CompileResponse) GetDiagnostics() []*CompileDiagnostic {
+	if x != nil {
+		return x.Diagnostics
+	}
+	return nil
+}
+
 type ExecutableSectionSize struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -503,6 +512,260 @@ func (x *ExecutableSectionSize) GetMaxSize() int64 {
 	return 0
 }
 
+type CompileDiagnostic struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Severity of the diagnostic
+	Severity string `protobuf:"bytes,1,opt,name=severity,proto3" json:"severity,omitempty"`
+	// The explanation of the diagnostic (it may be multiple preformatted lines)
+	Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+	// The file containing the diagnostic
+	File string `protobuf:"bytes,3,opt,name=file,proto3" json:"file,omitempty"`
+	// The line of the diagnostic if available (starts from 1)
+	Line int64 `protobuf:"varint,4,opt,name=line,proto3" json:"line,omitempty"`
+	// The column of the diagnostic if available (starts from 1)
+	Column int64 `protobuf:"varint,5,opt,name=column,proto3" json:"column,omitempty"`
+	// The context where this diagnostic is found (it may be multiple files that
+	// represents a chain of includes, or a text describing where the diagnostic
+	// is found)
+	Context []*CompileDiagnosticContext `protobuf:"bytes,6,rep,name=context,proto3" json:"context,omitempty"`
+	// Annotations or suggestions to the diagnostic made by the compiler
+	Notes []*CompileDiagnosticNote `protobuf:"bytes,7,rep,name=notes,proto3" json:"notes,omitempty"`
+}
+
+func (x *CompileDiagnostic) Reset() {
+	*x = CompileDiagnostic{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CompileDiagnostic) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CompileDiagnostic) ProtoMessage() {}
+
+func (x *CompileDiagnostic) ProtoReflect() protoreflect.Message {
+	mi := &file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CompileDiagnostic.ProtoReflect.Descriptor instead.
+func (*CompileDiagnostic) Descriptor() ([]byte, []int) {
+	return file_cc_arduino_cli_commands_v1_compile_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *CompileDiagnostic) GetSeverity() string {
+	if x != nil {
+		return x.Severity
+	}
+	return ""
+}
+
+func (x *CompileDiagnostic) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *CompileDiagnostic) GetFile() string {
+	if x != nil {
+		return x.File
+	}
+	return ""
+}
+
+func (x *CompileDiagnostic) GetLine() int64 {
+	if x != nil {
+		return x.Line
+	}
+	return 0
+}
+
+func (x *CompileDiagnostic) GetColumn() int64 {
+	if x != nil {
+		return x.Column
+	}
+	return 0
+}
+
+func (x *CompileDiagnostic) GetContext() []*CompileDiagnosticContext {
+	if x != nil {
+		return x.Context
+	}
+	return nil
+}
+
+func (x *CompileDiagnostic) GetNotes() []*CompileDiagnosticNote {
+	if x != nil {
+		return x.Notes
+	}
+	return nil
+}
+
+type CompileDiagnosticContext struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The message describing the context reference
+	Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	// The file of the context reference
+	File string `protobuf:"bytes,2,opt,name=file,proto3" json:"file,omitempty"`
+	// The line of the context reference
+	Line int64 `protobuf:"varint,3,opt,name=line,proto3" json:"line,omitempty"`
+	// The column of the context reference
+	Column int64 `protobuf:"varint,4,opt,name=column,proto3" json:"column,omitempty"`
+}
+
+func (x *CompileDiagnosticContext) Reset() {
+	*x = CompileDiagnosticContext{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CompileDiagnosticContext) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CompileDiagnosticContext) ProtoMessage() {}
+
+func (x *CompileDiagnosticContext) ProtoReflect() protoreflect.Message {
+	mi := &file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CompileDiagnosticContext.ProtoReflect.Descriptor instead.
+func (*CompileDiagnosticContext) Descriptor() ([]byte, []int) {
+	return file_cc_arduino_cli_commands_v1_compile_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *CompileDiagnosticContext) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *CompileDiagnosticContext) GetFile() string {
+	if x != nil {
+		return x.File
+	}
+	return ""
+}
+
+func (x *CompileDiagnosticContext) GetLine() int64 {
+	if x != nil {
+		return x.Line
+	}
+	return 0
+}
+
+func (x *CompileDiagnosticContext) GetColumn() int64 {
+	if x != nil {
+		return x.Column
+	}
+	return 0
+}
+
+type CompileDiagnosticNote struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The message describing the compiler note
+	Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+	// The file of the compiler note
+	File string `protobuf:"bytes,2,opt,name=file,proto3" json:"file,omitempty"`
+	// The line of the compiler note
+	Line int64 `protobuf:"varint,3,opt,name=line,proto3" json:"line,omitempty"`
+	// The column of the compiler note
+	Column int64 `protobuf:"varint,4,opt,name=column,proto3" json:"column,omitempty"`
+}
+
+func (x *CompileDiagnosticNote) Reset() {
+	*x = CompileDiagnosticNote{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CompileDiagnosticNote) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CompileDiagnosticNote) ProtoMessage() {}
+
+func (x *CompileDiagnosticNote) ProtoReflect() protoreflect.Message {
+	mi := &file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CompileDiagnosticNote.ProtoReflect.Descriptor instead.
+func (*CompileDiagnosticNote) Descriptor() ([]byte, []int) {
+	return file_cc_arduino_cli_commands_v1_compile_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *CompileDiagnosticNote) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
+func (x *CompileDiagnosticNote) GetFile() string {
+	if x != nil {
+		return x.File
+	}
+	return ""
+}
+
+func (x *CompileDiagnosticNote) GetLine() int64 {
+	if x != nil {
+		return x.Line
+	}
+	return 0
+}
+
+func (x *CompileDiagnosticNote) GetColumn() int64 {
+	if x != nil {
+		return x.Column
+	}
+	return 0
+}
+
 var File_cc_arduino_cli_commands_v1_compile_proto protoreflect.FileDescriptor
 
 var file_cc_arduino_cli_commands_v1_compile_proto_rawDesc = []byte{
@@ -587,7 +850,7 @@ var file_cc_arduino_cli_commands_v1_compile_proto_rawDesc = []byte{
 	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
 	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
 	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
-	0x22, 0xd6, 0x04, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70,
+	0x22, 0xa7, 0x05, 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70,
 	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x65,
 	0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6f, 0x75, 0x74, 0x53, 0x74, 0x72,
 	0x65, 0x61, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61,
@@ -624,18 +887,56 @@ var file_cc_arduino_cli_commands_v1_compile_proto_rawDesc = []byte{
 	0x72, 0x65, 0x73, 0x73, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x29,
 	0x0a, 0x10, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69,
 	0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x50,
-	0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x5a, 0x0a, 0x15, 0x45, 0x78, 0x65,
-	0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69,
-	0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61,
-	0x78, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d, 0x61,
-	0x78, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
-	0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75,
-	0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61,
-	0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
-	0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62,
-	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x4f, 0x0a, 0x0b, 0x64, 0x69, 0x61,
+	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d,
+	0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e,
+	0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70,
+	0x69, 0x6c, 0x65, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x0b, 0x64,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x73, 0x22, 0x5a, 0x0a, 0x15, 0x45, 0x78,
+	0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53,
+	0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6d,
+	0x61, 0x78, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6d,
+	0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x22, 0xa2, 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x69,
+	0x6c, 0x65, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x12, 0x1a, 0x0a, 0x08,
+	0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
+	0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73,
+	0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f,
+	0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75,
+	0x6d, 0x6e, 0x12, 0x4e, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x06, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f,
+	0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31,
+	0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
+	0x69, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+	0x78, 0x74, 0x12, 0x47, 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x31, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63,
+	0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43,
+	0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x4e, 0x6f, 0x74, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x22, 0x74, 0x0a, 0x18, 0x43,
+	0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
+	0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6c,
+	0x75, 0x6d, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d,
+	0x6e, 0x22, 0x71, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x44, 0x69, 0x61, 0x67,
+	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x4e, 0x6f, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x65,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06,
+	0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x63, 0x6f,
+	0x6c, 0x75, 0x6d, 0x6e, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
+	0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69,
+	0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, 0x72,
+	0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
+	0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -650,32 +951,38 @@ func file_cc_arduino_cli_commands_v1_compile_proto_rawDescGZIP() []byte {
 	return file_cc_arduino_cli_commands_v1_compile_proto_rawDescData
 }
 
-var file_cc_arduino_cli_commands_v1_compile_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_cc_arduino_cli_commands_v1_compile_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
 var file_cc_arduino_cli_commands_v1_compile_proto_goTypes = []interface{}{
 	(*CompileRequest)(nil),             // 0: cc.arduino.cli.commands.v1.CompileRequest
 	(*CompileResponse)(nil),            // 1: cc.arduino.cli.commands.v1.CompileResponse
 	(*ExecutableSectionSize)(nil),      // 2: cc.arduino.cli.commands.v1.ExecutableSectionSize
-	nil,                                // 3: cc.arduino.cli.commands.v1.CompileRequest.SourceOverrideEntry
-	(*Instance)(nil),                   // 4: cc.arduino.cli.commands.v1.Instance
-	(*wrapperspb.BoolValue)(nil),       // 5: google.protobuf.BoolValue
-	(*Library)(nil),                    // 6: cc.arduino.cli.commands.v1.Library
-	(*InstalledPlatformReference)(nil), // 7: cc.arduino.cli.commands.v1.InstalledPlatformReference
-	(*TaskProgress)(nil),               // 8: cc.arduino.cli.commands.v1.TaskProgress
+	(*CompileDiagnostic)(nil),          // 3: cc.arduino.cli.commands.v1.CompileDiagnostic
+	(*CompileDiagnosticContext)(nil),   // 4: cc.arduino.cli.commands.v1.CompileDiagnosticContext
+	(*CompileDiagnosticNote)(nil),      // 5: cc.arduino.cli.commands.v1.CompileDiagnosticNote
+	nil,                                // 6: cc.arduino.cli.commands.v1.CompileRequest.SourceOverrideEntry
+	(*Instance)(nil),                   // 7: cc.arduino.cli.commands.v1.Instance
+	(*wrapperspb.BoolValue)(nil),       // 8: google.protobuf.BoolValue
+	(*Library)(nil),                    // 9: cc.arduino.cli.commands.v1.Library
+	(*InstalledPlatformReference)(nil), // 10: cc.arduino.cli.commands.v1.InstalledPlatformReference
+	(*TaskProgress)(nil),               // 11: cc.arduino.cli.commands.v1.TaskProgress
 }
 var file_cc_arduino_cli_commands_v1_compile_proto_depIdxs = []int32{
-	4, // 0: cc.arduino.cli.commands.v1.CompileRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance
-	3, // 1: cc.arduino.cli.commands.v1.CompileRequest.source_override:type_name -> cc.arduino.cli.commands.v1.CompileRequest.SourceOverrideEntry
-	5, // 2: cc.arduino.cli.commands.v1.CompileRequest.export_binaries:type_name -> google.protobuf.BoolValue
-	6, // 3: cc.arduino.cli.commands.v1.CompileResponse.used_libraries:type_name -> cc.arduino.cli.commands.v1.Library
-	2, // 4: cc.arduino.cli.commands.v1.CompileResponse.executable_sections_size:type_name -> cc.arduino.cli.commands.v1.ExecutableSectionSize
-	7, // 5: cc.arduino.cli.commands.v1.CompileResponse.board_platform:type_name -> cc.arduino.cli.commands.v1.InstalledPlatformReference
-	7, // 6: cc.arduino.cli.commands.v1.CompileResponse.build_platform:type_name -> cc.arduino.cli.commands.v1.InstalledPlatformReference
-	8, // 7: cc.arduino.cli.commands.v1.CompileResponse.progress:type_name -> cc.arduino.cli.commands.v1.TaskProgress
-	8, // [8:8] is the sub-list for method output_type
-	8, // [8:8] is the sub-list for method input_type
-	8, // [8:8] is the sub-list for extension type_name
-	8, // [8:8] is the sub-list for extension extendee
-	0, // [0:8] is the sub-list for field type_name
+	7,  // 0: cc.arduino.cli.commands.v1.CompileRequest.instance:type_name -> cc.arduino.cli.commands.v1.Instance
+	6,  // 1: cc.arduino.cli.commands.v1.CompileRequest.source_override:type_name -> cc.arduino.cli.commands.v1.CompileRequest.SourceOverrideEntry
+	8,  // 2: cc.arduino.cli.commands.v1.CompileRequest.export_binaries:type_name -> google.protobuf.BoolValue
+	9,  // 3: cc.arduino.cli.commands.v1.CompileResponse.used_libraries:type_name -> cc.arduino.cli.commands.v1.Library
+	2,  // 4: cc.arduino.cli.commands.v1.CompileResponse.executable_sections_size:type_name -> cc.arduino.cli.commands.v1.ExecutableSectionSize
+	10, // 5: cc.arduino.cli.commands.v1.CompileResponse.board_platform:type_name -> cc.arduino.cli.commands.v1.InstalledPlatformReference
+	10, // 6: cc.arduino.cli.commands.v1.CompileResponse.build_platform:type_name -> cc.arduino.cli.commands.v1.InstalledPlatformReference
+	11, // 7: cc.arduino.cli.commands.v1.CompileResponse.progress:type_name -> cc.arduino.cli.commands.v1.TaskProgress
+	3,  // 8: cc.arduino.cli.commands.v1.CompileResponse.diagnostics:type_name -> cc.arduino.cli.commands.v1.CompileDiagnostic
+	4,  // 9: cc.arduino.cli.commands.v1.CompileDiagnostic.context:type_name -> cc.arduino.cli.commands.v1.CompileDiagnosticContext
+	5,  // 10: cc.arduino.cli.commands.v1.CompileDiagnostic.notes:type_name -> cc.arduino.cli.commands.v1.CompileDiagnosticNote
+	11, // [11:11] is the sub-list for method output_type
+	11, // [11:11] is the sub-list for method input_type
+	11, // [11:11] is the sub-list for extension type_name
+	11, // [11:11] is the sub-list for extension extendee
+	0,  // [0:11] is the sub-list for field type_name
 }
 
 func init() { file_cc_arduino_cli_commands_v1_compile_proto_init() }
@@ -722,6 +1029,42 @@ func file_cc_arduino_cli_commands_v1_compile_proto_init() {
 				return nil
 			}
 		}
+		file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CompileDiagnostic); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CompileDiagnosticContext); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_cc_arduino_cli_commands_v1_compile_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CompileDiagnosticNote); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -729,7 +1072,7 @@ func file_cc_arduino_cli_commands_v1_compile_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_cc_arduino_cli_commands_v1_compile_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   4,
+			NumMessages:   7,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/rpc/cc/arduino/cli/commands/v1/compile.proto b/rpc/cc/arduino/cli/commands/v1/compile.proto
index ff160ba1c01..57c6ca9d23d 100644
--- a/rpc/cc/arduino/cli/commands/v1/compile.proto
+++ b/rpc/cc/arduino/cli/commands/v1/compile.proto
@@ -115,6 +115,8 @@ message CompileResponse {
   TaskProgress progress = 8;
   // Build properties used for compiling
   repeated string build_properties = 9;
+  // Compiler errors and warnings
+  repeated CompileDiagnostic diagnostics = 10;
 }
 
 message ExecutableSectionSize {
@@ -122,3 +124,44 @@ message ExecutableSectionSize {
   int64 size = 2;
   int64 max_size = 3;
 }
+
+message CompileDiagnostic {
+  // Severity of the diagnostic
+  string severity = 1;
+  // The explanation of the diagnostic (it may be multiple preformatted lines)
+  string message = 2;
+  // The file containing the diagnostic
+  string file = 3;
+  // The line of the diagnostic if available (starts from 1)
+  int64 line = 4;
+  // The column of the diagnostic if available (starts from 1)
+  int64 column = 5;
+  // The context where this diagnostic is found (it may be multiple files that
+  // represents a chain of includes, or a text describing where the diagnostic
+  // is found)
+  repeated CompileDiagnosticContext context = 6;
+  // Annotations or suggestions to the diagnostic made by the compiler
+  repeated CompileDiagnosticNote notes = 7;
+}
+
+message CompileDiagnosticContext {
+  // The message describing the context reference
+  string message = 1;
+  // The file of the context reference
+  string file = 2;
+  // The line of the context reference
+  int64 line = 3;
+  // The column of the context reference
+  int64 column = 4;
+}
+
+message CompileDiagnosticNote {
+  // The message describing the compiler note
+  string message = 1;
+  // The file of the compiler note
+  string file = 2;
+  // The line of the compiler note
+  int64 line = 3;
+  // The column of the compiler note
+  int64 column = 4;
+}