diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml
index 8feed628a2a..87356de2458 100644
--- a/.github/workflows/golangci-lint.yml
+++ b/.github/workflows/golangci-lint.yml
@@ -25,10 +25,10 @@ jobs:
           go-version-file: .go-version
 
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@v6
+        uses: golangci/golangci-lint-action@v6.1.1
         with:
           # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
-          version: v1.55.2
+          version: v1.61.0
 
           # Give the job more time to execute.
           # Regarding `--whole-files`, the linter is supposed to support linting of changed a patch only but,
diff --git a/NOTICE.txt b/NOTICE.txt
index 19d663c021a..95b45b8f680 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -6066,6 +6066,217 @@ Contents of probable licence file $GOMODCACHE/github.com/open-telemetry/opentele
    limitations under the License.
 
 
+--------------------------------------------------------------------------------
+Dependency : github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status
+Version: v0.113.0
+Licence type (autodetected): Apache-2.0
+--------------------------------------------------------------------------------
+
+Contents of probable licence file $GOMODCACHE/github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status@v0.113.0/LICENSE:
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
 --------------------------------------------------------------------------------
 Dependency : github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor
 Version: v0.113.0
@@ -11156,12 +11367,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/comp
 
 
 --------------------------------------------------------------------------------
-Dependency : go.opentelemetry.io/collector/confmap
-Version: v1.19.0
+Dependency : go.opentelemetry.io/collector/component/componentstatus
+Version: v0.113.0
 Licence type (autodetected): Apache-2.0
 --------------------------------------------------------------------------------
 
-Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/confmap@v1.19.0/LICENSE:
+Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/component/componentstatus@v0.113.0/LICENSE:
 
 
                                  Apache License
@@ -11368,12 +11579,12 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/conf
 
 
 --------------------------------------------------------------------------------
-Dependency : go.opentelemetry.io/collector/confmap/converter/expandconverter
-Version: v0.113.0
+Dependency : go.opentelemetry.io/collector/confmap
+Version: v1.19.0
 Licence type (autodetected): Apache-2.0
 --------------------------------------------------------------------------------
 
-Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/confmap/converter/expandconverter@v0.113.0/LICENSE:
+Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/confmap@v1.19.0/LICENSE:
 
 
                                  Apache License
@@ -79354,218 +79565,6 @@ Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/clie
    limitations under the License.
 
 
---------------------------------------------------------------------------------
-Dependency : go.opentelemetry.io/collector/component/componentstatus
-Version: v0.113.0
-Licence type (autodetected): Apache-2.0
---------------------------------------------------------------------------------
-
-Contents of probable licence file $GOMODCACHE/go.opentelemetry.io/collector/component/componentstatus@v0.113.0/LICENSE:
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-
 --------------------------------------------------------------------------------
 Dependency : go.opentelemetry.io/collector/config/configauth
 Version: v0.113.0
diff --git a/changelog/fragments/1729011748-Add-EDOT-hybrid-mode.yaml b/changelog/fragments/1729011748-Add-EDOT-hybrid-mode.yaml
new file mode 100644
index 00000000000..f7ed858e654
--- /dev/null
+++ b/changelog/fragments/1729011748-Add-EDOT-hybrid-mode.yaml
@@ -0,0 +1,32 @@
+# Kind can be one of:
+# - breaking-change: a change to previously-documented behavior
+# - deprecation: functionality that is being removed in a later release
+# - bug-fix: fixes a problem in a previous version
+# - enhancement: extends functionality but does not break or fix existing behavior
+# - feature: new functionality
+# - known-issue: problems that we are aware of in a given version
+# - security: impacts on the security of a product or a user’s deployment.
+# - upgrade: important information for someone upgrading from a prior version
+# - other: does not fit into any of the other categories
+kind: feature
+
+# Change summary; a 80ish characters long description of the change.
+summary: Add ability to run Elastic Distribution of OTel Collector at the same time as other inputs
+
+# Long description; in case the summary is not enough to describe the change
+# this field accommodate a description without length limits.
+# NOTE: This field will be rendered only for breaking-change and known-issue kinds at the moment.
+#description:
+
+# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
+component: elastic-agent
+
+# PR URL; optional; the PR number that added the changeset.
+# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
+# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
+# Please provide it if you are adding a fragment for a different PR.
+pr: https://github.com/elastic/elastic-agent/pull/5767
+
+# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
+# If not present is automatically filled by the tooling with the issue linked to the PR number.
+#issue: https://github.com/owner/repo/1234
diff --git a/control_v2.proto b/control_v2.proto
index 3437fa39e59..ad8efdfe7f8 100644
--- a/control_v2.proto
+++ b/control_v2.proto
@@ -23,6 +23,18 @@ enum State {
   ROLLBACK = 8;
 }
 
+// CollectorComponentStatus used for OTel collector components.
+enum CollectorComponentStatus {
+    StatusNone = 0;
+    StatusStarting = 1;
+    StatusOK = 2;
+    StatusRecoverableError = 3;
+    StatusPermanentError = 4;
+    StatusFatalError = 5;
+    StatusStopping = 6;
+    StatusStopped = 7;
+}
+
 // Unit Type running inside a component.
 enum UnitType {
   INPUT = 0;
@@ -173,6 +185,18 @@ message StateAgentInfo {
   bool isManaged = 8;
 }
 
+// CollectorComponent is the status of an OTel collector component.
+message CollectorComponent {
+  // Status of the component.
+  CollectorComponentStatus status = 1;
+  // Error is set to the reported error.
+  string error = 2;
+  // Timestamp of status.
+  string timestamp = 3;
+  // Status information for sub-components of this component.
+  map<string, CollectorComponent> ComponentStatusMap = 4;
+}
+
 // StateResponse is the current state of Elastic Agent.
 // Next unused id: 8
 message StateResponse {
@@ -194,6 +218,9 @@ message StateResponse {
 
   // Upgrade details
   UpgradeDetails upgrade_details = 7;
+
+  // OTel collector component status information.
+  CollectorComponent collector = 8;
 }
 
 // UpgradeDetails captures the details of an ongoing Agent upgrade.
diff --git a/go.mod b/go.mod
index 232bfcb0a68..0b64c0408ba 100644
--- a/go.mod
+++ b/go.mod
@@ -44,6 +44,7 @@ require (
 	github.com/oklog/ulid/v2 v2.1.0
 	github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.113.0
 	github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension v0.113.0
+	github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status v0.113.0
 	github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.113.0
 	github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.113.0
 	github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.113.0
@@ -62,6 +63,7 @@ require (
 	go.elastic.co/apm/v2 v2.6.0
 	go.elastic.co/ecszap v1.0.2
 	go.elastic.co/go-licence-detector v0.7.0
+	go.opentelemetry.io/collector/component/componentstatus v0.113.0
 	go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.113.0
 	go.uber.org/zap v1.27.0
 	golang.org/x/crypto v0.28.0
@@ -109,7 +111,6 @@ require (
 	github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver v0.113.0
 	go.opentelemetry.io/collector/component v0.113.0
 	go.opentelemetry.io/collector/confmap v1.19.0
-	go.opentelemetry.io/collector/confmap/converter/expandconverter v0.113.0
 	go.opentelemetry.io/collector/confmap/provider/envprovider v1.19.0
 	go.opentelemetry.io/collector/confmap/provider/fileprovider v1.19.0
 	go.opentelemetry.io/collector/confmap/provider/httpprovider v1.19.0
@@ -497,7 +498,6 @@ require (
 	go.opencensus.io v0.24.0 // indirect
 	go.opentelemetry.io/collector v0.113.0 // indirect
 	go.opentelemetry.io/collector/client v1.19.0 // indirect
-	go.opentelemetry.io/collector/component/componentstatus v0.113.0 // indirect
 	go.opentelemetry.io/collector/config/configauth v0.113.0 // indirect
 	go.opentelemetry.io/collector/config/configcompression v1.19.0 // indirect
 	go.opentelemetry.io/collector/config/configgrpc v0.113.0 // indirect
diff --git a/go.sum b/go.sum
index 35d29a7ed39..cf15f3814a5 100644
--- a/go.sum
+++ b/go.sum
@@ -1153,6 +1153,8 @@ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.113.0
 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/sampling v0.113.0/go.mod h1:X25Nhlw6xhuNSd/C0FeEwmD4PGmcXDl7pa2jR0UREkU=
 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza v0.113.0 h1:G8w+wg4nnqBqe297fBWnjJ5Tg2OYDVEMsdWA9/3ozxQ=
 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza v0.113.0/go.mod h1:m3hDVsXPQzQfeji3+hn7NYJPHDRlHhQRNd5T7N5wZqc=
+github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status v0.113.0 h1:3cHaq0xbqzoEBxcHDl8h0YpUZ1W3St7UG5YQ8f9qCxw=
+github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status v0.113.0/go.mod h1:aJlolKULr8dNC4PlPkqpnBYGHrbanp4+cODG/8V/GW8=
 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.113.0 h1:mFYOvag34kGXceVj29k0ZpBUyjEX7VZq+KctUSfNiG0=
 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.113.0/go.mod h1:54P38b2i1CgHvZLxD3EAzVccqreamGEz2U4pqy9DuHw=
 github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus v0.113.0 h1:vKtNSM3VQBTJx1ecf+I1iqn4kj7fKif1SpBLQ+numf8=
@@ -1519,8 +1521,6 @@ go.opentelemetry.io/collector/config/internal v0.113.0 h1:9RAzH8v7ItFT1npHpvP0Sv
 go.opentelemetry.io/collector/config/internal v0.113.0/go.mod h1:yC7E4h1Uj0SubxcFImh6OvBHFTjMh99+A5PuyIgDWqc=
 go.opentelemetry.io/collector/confmap v1.19.0 h1:TQ0lZpAKqgsE0EKk+u4JA+uBbPYeFRmWP3GH43w40CY=
 go.opentelemetry.io/collector/confmap v1.19.0/go.mod h1:GgNu1ElPGmLn9govqIfjaopvdspw4PJ9KeDtWC4E2Q4=
-go.opentelemetry.io/collector/confmap/converter/expandconverter v0.113.0 h1:DBjWXlVzdwVbs1ZOH+k1vmoBt3TLx8NvRK8ZK3nKdmo=
-go.opentelemetry.io/collector/confmap/converter/expandconverter v0.113.0/go.mod h1:/YDWibNLalyfd0BR0V5ixiParsNCvVKkA58f3bcu/AA=
 go.opentelemetry.io/collector/confmap/provider/envprovider v1.19.0 h1:f8O/I5pVRN86Gx5mHekNx92S6fGdOS4VcooRJKWe6Bs=
 go.opentelemetry.io/collector/confmap/provider/envprovider v1.19.0/go.mod h1:AiaW5YW1LD0/WlZuc8eZuZPBH6PA9QqsiAYRX1iC6T0=
 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.19.0 h1:TYwyk4ea3U+5MYcEjrzZAaonBcLlabQu8CZeB7ekAYY=
diff --git a/internal/pkg/agent/application/actions/handlers/handler_action_upgrade_test.go b/internal/pkg/agent/application/actions/handlers/handler_action_upgrade_test.go
index fccffb46b70..3a930771cbd 100644
--- a/internal/pkg/agent/application/actions/handlers/handler_action_upgrade_test.go
+++ b/internal/pkg/agent/application/actions/handlers/handler_action_upgrade_test.go
@@ -110,7 +110,7 @@ func TestUpgradeHandler(t *testing.T) {
 				return nil, nil
 			},
 		},
-		nil, nil, nil, nil, nil, false)
+		nil, nil, nil, nil, nil, false, nil)
 	//nolint:errcheck // We don't need the termination state of the Coordinator
 	go c.Run(ctx)
 
@@ -169,7 +169,7 @@ func TestUpgradeHandlerSameVersion(t *testing.T) {
 				return nil, err
 			},
 		},
-		nil, nil, nil, nil, nil, false)
+		nil, nil, nil, nil, nil, false, nil)
 	//nolint:errcheck // We don't need the termination state of the Coordinator
 	go c.Run(ctx)
 
@@ -230,7 +230,7 @@ func TestUpgradeHandlerNewVersion(t *testing.T) {
 				return nil, nil
 			},
 		},
-		nil, nil, nil, nil, nil, false)
+		nil, nil, nil, nil, nil, false, nil)
 	//nolint:errcheck // We don't need the termination state of the Coordinator
 	go c.Run(ctx)
 
diff --git a/internal/pkg/agent/application/apm_config_modifier.go b/internal/pkg/agent/application/apm_config_modifier.go
index cf5f664d2a2..c396b6567ae 100644
--- a/internal/pkg/agent/application/apm_config_modifier.go
+++ b/internal/pkg/agent/application/apm_config_modifier.go
@@ -97,7 +97,7 @@ func getAPMConfigFromMap(cfg map[string]any) (*monitoringcfg.APMConfig, error) {
 	}
 
 	monitoringConfig := new(monitoringcfg.APMConfig)
-	err = newConfigFrom.Unpack(monitoringConfig)
+	err = newConfigFrom.UnpackTo(monitoringConfig)
 	if err != nil {
 		return nil, fmt.Errorf("error unpacking apm config: %w", err)
 	}
diff --git a/internal/pkg/agent/application/application.go b/internal/pkg/agent/application/application.go
index b72ff5664b5..4e42ccca917 100644
--- a/internal/pkg/agent/application/application.go
+++ b/internal/pkg/agent/application/application.go
@@ -9,10 +9,6 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/elastic/elastic-agent/pkg/features"
-	"github.com/elastic/elastic-agent/pkg/limits"
-	"github.com/elastic/elastic-agent/version"
-
 	"go.elastic.co/apm/v2"
 
 	"github.com/elastic/elastic-agent-libs/logp"
@@ -28,10 +24,14 @@ import (
 	"github.com/elastic/elastic-agent/internal/pkg/capabilities"
 	"github.com/elastic/elastic-agent/internal/pkg/composable"
 	"github.com/elastic/elastic-agent/internal/pkg/config"
+	otelmanager "github.com/elastic/elastic-agent/internal/pkg/otel/manager"
 	"github.com/elastic/elastic-agent/internal/pkg/release"
 	"github.com/elastic/elastic-agent/pkg/component"
 	"github.com/elastic/elastic-agent/pkg/component/runtime"
 	"github.com/elastic/elastic-agent/pkg/core/logger"
+	"github.com/elastic/elastic-agent/pkg/features"
+	"github.com/elastic/elastic-agent/pkg/limits"
+	"github.com/elastic/elastic-agent/version"
 )
 
 // New creates a new Agent and bootstrap the required subsystem.
@@ -176,13 +176,13 @@ func New(
 		}
 	}
 
-	// no need for vars in otel mode
 	varsManager, err := composable.New(log, rawConfig, composableManaged)
 	if err != nil {
 		return nil, nil, nil, errors.New(err, "failed to initialize composable controller")
 	}
 
-	coord := coordinator.New(log, cfg, logLevel, agentInfo, specs, reexec, upgrader, runtime, configMgr, varsManager, caps, monitor, isManaged, compModifiers...)
+	otelManager := otelmanager.NewOTelManager(log.Named("otel_manager"))
+	coord := coordinator.New(log, cfg, logLevel, agentInfo, specs, reexec, upgrader, runtime, configMgr, varsManager, caps, monitor, isManaged, otelManager, compModifiers...)
 	if managed != nil {
 		// the coordinator requires the config manager as well as in managed-mode the config manager requires the
 		// coordinator, so it must be set here once the coordinator is created
diff --git a/internal/pkg/agent/application/config_test.go b/internal/pkg/agent/application/config_test.go
index c2adbbc76de..ee74bca2f63 100644
--- a/internal/pkg/agent/application/config_test.go
+++ b/internal/pkg/agent/application/config_test.go
@@ -24,7 +24,7 @@ func testMgmtMode(t *testing.T) {
 	t.Run("succeed when local mode is selected", func(t *testing.T) {
 		c := mustWithConfigMode(true)
 		m := localConfig{}
-		err := c.Unpack(&m)
+		err := c.UnpackTo(&m)
 		require.NoError(t, err)
 		assert.Equal(t, false, m.Fleet.Enabled)
 		assert.Equal(t, true, configuration.IsStandalone(m.Fleet))
@@ -34,7 +34,7 @@ func testMgmtMode(t *testing.T) {
 	t.Run("succeed when fleet mode is selected", func(t *testing.T) {
 		c := mustWithConfigMode(false)
 		m := localConfig{}
-		err := c.Unpack(&m)
+		err := c.UnpackTo(&m)
 		require.NoError(t, err)
 		assert.Equal(t, true, m.Fleet.Enabled)
 		assert.Equal(t, false, configuration.IsStandalone(m.Fleet))
@@ -49,7 +49,7 @@ func testLocalConfig(t *testing.T) {
 		})
 
 		m := configuration.ReloadConfig{}
-		err := c.Unpack(&m)
+		err := c.UnpackTo(&m)
 		assert.Error(t, err)
 
 		c = config.MustNewConfigFrom(map[string]interface{}{
@@ -57,7 +57,7 @@ func testLocalConfig(t *testing.T) {
 			"period":  1,
 		})
 
-		err = c.Unpack(&m)
+		err = c.UnpackTo(&m)
 		assert.NoError(t, err)
 		assert.Equal(t, 1*time.Second, m.Period)
 	})
diff --git a/internal/pkg/agent/application/coordinator/coordinator.go b/internal/pkg/agent/application/coordinator/coordinator.go
index d54fe652018..7198f45bb04 100644
--- a/internal/pkg/agent/application/coordinator/coordinator.go
+++ b/internal/pkg/agent/application/coordinator/coordinator.go
@@ -13,7 +13,12 @@ import (
 	"sync/atomic"
 	"time"
 
+	"go.opentelemetry.io/collector/component/componentstatus"
+
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+
 	"go.elastic.co/apm/v2"
+	"go.opentelemetry.io/collector/confmap"
 	"gopkg.in/yaml.v2"
 
 	"github.com/elastic/elastic-agent-client/v7/pkg/client"
@@ -122,6 +127,17 @@ type RuntimeManager interface {
 	PerformComponentDiagnostics(ctx context.Context, additionalMetrics []cproto.AdditionalDiagnosticRequest, req ...component.Component) ([]runtime.ComponentDiagnostic, error)
 }
 
+// OTelManager provides an interface to run and update the runtime.
+type OTelManager interface {
+	Runner
+
+	// Update updates the current configuration for OTel.
+	Update(cfg *confmap.Conf)
+
+	// Watch returns the chanel to watch for configuration changes.
+	Watch() <-chan *status.AggregateStatus
+}
+
 // ConfigChange provides an interface for receiving a new configuration.
 //
 // Ack must be called if the configuration change was accepted and Fail should be called if it fails to be accepted.
@@ -193,6 +209,9 @@ type Coordinator struct {
 	configMgr  ConfigManager
 	varsMgr    VarsManager
 
+	otelMgr OTelManager
+	otelCfg *confmap.Conf
+
 	caps      capabilities.Capabilities
 	modifiers []ComponentsModifier
 
@@ -264,6 +283,7 @@ type Coordinator struct {
 	configErr        error
 	componentGenErr  error
 	runtimeUpdateErr error
+	otelErr          error
 
 	// The raw policy before spec lookup or variable substitution
 	ast *transpiler.AST
@@ -313,6 +333,9 @@ type managerChans struct {
 	varsManagerUpdate <-chan []*transpiler.Vars
 	varsManagerError  <-chan error
 
+	otelManagerUpdate <-chan *status.AggregateStatus
+	otelManagerError  <-chan error
+
 	upgradeMarkerUpdate <-chan upgrade.UpdateMarker
 }
 
@@ -339,7 +362,7 @@ type UpdateComponentChange struct {
 }
 
 // New creates a new coordinator.
-func New(logger *logger.Logger, cfg *configuration.Configuration, logLevel logp.Level, agentInfo info.Agent, specs component.RuntimeSpecs, reexecMgr ReExecManager, upgradeMgr UpgradeManager, runtimeMgr RuntimeManager, configMgr ConfigManager, varsMgr VarsManager, caps capabilities.Capabilities, monitorMgr MonitorManager, isManaged bool, modifiers ...ComponentsModifier) *Coordinator {
+func New(logger *logger.Logger, cfg *configuration.Configuration, logLevel logp.Level, agentInfo info.Agent, specs component.RuntimeSpecs, reexecMgr ReExecManager, upgradeMgr UpgradeManager, runtimeMgr RuntimeManager, configMgr ConfigManager, varsMgr VarsManager, caps capabilities.Capabilities, monitorMgr MonitorManager, isManaged bool, otelMgr OTelManager, modifiers ...ComponentsModifier) *Coordinator {
 	var fleetState cproto.State
 	var fleetMessage string
 	if !isManaged {
@@ -366,6 +389,7 @@ func New(logger *logger.Logger, cfg *configuration.Configuration, logLevel logp.
 		runtimeMgr: runtimeMgr,
 		configMgr:  configMgr,
 		varsMgr:    varsMgr,
+		otelMgr:    otelMgr,
 		caps:       caps,
 		modifiers:  modifiers,
 		state:      state,
@@ -420,6 +444,10 @@ func New(logger *logger.Logger, cfg *configuration.Configuration, logLevel logp.
 		c.managerChans.varsManagerUpdate = varsMgr.Watch()
 		c.managerChans.varsManagerError = varsMgr.Errors()
 	}
+	if otelMgr != nil {
+		c.managerChans.otelManagerUpdate = otelMgr.Watch()
+		c.managerChans.otelManagerError = otelMgr.Errors()
+	}
 	if upgradeMgr != nil && upgradeMgr.MarkerWatcher() != nil {
 		c.managerChans.upgradeMarkerUpdate = upgradeMgr.MarkerWatcher().Watch()
 	}
@@ -894,6 +922,12 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks {
 					ID    string                 `yaml:"id"`
 					State runtime.ComponentState `yaml:"state"`
 				}
+				type StateCollectorStatus struct {
+					Status     componentstatus.Status           `yaml:"status"`
+					Err        string                           `yaml:"error,omitempty"`
+					Timestamp  string                           `yaml:"timestamp"`
+					Components map[string]*StateCollectorStatus `yaml:"components,omitempty"`
+				}
 				type StateHookOutput struct {
 					State          agentclient.State      `yaml:"state"`
 					Message        string                 `yaml:"message"`
@@ -901,9 +935,29 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks {
 					FleetMessage   string                 `yaml:"fleet_message"`
 					LogLevel       logp.Level             `yaml:"log_level"`
 					Components     []StateComponentOutput `yaml:"components"`
+					Collector      *StateCollectorStatus  `yaml:"collector,omitempty"`
 					UpgradeDetails *details.Details       `yaml:"upgrade_details,omitempty"`
 				}
 
+				var toCollectorStatus func(status *status.AggregateStatus) *StateCollectorStatus
+				toCollectorStatus = func(status *status.AggregateStatus) *StateCollectorStatus {
+					s := &StateCollectorStatus{
+						Status:    status.Status(),
+						Timestamp: status.Timestamp().Format(time.RFC3339Nano),
+					}
+					statusErr := status.Err()
+					if statusErr != nil {
+						s.Err = statusErr.Error()
+					}
+					if len(status.ComponentStatusMap) > 0 {
+						s.Components = make(map[string]*StateCollectorStatus, len(status.ComponentStatusMap))
+						for k, v := range status.ComponentStatusMap {
+							s.Components[k] = toCollectorStatus(v)
+						}
+					}
+					return s
+				}
+
 				s := c.State()
 				n := len(s.Components)
 				compStates := make([]StateComponentOutput, n)
@@ -913,6 +967,10 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks {
 						State: s.Components[i].State,
 					}
 				}
+				var collectorStatus *StateCollectorStatus
+				if s.Collector != nil {
+					collectorStatus = toCollectorStatus(s.Collector)
+				}
 				output := StateHookOutput{
 					State:          s.State,
 					Message:        s.Message,
@@ -920,6 +978,7 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks {
 					FleetMessage:   s.FleetMessage,
 					LogLevel:       s.LogLevel,
 					Components:     compStates,
+					Collector:      collectorStatus,
 					UpgradeDetails: s.UpgradeDetails,
 				}
 				o, err := yaml.Marshal(output)
@@ -929,6 +988,22 @@ func (c *Coordinator) DiagnosticHooks() diagnostics.Hooks {
 				return o
 			},
 		},
+		{
+			Name:        "otel",
+			Filename:    "otel.yaml",
+			Description: "current otel configuration used by the Elastic Agent",
+			ContentType: "application/yaml",
+			Hook: func(_ context.Context) []byte {
+				if c.otelCfg == nil {
+					return []byte("no active OTel configuration")
+				}
+				o, err := yaml.Marshal(c.otelCfg.ToStringMap())
+				if err != nil {
+					return []byte(fmt.Sprintf("error: failed to convert to yaml: %v", err))
+				}
+				return o
+			},
+		},
 	}
 }
 
@@ -981,6 +1056,17 @@ func (c *Coordinator) runner(ctx context.Context) error {
 		varsErrCh <- nil
 	}
 
+	otelErrCh := make(chan error, 1)
+	if c.otelMgr != nil {
+		go func() {
+			err := c.otelMgr.Run(ctx)
+			cancel()
+			otelErrCh <- err
+		}()
+	} else {
+		otelErrCh <- nil
+	}
+
 	upgradeMarkerWatcherErrCh := make(chan error, 1)
 	if c.upgradeMgr != nil && c.upgradeMgr.MarkerWatcher() != nil {
 		err := c.upgradeMgr.MarkerWatcher().Run(ctx)
@@ -1000,7 +1086,7 @@ func (c *Coordinator) runner(ctx context.Context) error {
 
 	// If we got fatal errors from any of the managers, return them.
 	// Otherwise, just return the context's closing error.
-	err := collectManagerErrors(managerShutdownTimeout, varsErrCh, runtimeErrCh, configErrCh, upgradeMarkerWatcherErrCh)
+	err := collectManagerErrors(managerShutdownTimeout, varsErrCh, runtimeErrCh, configErrCh, otelErrCh, upgradeMarkerWatcherErrCh)
 	if err != nil {
 		c.logger.Debugf("Manager errors on Coordinator shutdown: %v", err.Error())
 		return err
@@ -1046,6 +1132,9 @@ func (c *Coordinator) runLoopIteration(ctx context.Context) {
 	case varsErr := <-c.managerChans.varsManagerError:
 		c.setVarsManagerError(varsErr)
 
+	case otelErr := <-c.managerChans.otelManagerError:
+		c.setOTelError(otelErr)
+
 	case overrideState := <-c.overrideStateChan:
 		c.setOverrideState(overrideState)
 
@@ -1101,6 +1190,10 @@ func (c *Coordinator) runLoopIteration(ctx context.Context) {
 			c.processVars(ctx, vars)
 		}
 
+	case collector := <-c.managerChans.otelManagerUpdate:
+		c.state.Collector = collector
+		c.stateNeedsRefresh = true
+
 	case ll := <-c.logLevelCh:
 		if ctx.Err() == nil {
 			c.processLogLevel(ctx, ll)
@@ -1121,6 +1214,15 @@ func (c *Coordinator) runLoopIteration(ctx context.Context) {
 
 // Always called on the main Coordinator goroutine.
 func (c *Coordinator) processConfig(ctx context.Context, cfg *config.Config) (err error) {
+	if c.otelMgr != nil {
+		c.otelCfg = cfg.OTel
+		c.otelMgr.Update(cfg.OTel)
+	}
+	return c.processConfigAgent(ctx, cfg)
+}
+
+// Always called on the main Coordinator goroutine.
+func (c *Coordinator) processConfigAgent(ctx context.Context, cfg *config.Config) (err error) {
 	span, ctx := apm.StartSpan(ctx, "config", "app.internal")
 	defer func() {
 		apm.CaptureError(ctx, err).Send()
@@ -1547,9 +1649,9 @@ func diffUnitList(old, new []component.Unit) map[string]diffCheck {
 // It returns any resulting errors as a multierror, or nil if no errors
 // were reported.
 // Called on the main Coordinator goroutine.
-func collectManagerErrors(timeout time.Duration, varsErrCh, runtimeErrCh, configErrCh, upgradeMarkerWatcherErrCh chan error) error {
-	var runtimeErr, configErr, varsErr, upgradeMarkerWatcherErr error
-	var returnedRuntime, returnedConfig, returnedVars, returnedUpgradeMarkerWatcher bool
+func collectManagerErrors(timeout time.Duration, varsErrCh, runtimeErrCh, configErrCh, otelErrCh, upgradeMarkerWatcherErrCh chan error) error {
+	var runtimeErr, configErr, varsErr, otelErr, upgradeMarkerWatcherErr error
+	var returnedRuntime, returnedConfig, returnedVars, returnedOtel, returnedUpgradeMarkerWatcher bool
 
 	// in case other components are locked up, let us time out
 	timeoutWait := time.NewTimer(timeout)
@@ -1571,7 +1673,7 @@ func collectManagerErrors(timeout time.Duration, varsErrCh, runtimeErrCh, config
 	var errs []error
 
 waitLoop:
-	for !returnedRuntime || !returnedConfig || !returnedVars || !returnedUpgradeMarkerWatcher {
+	for !returnedRuntime || !returnedConfig || !returnedVars || !returnedOtel || !returnedUpgradeMarkerWatcher {
 		select {
 		case runtimeErr = <-runtimeErrCh:
 			returnedRuntime = true
@@ -1579,6 +1681,8 @@ waitLoop:
 			returnedConfig = true
 		case varsErr = <-varsErrCh:
 			returnedVars = true
+		case otelErr = <-otelErrCh:
+			returnedOtel = true
 		case upgradeMarkerWatcherErr = <-upgradeMarkerWatcherErrCh:
 			returnedUpgradeMarkerWatcher = true
 		case <-timeoutWait.C:
@@ -1592,6 +1696,9 @@ waitLoop:
 			if !returnedVars {
 				timeouts = append(timeouts, "no response from vars manager")
 			}
+			if !returnedOtel {
+				timeouts = append(timeouts, "no response from otel manager")
+			}
 			if !returnedUpgradeMarkerWatcher {
 				timeouts = append(timeouts, "no response from upgrade marker watcher")
 			}
@@ -1609,6 +1716,9 @@ waitLoop:
 	if varsErr != nil && !errors.Is(varsErr, context.Canceled) {
 		errs = append(errs, fmt.Errorf("vars manager: %w", varsErr))
 	}
+	if otelErr != nil && !errors.Is(otelErr, context.Canceled) {
+		errs = append(errs, fmt.Errorf("otel manager: %w", otelErr))
+	}
 	if upgradeMarkerWatcherErr != nil && !errors.Is(upgradeMarkerWatcherErr, context.Canceled) {
 		errs = append(errs, fmt.Errorf("upgrade marker watcher: %w", upgradeMarkerWatcherErr))
 	}
diff --git a/internal/pkg/agent/application/coordinator/coordinator_state.go b/internal/pkg/agent/application/coordinator/coordinator_state.go
index e6e030d7b39..974c1c539f9 100644
--- a/internal/pkg/agent/application/coordinator/coordinator_state.go
+++ b/internal/pkg/agent/application/coordinator/coordinator_state.go
@@ -7,11 +7,14 @@ package coordinator
 import (
 	"fmt"
 
-	"github.com/elastic/elastic-agent-client/v7/pkg/client"
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component/componentstatus"
 
+	"github.com/elastic/elastic-agent-client/v7/pkg/client"
 	"github.com/elastic/elastic-agent-libs/logp"
 
 	"github.com/elastic/elastic-agent/internal/pkg/agent/application/upgrade/details"
+	"github.com/elastic/elastic-agent/internal/pkg/otel/otelhelpers"
 	"github.com/elastic/elastic-agent/pkg/component/runtime"
 	agentclient "github.com/elastic/elastic-agent/pkg/control/v2/client"
 )
@@ -33,6 +36,8 @@ type State struct {
 	Components []runtime.ComponentComponentState `yaml:"components"`
 	LogLevel   logp.Level                        `yaml:"log_level"`
 
+	Collector *status.AggregateStatus
+
 	UpgradeDetails *details.Details `yaml:"upgrade_details,omitempty"`
 }
 
@@ -70,6 +75,13 @@ func (c *Coordinator) setRuntimeUpdateError(err error) {
 	c.stateNeedsRefresh = true
 }
 
+// setOTelError reports a failed error for otel manager.
+// Called on the main Coordinator goroutine.
+func (c *Coordinator) setOTelError(err error) {
+	c.otelErr = err
+	c.stateNeedsRefresh = true
+}
+
 // setConfigManagerError updates the error state for the config manager.
 // Called on the main Coordinator goroutine.
 func (c *Coordinator) setConfigManagerError(err error) {
@@ -183,6 +195,10 @@ func (c *Coordinator) generateReportableState() (s State) {
 	s.UpgradeDetails = c.state.UpgradeDetails
 	s.Components = make([]runtime.ComponentComponentState, len(c.state.Components))
 	copy(s.Components, c.state.Components)
+	if c.state.Collector != nil {
+		// copy the contents
+		s.Collector = copyOTelStatus(c.state.Collector)
+	}
 
 	// Ordering of state aggregation:
 	// - Override state, if present
@@ -202,6 +218,9 @@ func (c *Coordinator) generateReportableState() (s State) {
 	} else if c.runtimeUpdateErr != nil {
 		s.State = agentclient.Failed
 		s.Message = fmt.Sprintf("Runtime update failed: %s", c.runtimeUpdateErr.Error())
+	} else if c.otelErr != nil {
+		s.State = agentclient.Failed
+		s.Message = fmt.Sprintf("OTel manager failed: %s", c.otelErr.Error())
 	} else if c.configMgrErr != nil {
 		s.State = agentclient.Failed
 		s.Message = fmt.Sprintf("Config manager: %s", c.configMgrErr.Error())
@@ -211,10 +230,10 @@ func (c *Coordinator) generateReportableState() (s State) {
 	} else if c.varsMgrErr != nil {
 		s.State = agentclient.Failed
 		s.Message = fmt.Sprintf("Vars manager: %s", c.varsMgrErr.Error())
-	} else if hasState(s.Components, client.UnitStateFailed) {
+	} else if hasState(s.Components, client.UnitStateFailed) || otelhelpers.HasStatus(s.Collector, componentstatus.StatusFatalError) || otelhelpers.HasStatus(s.Collector, componentstatus.StatusPermanentError) {
 		s.State = agentclient.Degraded
 		s.Message = "1 or more components/units in a failed state"
-	} else if hasState(s.Components, client.UnitStateDegraded) {
+	} else if hasState(s.Components, client.UnitStateDegraded) || otelhelpers.HasStatus(s.Collector, componentstatus.StatusRecoverableError) {
 		s.State = agentclient.Degraded
 		s.Message = "1 or more components/units in a degraded state"
 	} else {
@@ -264,3 +283,14 @@ func hasState(components []runtime.ComponentComponentState, state client.UnitSta
 	}
 	return false
 }
+
+func copyOTelStatus(copy *status.AggregateStatus) *status.AggregateStatus {
+	dest := &status.AggregateStatus{
+		Event:              copy.Event,
+		ComponentStatusMap: make(map[string]*status.AggregateStatus, len(copy.ComponentStatusMap)),
+	}
+	for k, v := range copy.ComponentStatusMap {
+		dest.ComponentStatusMap[k] = copyOTelStatus(v)
+	}
+	return dest
+}
diff --git a/internal/pkg/agent/application/coordinator/coordinator_test.go b/internal/pkg/agent/application/coordinator/coordinator_test.go
index 23f323fee54..36f788d6f24 100644
--- a/internal/pkg/agent/application/coordinator/coordinator_test.go
+++ b/internal/pkg/agent/application/coordinator/coordinator_test.go
@@ -15,12 +15,14 @@ import (
 	"testing"
 	"time"
 
-	"google.golang.org/protobuf/types/known/structpb"
+	otelmanager "github.com/elastic/elastic-agent/internal/pkg/otel/manager"
 
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
-
 	"go.elastic.co/apm/v2/apmtest"
+	"go.opentelemetry.io/collector/confmap"
+	"google.golang.org/protobuf/types/known/structpb"
 
 	"github.com/elastic/elastic-agent-libs/logp"
 
@@ -94,7 +96,7 @@ func waitForState(
 				return
 			}
 		case <-timeoutChan:
-			assert.Fail(t, "timed out waiting for expected state")
+			require.Fail(t, "timed out waiting for expected state")
 			return
 		}
 	}
@@ -633,7 +635,7 @@ func TestCoordinator_StateSubscribeIsolatedUnits(t *testing.T) {
 }
 
 func TestCollectManagerErrorsTimeout(t *testing.T) {
-	handlerChan, _, _, _, _ := setupManagerShutdownChannels(time.Millisecond)
+	handlerChan, _, _, _, _, _ := setupManagerShutdownChannels(time.Millisecond)
 	// Don't send anything to the shutdown channels, causing a timeout
 	// in collectManagerErrors
 	waitAndTestError(t, func(err error) bool {
@@ -643,7 +645,7 @@ func TestCollectManagerErrorsTimeout(t *testing.T) {
 }
 
 func TestCollectManagerErrorsOneResponse(t *testing.T) {
-	handlerChan, _, _, config, _ := setupManagerShutdownChannels(10 * time.Millisecond)
+	handlerChan, _, _, config, _, _ := setupManagerShutdownChannels(10 * time.Millisecond)
 
 	// Send an error for the config manager -- we should also get a
 	// timeout error since we don't send anything on the other two channels.
@@ -658,28 +660,32 @@ func TestCollectManagerErrorsOneResponse(t *testing.T) {
 }
 
 func TestCollectManagerErrorsAllResponses(t *testing.T) {
-	handlerChan, runtime, varWatcher, config, upgradeMarkerWatcher := setupManagerShutdownChannels(5 * time.Second)
+	handlerChan, runtime, varWatcher, config, otel, upgradeMarkerWatcher := setupManagerShutdownChannels(5 * time.Second)
 	runtimeErrStr := "runtime error"
 	varsErrStr := "vars error"
+	otelErrStr := "otel error"
 	upgradeMarkerWatcherErrStr := "upgrade marker watcher error"
 	runtime <- errors.New(runtimeErrStr)
 	varWatcher <- errors.New(varsErrStr)
 	config <- nil
+	otel <- errors.New(otelErrStr)
 	upgradeMarkerWatcher <- errors.New(upgradeMarkerWatcherErrStr)
 
 	waitAndTestError(t, func(err error) bool {
 		return err != nil &&
 			strings.Contains(err.Error(), runtimeErrStr) &&
 			strings.Contains(err.Error(), varsErrStr) &&
+			strings.Contains(err.Error(), otelErrStr) &&
 			strings.Contains(err.Error(), upgradeMarkerWatcherErrStr)
 	}, handlerChan)
 }
 
 func TestCollectManagerErrorsAllResponsesNoErrors(t *testing.T) {
-	handlerChan, runtime, varWatcher, config, upgradeMarkerWatcher := setupManagerShutdownChannels(5 * time.Second)
+	handlerChan, runtime, varWatcher, config, otel, upgradeMarkerWatcher := setupManagerShutdownChannels(5 * time.Second)
 	runtime <- nil
 	varWatcher <- nil
 	config <- context.Canceled
+	otel <- nil
 	upgradeMarkerWatcher <- nil
 
 	// All errors are nil or context.Canceled, so collectManagerErrors
@@ -710,19 +716,20 @@ func waitAndTestError(t *testing.T, check func(error) bool, handlerErr chan erro
 	}
 }
 
-func setupManagerShutdownChannels(timeout time.Duration) (chan error, chan error, chan error, chan error, chan error) {
+func setupManagerShutdownChannels(timeout time.Duration) (chan error, chan error, chan error, chan error, chan error, chan error) {
 	runtime := make(chan error)
 	varWatcher := make(chan error)
 	config := make(chan error)
+	otelWatcher := make(chan error)
 	upgradeMarkerWatcher := make(chan error)
 
 	handlerChan := make(chan error)
 	go func() {
-		handlerErr := collectManagerErrors(timeout, varWatcher, runtime, config, upgradeMarkerWatcher)
+		handlerErr := collectManagerErrors(timeout, varWatcher, runtime, config, otelWatcher, upgradeMarkerWatcher)
 		handlerChan <- handlerErr
 	}()
 
-	return handlerChan, runtime, varWatcher, config, upgradeMarkerWatcher
+	return handlerChan, runtime, varWatcher, config, otelWatcher, upgradeMarkerWatcher
 }
 
 func TestCoordinator_ReExec(t *testing.T) {
@@ -897,6 +904,7 @@ func createCoordinator(t *testing.T, ctx context.Context, opts ...CoordinatorOpt
 	cfg.Port = 0
 	rm, err := runtime.NewManager(l, l, ai, apmtest.DiscardTracer, monitoringMgr, cfg)
 	require.NoError(t, err)
+	otelMgr := otelmanager.NewOTelManager(l)
 
 	caps, err := capabilities.LoadFile(paths.AgentCapabilitiesPath(), l)
 	require.NoError(t, err)
@@ -909,7 +917,7 @@ func createCoordinator(t *testing.T, ctx context.Context, opts ...CoordinatorOpt
 		upgradeManager = &fakeUpgradeManager{}
 	}
 
-	coord := New(l, nil, logp.DebugLevel, ai, specs, &fakeReExecManager{}, upgradeManager, rm, cfgMgr, varsMgr, caps, monitoringMgr, o.managed)
+	coord := New(l, nil, logp.DebugLevel, ai, specs, &fakeReExecManager{}, upgradeManager, rm, cfgMgr, varsMgr, caps, monitoringMgr, o.managed, otelMgr)
 	return coord, cfgMgr, varsMgr
 }
 
@@ -1100,6 +1108,36 @@ func (f *fakeVarsManager) Vars(ctx context.Context, vars []*transpiler.Vars) {
 	}
 }
 
+type fakeOTelManager struct {
+	updateCallback func(*confmap.Conf) error
+	result         error
+	errChan        chan error
+}
+
+func (f *fakeOTelManager) Run(ctx context.Context) error {
+	<-ctx.Done()
+	return ctx.Err()
+}
+
+func (f *fakeOTelManager) Errors() <-chan error {
+	return nil
+}
+
+func (f *fakeOTelManager) Update(cfg *confmap.Conf) {
+	f.result = nil
+	if f.updateCallback != nil {
+		f.result = f.updateCallback(cfg)
+	}
+	if f.errChan != nil {
+		// If a reporting channel is set, send the result to it
+		f.errChan <- f.result
+	}
+}
+
+func (f *fakeOTelManager) Watch() <-chan *status.AggregateStatus {
+	return nil
+}
+
 // An implementation of the RuntimeManager interface for use in testing.
 type fakeRuntimeManager struct {
 	state          []runtime.ComponentComponentState
diff --git a/internal/pkg/agent/application/coordinator/coordinator_unit_test.go b/internal/pkg/agent/application/coordinator/coordinator_unit_test.go
index 9ebc2a26f43..a4f998bd82b 100644
--- a/internal/pkg/agent/application/coordinator/coordinator_unit_test.go
+++ b/internal/pkg/agent/application/coordinator/coordinator_unit_test.go
@@ -13,11 +13,14 @@ package coordinator
 import (
 	"context"
 	"errors"
-	"fmt"
 	"net"
 	"testing"
 	"time"
 
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component/componentstatus"
+	"go.opentelemetry.io/collector/confmap"
+
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
@@ -162,6 +165,94 @@ func TestCoordinatorReportsUnhealthyComponents(t *testing.T) {
 	}
 }
 
+func TestCoordinatorReportsUnhealthyOTelComponents(t *testing.T) {
+	// Set a one-second timeout -- nothing here should block, but if it
+	// does let's report a failure instead of timing out the test runner.
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+
+	// Channels have buffer length 1 so we don't have to run on multiple
+	// goroutines.
+	stateChan := make(chan State, 1)
+	otelChan := make(chan *status.AggregateStatus, 1)
+	coord := &Coordinator{
+		state: State{
+			CoordinatorState:   agentclient.Healthy,
+			CoordinatorMessage: "Running",
+		},
+		stateBroadcaster: &broadcaster.Broadcaster[State]{
+			InputChan: stateChan,
+		},
+		managerChans: managerChans{
+			otelManagerUpdate: otelChan,
+		},
+		componentPIDTicker: time.NewTicker(time.Second * 30),
+	}
+
+	unhealthyOTel := &status.AggregateStatus{
+		Event: componentstatus.NewEvent(componentstatus.StatusRecoverableError),
+		ComponentStatusMap: map[string]*status.AggregateStatus{
+			"test-component-1": {
+				Event: componentstatus.NewRecoverableErrorEvent(errors.New("test message")),
+			},
+		},
+	}
+
+	// Send the otel component state to the Coordinator channel and let it run for an
+	// iteration to update
+	otelChan <- unhealthyOTel
+	coord.runLoopIteration(ctx)
+	select {
+	case state := <-stateChan:
+		assert.Equal(t, agentclient.Degraded, state.State, "Degraded component state should cause degraded Coordinator state")
+		assert.Equal(t, "1 or more components/units in a degraded state", state.Message, "state message should reflect degraded component")
+	default:
+		assert.Fail(t, "Coordinator's state didn't change")
+	}
+
+	// Try again, escalating the component's state to Failed.
+	// The state message should change slightly, but the overall Coordinator
+	// state should still just be Degraded -- components / units can't cause
+	// a Failed state, only errors in the managers can do that.
+	unhealthyOTel = &status.AggregateStatus{
+		Event: componentstatus.NewEvent(componentstatus.StatusFatalError),
+		ComponentStatusMap: map[string]*status.AggregateStatus{
+			"test-component-1": {
+				Event: componentstatus.NewFatalErrorEvent(errors.New("test message")),
+			},
+		},
+	}
+	otelChan <- unhealthyOTel
+	coord.runLoopIteration(ctx)
+	select {
+	case state := <-stateChan:
+		assert.Equal(t, agentclient.Degraded, state.State, "Failed component state should cause degraded Coordinator state")
+		assert.Equal(t, "1 or more components/units in a failed state", state.Message, "state message should reflect failed component")
+	default:
+		assert.Fail(t, "Coordinator's state didn't change")
+	}
+
+	// Reset component state to UnitStateStarting and verify the
+	// Coordinator recovers
+	unhealthyOTel = &status.AggregateStatus{
+		Event: componentstatus.NewEvent(componentstatus.StatusStarting),
+		ComponentStatusMap: map[string]*status.AggregateStatus{
+			"test-component-1": {
+				Event: componentstatus.NewEvent(componentstatus.StatusStarting),
+			},
+		},
+	}
+	otelChan <- unhealthyOTel
+	coord.runLoopIteration(ctx)
+	select {
+	case state := <-stateChan:
+		assert.Equal(t, agentclient.Healthy, state.State, "Starting component state should cause healthy Coordinator state")
+		assert.Equal(t, "Running", state.Message, "Healthy coordinator should return to baseline state message")
+	default:
+		assert.Fail(t, "Coordinator's state didn't change")
+	}
+}
+
 func TestCoordinatorComponentStatesAreSeparate(t *testing.T) {
 	// Report two healthy components, set one to unhealthy, then verify that
 	// healthy state reports from the second component don't restore the
@@ -686,7 +777,7 @@ inputs:
 	assert.True(t, monitoringServer.isRunning)
 }
 
-func TestCoordinatorPolicyChangeUpdatesRuntimeManager(t *testing.T) {
+func TestCoordinatorPolicyChangeUpdatesRuntimeAndOTelManager(t *testing.T) {
 	// Send a test policy to the Coordinator as a Config Manager update,
 	// verify it generates the right component model and sends it to the
 	// runtime manager, then send an empty policy and verify it calls
@@ -710,6 +801,15 @@ func TestCoordinatorPolicyChangeUpdatesRuntimeManager(t *testing.T) {
 			return nil
 		},
 	}
+	var otelUpdated bool         // Set by otel manager callback
+	var otelConfig *confmap.Conf // Set by otel manager callback
+	otelManager := &fakeOTelManager{
+		updateCallback: func(cfg *confmap.Conf) error {
+			otelUpdated = true
+			otelConfig = cfg
+			return nil
+		},
+	}
 
 	coord := &Coordinator{
 		logger:           logger,
@@ -719,11 +819,12 @@ func TestCoordinatorPolicyChangeUpdatesRuntimeManager(t *testing.T) {
 			configManagerUpdate: configChan,
 		},
 		runtimeMgr:         runtimeManager,
+		otelMgr:            otelManager,
 		vars:               emptyVars(t),
 		componentPIDTicker: time.NewTicker(time.Second * 30),
 	}
 
-	// Create a policy with one input and one output
+	// Create a policy with one input and one output (no otel configuration)
 	cfg := config.MustNewConfigFrom(`
 outputs:
   default:
@@ -746,6 +847,8 @@ inputs:
 	// manually (sorry).
 	assert.True(t, updated, "Runtime manager should be updated after a policy change")
 	require.Equal(t, 1, len(components), "Test policy should generate one component")
+	assert.True(t, otelUpdated, "OTel manager should be updated after a policy change")
+	require.Nil(t, otelConfig, "OTel manager should not have any config")
 
 	component := components[0]
 	assert.Equal(t, "filestream-default", component.ID)
@@ -765,16 +868,57 @@ inputs:
 	assert.Equal(t, client.UnitTypeOutput, units[1].Type)
 	assert.Equal(t, "elasticsearch", units[1].Config.Type)
 
+	// Send a new config update that includes otel configuration
+	updated = false
+	components = nil
+	otelUpdated = false
+	otelConfig = nil
+	cfg = config.MustNewConfigFrom(`
+outputs:
+  default:
+    type: elasticsearch
+inputs:
+  - id: test-input
+    type: filestream
+    use_output: default
+receivers:
+  otlp:
+processors:
+  batch:
+exporters:
+  otlp:
+service:
+  pipelines:
+    traces:
+      receivers:
+        - otlp
+      exporters:
+        - otlp
+`)
+	cfgChange = &configChange{cfg: cfg}
+	configChan <- cfgChange
+	coord.runLoopIteration(ctx)
+
+	// Validate that the runtime manager and otel manager got the updated configuration
+	assert.True(t, updated, "Runtime manager should be updated after a policy change")
+	require.Equal(t, 1, len(components), "Test policy should generate one component")
+	assert.True(t, otelUpdated, "OTel manager should be updated after a policy change")
+	require.NotNil(t, otelConfig, "OTel manager should have a config")
+
 	// Send a new empty config update and make sure the runtime manager
-	// receives that as well.
+	// and otel manager receives that as well.
 	updated = false
 	components = nil
+	otelUpdated = false
+	otelConfig = nil
 	cfgChange = &configChange{cfg: config.MustNewConfigFrom(nil)}
 	configChan <- cfgChange
 	coord.runLoopIteration(ctx)
 	assert.True(t, cfgChange.acked, "empty policy should be acknowledged")
 	assert.True(t, updated, "empty policy should cause runtime manager update")
 	assert.Empty(t, components, "empty policy should produce empty component model")
+	assert.True(t, otelUpdated, "empty policy should cause otel manager update")
+	assert.Nil(t, otelConfig, "empty policy should cause otel manager to get nil config")
 }
 
 func TestCoordinatorReportsRuntimeManagerUpdateFailure(t *testing.T) {
@@ -791,7 +935,7 @@ func TestCoordinatorReportsRuntimeManagerUpdateFailure(t *testing.T) {
 	// Create a mocked runtime manager that always reports an error
 	runtimeManager := &fakeRuntimeManager{
 		updateCallback: func(comp []component.Component) error {
-			return fmt.Errorf(errorStr)
+			return errors.New(errorStr)
 		},
 		errChan: updateErrChan,
 	}
@@ -836,6 +980,67 @@ func TestCoordinatorReportsRuntimeManagerUpdateFailure(t *testing.T) {
 	assert.Contains(t, state.Message, errorStr, "Failed policy update should be reported in Coordinator state message")
 }
 
+func TestCoordinatorReportsOTelManagerUpdateFailure(t *testing.T) {
+	// Set a one-second timeout -- nothing here should block, but if it
+	// does let's report a failure instead of timing out the test runner.
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+	logger := logp.NewLogger("testing")
+
+	configChan := make(chan ConfigChange, 1)
+	updateErrChan := make(chan error, 1)
+
+	// Create a mocked otel manager that always reports an error
+	const errorStr = "update failed for testing reasons"
+	runtimeManager := &fakeRuntimeManager{}
+	otelManager := &fakeOTelManager{
+		updateCallback: func(retrieved *confmap.Conf) error {
+			return errors.New(errorStr)
+		},
+		errChan: updateErrChan,
+	}
+
+	coord := &Coordinator{
+		logger:           logger,
+		agentInfo:        &info.AgentInfo{},
+		stateBroadcaster: broadcaster.New(State{}, 0, 0),
+		managerChans: managerChans{
+			configManagerUpdate: configChan,
+			// Give coordinator the same error channel we set on the otel
+			// manager, so it receives the update result.
+			otelManagerError: updateErrChan,
+		},
+		runtimeMgr:         runtimeManager,
+		otelMgr:            otelManager,
+		vars:               emptyVars(t),
+		componentPIDTicker: time.NewTicker(time.Second * 30),
+	}
+
+	// Send an empty policy which should forward an empty component model to
+	// the otel manager (which we have set up to report an error).
+	cfg := config.MustNewConfigFrom(nil)
+	configChange := &configChange{cfg: cfg}
+	configChan <- configChange
+	coord.runLoopIteration(ctx)
+
+	// Make sure the config change was acknowledged to the config manager
+	// (the failure is not reported here since it happens asynchronously; it
+	// will appear in the coordinator state afterwards.)
+	assert.True(t, configChange.acked, "Config change should be acknowledged to the config manager")
+	assert.NoError(t, configChange.err, "Config change with async error should succeed")
+
+	// Now do another run loop iteration to let the update error propagate,
+	// and make sure it is reported correctly.
+	coord.runLoopIteration(ctx)
+	require.Error(t, coord.otelErr, "OTel update failure should be saved in otelErr")
+	assert.Equal(t, errorStr, coord.otelErr.Error(), "otelErr should match the error reported by the otel manager")
+
+	// Make sure the error appears in the Coordinator state.
+	state := coord.State()
+	assert.Equal(t, agentclient.Failed, state.State, "Failed policy update should cause failed Coordinator")
+	assert.Contains(t, state.Message, errorStr, "Failed policy update should be reported in Coordinator state message")
+}
+
 func TestCoordinatorAppliesVarsToPolicy(t *testing.T) {
 	// Make sure:
 	// - An input unit that depends on an undefined variable is not created
diff --git a/internal/pkg/agent/application/coordinator/diagnostics_test.go b/internal/pkg/agent/application/coordinator/diagnostics_test.go
index 9c72400e8e8..346999e8f86 100644
--- a/internal/pkg/agent/application/coordinator/diagnostics_test.go
+++ b/internal/pkg/agent/application/coordinator/diagnostics_test.go
@@ -41,6 +41,7 @@ func TestCoordinatorExpectedDiagnosticHooks(t *testing.T) {
 		"components-expected",
 		"components-actual",
 		"state",
+		"otel",
 	}
 
 	coord := &Coordinator{}
diff --git a/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go b/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go
index c36b37cd017..a369282fd68 100644
--- a/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go
+++ b/internal/pkg/agent/application/gateway/fleet/fleet_gateway.go
@@ -8,6 +8,8 @@ import (
 	"context"
 	"time"
 
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+
 	agentclient "github.com/elastic/elastic-agent/pkg/control/v2/client"
 
 	eaclient "github.com/elastic/elastic-agent-client/v7/pkg/client"
@@ -18,6 +20,7 @@ import (
 	"github.com/elastic/elastic-agent/internal/pkg/fleetapi"
 	"github.com/elastic/elastic-agent/internal/pkg/fleetapi/acker"
 	"github.com/elastic/elastic-agent/internal/pkg/fleetapi/client"
+	"github.com/elastic/elastic-agent/internal/pkg/otel/otelhelpers"
 	"github.com/elastic/elastic-agent/internal/pkg/scheduler"
 	"github.com/elastic/elastic-agent/pkg/component/runtime"
 	"github.com/elastic/elastic-agent/pkg/core/logger"
@@ -232,7 +235,7 @@ func (f *FleetGateway) doExecute(ctx context.Context, bo backoff.Backoff) (*flee
 	return nil, ctx.Err()
 }
 
-func (f *FleetGateway) convertToCheckinComponents(components []runtime.ComponentComponentState) []fleetapi.CheckinComponent {
+func (f *FleetGateway) convertToCheckinComponents(components []runtime.ComponentComponentState, collector *status.AggregateStatus) []fleetapi.CheckinComponent {
 	if components == nil {
 		return nil
 	}
@@ -250,7 +253,11 @@ func (f *FleetGateway) convertToCheckinComponents(components []runtime.Component
 		return ""
 	}
 
-	checkinComponents := make([]fleetapi.CheckinComponent, 0, len(components))
+	size := len(components)
+	if collector != nil {
+		size += len(collector.ComponentStatusMap)
+	}
+	checkinComponents := make([]fleetapi.CheckinComponent, 0, size)
 
 	for _, item := range components {
 		component := item.Component
@@ -280,6 +287,36 @@ func (f *FleetGateway) convertToCheckinComponents(components []runtime.Component
 		checkinComponents = append(checkinComponents, checkinComponent)
 	}
 
+	// OTel status is placed as a component for each top-level component in OTel
+	// and each subcomponent is a unit.
+	if collector != nil {
+		for id, item := range collector.ComponentStatusMap {
+			state, msg := otelhelpers.StateWithMessage(item)
+
+			checkinComponent := fleetapi.CheckinComponent{
+				ID:      id,
+				Type:    "otel",
+				Status:  stateString(state),
+				Message: msg,
+			}
+
+			if len(item.ComponentStatusMap) > 0 {
+				units := make([]fleetapi.CheckinUnit, 0, len(item.ComponentStatusMap))
+				for unitId, unitItem := range item.ComponentStatusMap {
+					unitState, unitMsg := otelhelpers.StateWithMessage(unitItem)
+					units = append(units, fleetapi.CheckinUnit{
+						ID:      unitId,
+						Status:  stateString(unitState),
+						Message: unitMsg,
+					})
+				}
+				checkinComponent.Units = units
+			}
+
+			checkinComponents = append(checkinComponents, checkinComponent)
+		}
+	}
+
 	return checkinComponents
 }
 
@@ -299,7 +336,7 @@ func (f *FleetGateway) execute(ctx context.Context) (*fleetapi.CheckinResponse,
 	state := f.stateFetcher()
 
 	// convert components into checkin components structure
-	components := f.convertToCheckinComponents(state.Components)
+	components := f.convertToCheckinComponents(state.Components, state.Collector)
 
 	f.log.Debugf("correcting agent loglevel from %s to %s using coordinator state", ecsMeta.Elastic.Agent.LogLevel, state.LogLevel.String())
 	// Fix loglevel with the current log level used by coordinator
diff --git a/internal/pkg/agent/application/info/agent_id.go b/internal/pkg/agent/application/info/agent_id.go
index 348c428a26e..31435d02cd5 100644
--- a/internal/pkg/agent/application/info/agent_id.go
+++ b/internal/pkg/agent/application/info/agent_id.go
@@ -127,7 +127,7 @@ func getInfoFromStore(s ioStore, logLevel string) (*persistentAgentInfo, bool, e
 		LogLevel:       logLevel,
 		MonitoringHTTP: monitoringConfig.DefaultConfig().HTTP,
 	}
-	if err := cc.Unpack(&pid); err != nil {
+	if err := cc.UnpackTo(&pid); err != nil {
 		return nil, false, errors.New(err, "failed to unpack stored config to map")
 	}
 
@@ -152,7 +152,7 @@ func updateAgentInfo(s ioStore, agentInfo *persistentAgentInfo) error {
 	}
 
 	configMap := make(map[string]interface{})
-	if err := cfg.Unpack(&configMap); err != nil {
+	if err := cfg.UnpackTo(&configMap); err != nil {
 		return errors.New(err, "failed to unpack stored config to map")
 	}
 
@@ -160,7 +160,7 @@ func updateAgentInfo(s ioStore, agentInfo *persistentAgentInfo) error {
 	if agentInfoSubMap, found := configMap[agentInfoKey]; found {
 		if cc, err := config.NewConfigFrom(agentInfoSubMap); err == nil {
 			pid := &persistentAgentInfo{}
-			err := cc.Unpack(&pid)
+			err := cc.UnpackTo(&pid)
 			if err == nil && pid.ID != agentInfo.ID {
 				// if our id is different (we just generated it)
 				// keep the one present in the file
diff --git a/internal/pkg/agent/application/monitoring/liveness.go b/internal/pkg/agent/application/monitoring/liveness.go
index f0d75b019d9..a0ffdb43feb 100644
--- a/internal/pkg/agent/application/monitoring/liveness.go
+++ b/internal/pkg/agent/application/monitoring/liveness.go
@@ -9,7 +9,11 @@ import (
 	"net/http"
 	"time"
 
+	"go.opentelemetry.io/collector/component/componentstatus"
+
 	"github.com/elastic/elastic-agent-client/v7/pkg/client"
+
+	"github.com/elastic/elastic-agent/internal/pkg/otel/otelhelpers"
 )
 
 const formValueKey = "failon"
@@ -79,6 +83,11 @@ func livenessHandler(coord CoordinatorState) func(http.ResponseWriter, *http.Req
 				unhealthyComponent = true
 			}
 		}
+		if state.Collector != nil {
+			if (failConfig.Failed && (otelhelpers.HasStatus(state.Collector, componentstatus.StatusFatalError) || otelhelpers.HasStatus(state.Collector, componentstatus.StatusPermanentError))) || (failConfig.Degraded && otelhelpers.HasStatus(state.Collector, componentstatus.StatusRecoverableError)) {
+				unhealthyComponent = true
+			}
+		}
 		// bias towards the coordinator check, since it can be otherwise harder to diagnose
 		if unhealthyComponent {
 			w.WriteHeader(http.StatusInternalServerError)
diff --git a/internal/pkg/agent/application/monitoring/liveness_test.go b/internal/pkg/agent/application/monitoring/liveness_test.go
index 514df72fed6..abe3bb94cc9 100644
--- a/internal/pkg/agent/application/monitoring/liveness_test.go
+++ b/internal/pkg/agent/application/monitoring/liveness_test.go
@@ -12,6 +12,9 @@ import (
 	"testing"
 	"time"
 
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component/componentstatus"
+
 	"github.com/stretchr/testify/require"
 
 	"github.com/elastic/elastic-agent-client/v7/pkg/client"
@@ -352,6 +355,50 @@ func TestProcessHTTPHandler(t *testing.T) {
 			liveness:     true,
 			failon:       "degraded",
 		},
+		{
+			name: "healthy-liveness-off-otel",
+			coord: mockCoordinator{
+				isUp: true,
+				state: coordinator.State{
+					Collector: &status.AggregateStatus{
+						Event: componentstatus.NewEvent(componentstatus.StatusOK),
+						ComponentStatusMap: map[string]*status.AggregateStatus{
+							"test-component": &status.AggregateStatus{
+								Event: componentstatus.NewEvent(componentstatus.StatusOK),
+							},
+							"test-component2": &status.AggregateStatus{
+								Event: componentstatus.NewEvent(componentstatus.StatusOK),
+							},
+						},
+					},
+				},
+			},
+			expectedCode: 200,
+			liveness:     false,
+			failon:       "degraded",
+		},
+		{
+			name: "degraded-and-healthy-otel",
+			coord: mockCoordinator{
+				isUp: true,
+				state: coordinator.State{
+					Collector: &status.AggregateStatus{
+						Event: componentstatus.NewEvent(componentstatus.StatusRecoverableError),
+						ComponentStatusMap: map[string]*status.AggregateStatus{
+							"test-component": &status.AggregateStatus{
+								Event: componentstatus.NewEvent(componentstatus.StatusRecoverableError),
+							},
+							"test-component2": &status.AggregateStatus{
+								Event: componentstatus.NewEvent(componentstatus.StatusOK),
+							},
+						},
+					},
+				},
+			},
+			expectedCode: 500,
+			liveness:     true,
+			failon:       "degraded",
+		},
 	}
 
 	// test with processesHandler
diff --git a/internal/pkg/agent/application/monitoring/reload/reload.go b/internal/pkg/agent/application/monitoring/reload/reload.go
index 9247f7aea45..d012e1f3cd8 100644
--- a/internal/pkg/agent/application/monitoring/reload/reload.go
+++ b/internal/pkg/agent/application/monitoring/reload/reload.go
@@ -94,7 +94,7 @@ func (sr *ServerReloader) Addr() net.Addr {
 
 func (sr *ServerReloader) Reload(rawConfig *aConfig.Config) error {
 	newConfig := configuration.DefaultConfiguration()
-	if err := rawConfig.Unpack(&newConfig); err != nil {
+	if err := rawConfig.UnpackTo(&newConfig); err != nil {
 		return errors.New(err, "failed to unpack monitoring config during reload")
 	}
 
diff --git a/internal/pkg/agent/application/monitoring/v1_monitor.go b/internal/pkg/agent/application/monitoring/v1_monitor.go
index 7512b989a98..0d219f849e8 100644
--- a/internal/pkg/agent/application/monitoring/v1_monitor.go
+++ b/internal/pkg/agent/application/monitoring/v1_monitor.go
@@ -105,7 +105,7 @@ func (b *BeatsMonitor) Reload(rawConfig *config.Config) error {
 		return nil
 	}
 
-	if err := rawConfig.Unpack(&b.config); err != nil {
+	if err := rawConfig.UnpackTo(&b.config); err != nil {
 		return errors.New(err, "failed to unpack monitoring config during reload")
 	}
 	return nil
diff --git a/internal/pkg/agent/application/upgrade/artifact/config.go b/internal/pkg/agent/application/upgrade/artifact/config.go
index 07be58fb123..d43ea6bb60e 100644
--- a/internal/pkg/agent/application/upgrade/artifact/config.go
+++ b/internal/pkg/agent/application/upgrade/artifact/config.go
@@ -133,7 +133,7 @@ func (r *Reloader) reloadConfig(rawConfig *config.Config) error {
 	tmp := &reloadConfig{
 		C: DefaultConfig(),
 	}
-	if err := rawConfig.Unpack(&tmp); err != nil {
+	if err := rawConfig.UnpackTo(&tmp); err != nil {
 		return err
 	}
 
@@ -160,7 +160,7 @@ func (r *Reloader) reloadSourceURI(rawConfig *config.Config) error {
 		FleetSourceURI string `json:"agent.download.source_uri" config:"agent.download.source_uri"`
 	}
 	cfg := &reloadConfig{}
-	if err := rawConfig.Unpack(&cfg); err != nil {
+	if err := rawConfig.UnpackTo(&cfg); err != nil {
 		return errors.New(err, "failed to unpack config during reload")
 	}
 
@@ -274,7 +274,7 @@ func (c *Config) Unpack(cfg *c.C) error {
 		return err
 	}
 	// HTTPTransportSettings.Proxy.Headers defaults to empty. If absent in cfg,
-	// Unpack will set it to nil. To ensure consistency, we reset it to empty.
+	// UnpackTo will set it to nil. To ensure consistency, we reset it to empty.
 	if transport.Proxy.Headers == nil {
 		transport.Proxy.Headers = map[string]string{}
 	}
diff --git a/internal/pkg/agent/application/upgrade/artifact/config_test.go b/internal/pkg/agent/application/upgrade/artifact/config_test.go
index 70ff03559c0..32bf307b870 100644
--- a/internal/pkg/agent/application/upgrade/artifact/config_test.go
+++ b/internal/pkg/agent/application/upgrade/artifact/config_test.go
@@ -307,6 +307,6 @@ func TestConfig_Unpack(t *testing.T) {
 	require.NoError(t, err, "could not create config from empty string")
 
 	err = defaultcfg.Unpack(emptycgf)
-	require.NoError(t, err, "Unpack failed")
+	require.NoError(t, err, "UnpackTo failed")
 	assert.Equal(t, DefaultConfig(), defaultcfg)
 }
diff --git a/internal/pkg/agent/application/upgrade/upgrade.go b/internal/pkg/agent/application/upgrade/upgrade.go
index b2eda395ed7..43702d44f83 100644
--- a/internal/pkg/agent/application/upgrade/upgrade.go
+++ b/internal/pkg/agent/application/upgrade/upgrade.go
@@ -110,7 +110,7 @@ func (u *Upgrader) Reload(rawConfig *config.Config) error {
 		FleetSourceURI string `json:"agent.download.source_uri" config:"agent.download.source_uri"`
 	}
 	fleetSourceURI := &fleetCfg{}
-	if err := rawConfig.Unpack(&fleetSourceURI); err != nil {
+	if err := rawConfig.UnpackTo(&fleetSourceURI); err != nil {
 		return errors.New(err, "failed to unpack config during reload")
 	}
 
diff --git a/internal/pkg/agent/cmd/container.go b/internal/pkg/agent/cmd/container.go
index b0a3ad63e5a..b807c8ec162 100644
--- a/internal/pkg/agent/cmd/container.go
+++ b/internal/pkg/agent/cmd/container.go
@@ -206,7 +206,7 @@ func containerCmd(streams *cli.IOStreams) error {
 			return fmt.Errorf("parsing config file(%s): %w", f, err)
 		}
 		if c != nil {
-			err = c.Unpack(&cfg)
+			err = c.UnpackTo(&cfg)
 			if err != nil {
 				return fmt.Errorf("unpacking config file(%s): %w", f, err)
 			}
@@ -899,7 +899,7 @@ func tryContainerLoadPaths() error {
 		return fmt.Errorf("failed to load %s: %w", pathFile, err)
 	}
 	var paths containerPaths
-	err = cfg.Unpack(&paths)
+	err = cfg.UnpackTo(&paths)
 	if err != nil {
 		return fmt.Errorf("failed to unpack %s: %w", pathFile, err)
 	}
diff --git a/internal/pkg/agent/cmd/container_test.go b/internal/pkg/agent/cmd/container_test.go
index 6afc9ba88ce..3ada160fee8 100644
--- a/internal/pkg/agent/cmd/container_test.go
+++ b/internal/pkg/agent/cmd/container_test.go
@@ -85,7 +85,7 @@ func TestContainerTestPaths(t *testing.T) {
 			require.NoError(t, err)
 
 			var paths containerPaths
-			err = cfg.Unpack(&paths)
+			err = cfg.UnpackTo(&paths)
 			require.NoError(t, err)
 
 			require.Equal(t, c.expected, paths)
diff --git a/internal/pkg/agent/cmd/enroll_cmd.go b/internal/pkg/agent/cmd/enroll_cmd.go
index 2bb07dde414..91f652c9ef5 100644
--- a/internal/pkg/agent/cmd/enroll_cmd.go
+++ b/internal/pkg/agent/cmd/enroll_cmd.go
@@ -1076,7 +1076,7 @@ func getPersistentConfig(pathConfigFile string) (map[string]interface{}, error)
 		MonitoringHTTP: monitoringConfig.DefaultConfig().HTTP,
 	}
 
-	if err := rawConfig.Unpack(&pc); err != nil {
+	if err := rawConfig.UnpackTo(&pc); err != nil {
 		return nil, err
 	}
 
diff --git a/internal/pkg/agent/cmd/enroll_cmd_test.go b/internal/pkg/agent/cmd/enroll_cmd_test.go
index c175240abfa..6131c1de959 100644
--- a/internal/pkg/agent/cmd/enroll_cmd_test.go
+++ b/internal/pkg/agent/cmd/enroll_cmd_test.go
@@ -870,7 +870,7 @@ func readConfig(raw []byte) (*configuration.FleetAgentConfig, error) {
 	}
 
 	cfg := configuration.DefaultConfiguration()
-	if err := config.Unpack(cfg); err != nil {
+	if err := config.UnpackTo(cfg); err != nil {
 		return nil, err
 	}
 	return cfg.Fleet, nil
diff --git a/internal/pkg/agent/cmd/inspect.go b/internal/pkg/agent/cmd/inspect.go
index 600b4ba4985..c5826d64a43 100644
--- a/internal/pkg/agent/cmd/inspect.go
+++ b/internal/pkg/agent/cmd/inspect.go
@@ -389,7 +389,7 @@ func getMonitoringFn(ctx context.Context, cfg map[string]interface{}) (component
 	}
 
 	agentCfg := configuration.DefaultConfiguration()
-	if err := config.Unpack(agentCfg); err != nil {
+	if err := config.UnpackTo(agentCfg); err != nil {
 		return nil, err
 	}
 
diff --git a/internal/pkg/agent/cmd/otel.go b/internal/pkg/agent/cmd/otel.go
index 8007f9512b8..3ce0d3db269 100644
--- a/internal/pkg/agent/cmd/otel.go
+++ b/internal/pkg/agent/cmd/otel.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package cmd
 
 import (
diff --git a/internal/pkg/agent/cmd/otel_flags.go b/internal/pkg/agent/cmd/otel_flags.go
index 8cf66dd5e14..57cae05884e 100644
--- a/internal/pkg/agent/cmd/otel_flags.go
+++ b/internal/pkg/agent/cmd/otel_flags.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package cmd
 
 import (
diff --git a/internal/pkg/agent/cmd/otel_flags_test.go b/internal/pkg/agent/cmd/otel_flags_test.go
index e1fc06bb63d..24fe30e2afd 100644
--- a/internal/pkg/agent/cmd/otel_flags_test.go
+++ b/internal/pkg/agent/cmd/otel_flags_test.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package cmd
 
 import (
diff --git a/internal/pkg/agent/cmd/otel_windows.go b/internal/pkg/agent/cmd/otel_windows.go
deleted file mode 100644
index d914ab1c963..00000000000
--- a/internal/pkg/agent/cmd/otel_windows.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
-// or more contributor license agreements. Licensed under the Elastic License 2.0;
-// you may not use this file except in compliance with the Elastic License 2.0.
-
-//go:build windows
-
-package cmd
-
-import (
-	"github.com/spf13/cobra"
-
-	"github.com/elastic/elastic-agent/internal/pkg/cli"
-)
-
-func newOtelCommandWithArgs(args []string, streams *cli.IOStreams) *cobra.Command {
-	return nil
-}
diff --git a/internal/pkg/agent/cmd/otel_windows_test.go b/internal/pkg/agent/cmd/otel_windows_test.go
deleted file mode 100644
index 0c12c121576..00000000000
--- a/internal/pkg/agent/cmd/otel_windows_test.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
-// or more contributor license agreements. Licensed under the Elastic License 2.0;
-// you may not use this file except in compliance with the Elastic License 2.0.
-
-//go:build windows
-
-package cmd
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/require"
-)
-
-func TestOtelCommandIsNil(t *testing.T) {
-	require.Nil(t, newOtelCommandWithArgs(nil, nil))
-}
diff --git a/internal/pkg/agent/cmd/status.go b/internal/pkg/agent/cmd/status.go
index 2288c11b463..d9c82359462 100644
--- a/internal/pkg/agent/cmd/status.go
+++ b/internal/pkg/agent/cmd/status.go
@@ -96,6 +96,13 @@ func formatStatus(state client.State, message string) string {
 	return fmt.Sprintf("status: (%s) %s", state, message)
 }
 
+func formatComponentStatus(component *client.CollectorComponent) string {
+	if component.Error != "" {
+		return fmt.Sprintf("status: %s [%s]", component.Status, component.Error)
+	}
+	return fmt.Sprintf("status: %s", component.Status)
+}
+
 func listComponentState(l list.Writer, components []client.ComponentState, all bool) {
 	for _, c := range components {
 		// see if any unit is not Healthy because component
@@ -134,6 +141,27 @@ func listComponentState(l list.Writer, components []client.ComponentState, all b
 	}
 }
 
+func listCollectorState(l list.Writer, id string, component *client.CollectorComponent) {
+	if component == nil {
+		return
+	}
+	l.AppendItem(id)
+	l.Indent()
+	l.AppendItem(formatComponentStatus(component))
+	if len(component.ComponentStatusMap) > 0 {
+		// list in order
+		keys := make([]string, 0, len(component.ComponentStatusMap))
+		for k := range component.ComponentStatusMap {
+			keys = append(keys, k)
+		}
+		sort.Strings(keys)
+		for _, k := range keys {
+			listCollectorState(l, k, component.ComponentStatusMap[k])
+		}
+	}
+	l.UnIndent()
+}
+
 func listAgentState(l list.Writer, state *client.AgentState, all bool) {
 	l.AppendItem("elastic-agent")
 	l.Indent()
@@ -148,6 +176,21 @@ func listAgentState(l list.Writer, state *client.AgentState, all bool) {
 	}
 	l.UnIndent()
 	listComponentState(l, state.Components, all)
+	if state.Collector != nil {
+		l.Indent()
+		if len(state.Collector.ComponentStatusMap) > 0 {
+			// list in order
+			keys := make([]string, 0, len(state.Collector.ComponentStatusMap))
+			for k := range state.Collector.ComponentStatusMap {
+				keys = append(keys, k)
+			}
+			sort.Strings(keys)
+			for _, k := range keys {
+				listCollectorState(l, k, state.Collector.ComponentStatusMap[k])
+			}
+		}
+		l.UnIndent()
+	}
 
 	// Upgrade details
 	listUpgradeDetails(l, state.UpgradeDetails)
diff --git a/internal/pkg/agent/cmd/validate.go b/internal/pkg/agent/cmd/validate.go
index e5f049be855..098c50dba17 100644
--- a/internal/pkg/agent/cmd/validate.go
+++ b/internal/pkg/agent/cmd/validate.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package cmd
 
 import (
diff --git a/internal/pkg/agent/configuration/configuration.go b/internal/pkg/agent/configuration/configuration.go
index c29908bf1d9..e1cc9ab951f 100644
--- a/internal/pkg/agent/configuration/configuration.go
+++ b/internal/pkg/agent/configuration/configuration.go
@@ -27,7 +27,7 @@ func DefaultConfiguration() *Configuration {
 // NewFromConfig creates a configuration based on common Config.
 func NewFromConfig(cfg *config.Config) (*Configuration, error) {
 	c := DefaultConfiguration()
-	if err := cfg.Unpack(c); err != nil {
+	if err := cfg.UnpackTo(c); err != nil {
 		return nil, errors.New(err, errors.TypeConfig)
 	}
 
@@ -38,7 +38,7 @@ func NewFromConfig(cfg *config.Config) (*Configuration, error) {
 func NewPartialFromConfigNoDefaults(cfg *config.Config) (*Configuration, error) {
 	c := new(Configuration)
 	// Validator tag set to "validate_disable" is a hack to avoid validation errors on a partial config
-	if err := cfg.Unpack(c, ucfg.ValidatorTag("validate_disable")); err != nil {
+	if err := cfg.UnpackTo(c, ucfg.ValidatorTag("validate_disable")); err != nil {
 		return nil, errors.New(err, errors.TypeConfig)
 	}
 
diff --git a/internal/pkg/composable/controller.go b/internal/pkg/composable/controller.go
index 73a3c49a967..7cab450ce00 100644
--- a/internal/pkg/composable/controller.go
+++ b/internal/pkg/composable/controller.go
@@ -55,7 +55,7 @@ func New(log *logger.Logger, c *config.Config, managed bool) (Controller, error)
 
 	var providersCfg Config
 	if c != nil {
-		err := c.Unpack(&providersCfg)
+		err := c.UnpackTo(&providersCfg)
 		if err != nil {
 			return nil, errors.New(err, "failed to unpack providers config", errors.TypeConfig)
 		}
diff --git a/internal/pkg/composable/providers/docker/docker.go b/internal/pkg/composable/providers/docker/docker.go
index 72082a476b1..49ec74d4fdb 100644
--- a/internal/pkg/composable/providers/docker/docker.go
+++ b/internal/pkg/composable/providers/docker/docker.go
@@ -107,7 +107,7 @@ func DynamicProviderBuilder(logger *logger.Logger, c *config.Config, managed boo
 	if c == nil {
 		c = config.New()
 	}
-	err := c.Unpack(&cfg)
+	err := c.UnpackTo(&cfg)
 	if err != nil {
 		return nil, errors.New(err, "failed to unpack configuration")
 	}
diff --git a/internal/pkg/composable/providers/host/host.go b/internal/pkg/composable/providers/host/host.go
index efa555f7bf5..6ba4e5356d7 100644
--- a/internal/pkg/composable/providers/host/host.go
+++ b/internal/pkg/composable/providers/host/host.go
@@ -109,7 +109,7 @@ func ContextProviderBuilder(log *logger.Logger, c *config.Config, _ bool) (corec
 		fetcher: getHostInfo(log),
 	}
 	if c != nil {
-		err := c.Unpack(p)
+		err := c.UnpackTo(p)
 		if err != nil {
 			return nil, fmt.Errorf("failed to unpack config: %w", err)
 		}
diff --git a/internal/pkg/composable/providers/kubernetes/kubernetes.go b/internal/pkg/composable/providers/kubernetes/kubernetes.go
index 2beb701a5df..05583996920 100644
--- a/internal/pkg/composable/providers/kubernetes/kubernetes.go
+++ b/internal/pkg/composable/providers/kubernetes/kubernetes.go
@@ -46,7 +46,7 @@ func DynamicProviderBuilder(logger *logger.Logger, c *config.Config, managed boo
 	if c == nil {
 		c = config.New()
 	}
-	err := c.Unpack(&cfg)
+	err := c.UnpackTo(&cfg)
 	if err != nil {
 		return nil, errors.New(err, "failed to unpack configuration")
 	}
diff --git a/internal/pkg/composable/providers/kubernetes/pod_test.go b/internal/pkg/composable/providers/kubernetes/pod_test.go
index 936e2fb0479..71f08108786 100644
--- a/internal/pkg/composable/providers/kubernetes/pod_test.go
+++ b/internal/pkg/composable/providers/kubernetes/pod_test.go
@@ -177,7 +177,7 @@ func TestGenerateContainerPodData(t *testing.T) {
 	logger := getLogger()
 	var cfg Config
 	c := config.New()
-	_ = c.Unpack(&cfg)
+	_ = c.UnpackTo(&cfg)
 	generateContainerData(
 		&comm,
 		pod,
@@ -307,7 +307,7 @@ func TestEphemeralContainers(t *testing.T) {
 	logger := getLogger()
 	var cfg Config
 	c := config.New()
-	_ = c.Unpack(&cfg)
+	_ = c.UnpackTo(&cfg)
 	generateContainerData(
 		&comm,
 		pod,
diff --git a/internal/pkg/composable/providers/kubernetesleaderelection/kubernetes_leaderelection.go b/internal/pkg/composable/providers/kubernetesleaderelection/kubernetes_leaderelection.go
index b88bdd39db2..6f25a57dc3d 100644
--- a/internal/pkg/composable/providers/kubernetesleaderelection/kubernetes_leaderelection.go
+++ b/internal/pkg/composable/providers/kubernetesleaderelection/kubernetes_leaderelection.go
@@ -42,7 +42,7 @@ func ContextProviderBuilder(logger *logger.Logger, c *config.Config, managed boo
 	if c == nil {
 		c = config.New()
 	}
-	err := c.Unpack(&cfg)
+	err := c.UnpackTo(&cfg)
 	if err != nil {
 		return nil, errors.New(err, "failed to unpack configuration")
 	}
diff --git a/internal/pkg/composable/providers/kubernetessecrets/kubernetes_secrets.go b/internal/pkg/composable/providers/kubernetessecrets/kubernetes_secrets.go
index 146a0399f6b..6921003cb30 100644
--- a/internal/pkg/composable/providers/kubernetessecrets/kubernetes_secrets.go
+++ b/internal/pkg/composable/providers/kubernetessecrets/kubernetes_secrets.go
@@ -50,7 +50,7 @@ func ContextProviderBuilder(logger *logger.Logger, c *config.Config, _ bool) (co
 	if c == nil {
 		c = config.New()
 	}
-	err := c.Unpack(&cfg)
+	err := c.UnpackTo(&cfg)
 	if err != nil {
 		return nil, errors.New(err, "failed to unpack configuration")
 	}
diff --git a/internal/pkg/composable/providers/local/local.go b/internal/pkg/composable/providers/local/local.go
index 7a737dec220..470d6c0a312 100644
--- a/internal/pkg/composable/providers/local/local.go
+++ b/internal/pkg/composable/providers/local/local.go
@@ -36,7 +36,7 @@ func (c *contextProvider) Run(ctx context.Context, comm corecomp.ContextProvider
 func ContextProviderBuilder(_ *logger.Logger, c *config.Config, _ bool) (corecomp.ContextProvider, error) {
 	p := &contextProvider{}
 	if c != nil {
-		err := c.Unpack(p)
+		err := c.UnpackTo(p)
 		if err != nil {
 			return nil, fmt.Errorf("failed to unpack vars: %w", err)
 		}
diff --git a/internal/pkg/composable/providers/localdynamic/localdynamic.go b/internal/pkg/composable/providers/localdynamic/localdynamic.go
index 2296d93c0fc..6bef79633b7 100644
--- a/internal/pkg/composable/providers/localdynamic/localdynamic.go
+++ b/internal/pkg/composable/providers/localdynamic/localdynamic.go
@@ -44,7 +44,7 @@ func (c *dynamicProvider) Run(comm composable.DynamicProviderComm) error {
 func DynamicProviderBuilder(_ *logger.Logger, c *config.Config, _ bool) (composable.DynamicProvider, error) {
 	p := &dynamicProvider{}
 	if c != nil {
-		err := c.Unpack(p)
+		err := c.UnpackTo(p)
 		if err != nil {
 			return nil, fmt.Errorf("failed to unpack vars: %w", err)
 		}
diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go
index 5a10ce6541b..b57a36eca88 100644
--- a/internal/pkg/config/config.go
+++ b/internal/pkg/config/config.go
@@ -7,8 +7,10 @@ package config
 import (
 	"fmt"
 	"io"
+	"maps"
 	"os"
 
+	"go.opentelemetry.io/collector/confmap"
 	"gopkg.in/yaml.v2"
 
 	"github.com/elastic/go-ucfg"
@@ -17,12 +19,22 @@ import (
 
 // options hold the specified options
 type options struct {
+	otelKeys []string
 	skipKeys []string
 }
 
 // Option is an option type that modifies how loading configs work
 type Option func(*options)
 
+// OTelKeys maps top-level keys to OTel specific configuration.
+//
+// The provided keys only skip if the keys are top-level keys.
+func OTelKeys(keys ...string) Option {
+	return func(opts *options) {
+		opts.otelKeys = keys
+	}
+}
+
 // VarSkipKeys prevents variable expansion for these keys.
 //
 // The provided keys only skip if the keys are top-level keys.
@@ -39,14 +51,20 @@ var DefaultOptions = []interface{}{
 	ucfg.VarExp,
 	VarSkipKeys("inputs"),
 	ucfg.IgnoreCommas,
+	OTelKeys("connectors", "receivers", "processors", "exporters", "extensions", "service"),
 }
 
-// Config custom type over a ucfg.Config to add new methods on the object.
-type Config ucfg.Config
+// Config custom type that can provide both an Agent configuration alongside of an optional OTel configuration.
+type Config struct {
+	// Agent configuration
+	Agent *ucfg.Config
+	// OTel configuration (YAML bytes raw)
+	OTel *confmap.Conf
+}
 
 // New creates a new empty config.
 func New() *Config {
-	return newConfigFrom(ucfg.New())
+	return newConfigFrom(ucfg.New(), nil)
 }
 
 // NewConfigFrom takes a interface and read the configuration like it was YAML.
@@ -83,10 +101,20 @@ func NewConfigFrom(from interface{}, opts ...interface{}) (*Config, error) {
 			return nil, err
 		}
 	} else if contents, ok := from.(map[string]interface{}); ok {
-		data = contents
+		// don't modify the incoming contents
+		data = maps.Clone(contents)
 	} else {
 		c, err := ucfg.NewFrom(from, ucfgOpts...)
-		return newConfigFrom(c), err
+		return newConfigFrom(c, nil), err
+	}
+
+	otelKeys := map[string]interface{}{}
+	for _, skip := range local.otelKeys {
+		val, ok := data[skip]
+		if ok {
+			otelKeys[skip] = val
+			delete(data, skip)
+		}
 	}
 
 	skippedKeys := map[string]interface{}{}
@@ -103,14 +131,17 @@ func NewConfigFrom(from interface{}, opts ...interface{}) (*Config, error) {
 	}
 	if len(skippedKeys) > 0 {
 		err = cfg.Merge(skippedKeys, ucfg.ResolveNOOP)
-
-		// we modified incoming object
-		// cleanup so skipped keys are not missing
-		for k, v := range skippedKeys {
-			data[k] = v
+		if err != nil {
+			return nil, err
 		}
 	}
-	return newConfigFrom(cfg), err
+
+	var otelCfg *confmap.Conf
+	if len(otelKeys) > 0 {
+		otelCfg = confmap.NewFromStringMap(otelKeys)
+	}
+
+	return newConfigFrom(cfg, otelCfg), nil
 }
 
 // MustNewConfigFrom try to create a configuration based on the type passed as arguments and panic
@@ -123,12 +154,23 @@ func MustNewConfigFrom(from interface{}) *Config {
 	return c
 }
 
-func newConfigFrom(in *ucfg.Config) *Config {
-	return (*Config)(in)
+func newConfigFrom(in *ucfg.Config, otel *confmap.Conf) *Config {
+	return &Config{
+		Agent: in,
+		OTel:  otel,
+	}
+}
+
+// Unpack implements the ucfg.Unpacker interface.
+func (c *Config) Unpack(val interface{}) error {
+	if c.Agent == nil {
+		c.Agent = ucfg.New()
+	}
+	return c.Agent.Merge(val)
 }
 
-// Unpack unpacks a struct to Config.
-func (c *Config) Unpack(to interface{}, opts ...interface{}) error {
+// UnpackTo unpacks this config into to with the given options.
+func (c *Config) UnpackTo(to interface{}, opts ...interface{}) error {
 	ucfgOpts, _, err := getOptions(opts...)
 	if err != nil {
 		return err
@@ -137,7 +179,7 @@ func (c *Config) Unpack(to interface{}, opts ...interface{}) error {
 }
 
 func (c *Config) access() *ucfg.Config {
-	return (*ucfg.Config)(c)
+	return c.Agent
 }
 
 // Merge merges two configuration together.
@@ -146,6 +188,24 @@ func (c *Config) Merge(from interface{}, opts ...interface{}) error {
 	if err != nil {
 		return err
 	}
+	cfg, ok := from.(*Config)
+	if ok {
+		// can merge both together
+		err = c.access().Merge(cfg.Agent, ucfgOpts...)
+		if err != nil {
+			return err
+		}
+		if c.OTel == nil && cfg.OTel != nil {
+			// simple, update to other retrieved configuration
+			c.OTel = cfg.OTel
+		} else if cfg.OTel != nil {
+			err = c.OTel.Merge(cfg.OTel)
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	}
 	return c.access().Merge(from, ucfgOpts...)
 }
 
@@ -223,7 +283,7 @@ func (c *Config) Enabled() bool {
 	if c == nil {
 		return false
 	}
-	if err := c.Unpack(&testEnabled); err != nil {
+	if err := c.UnpackTo(&testEnabled); err != nil {
 		// if unpacking fails, expect 'enabled' being set to default value
 		return true
 	}
@@ -248,7 +308,7 @@ func LoadFiles(paths ...string) (*Config, error) {
 			return nil, err
 		}
 	}
-	return newConfigFrom(merger.Config()), nil
+	return newConfigFrom(merger.Config(), nil), nil
 }
 
 func getOptions(opts ...interface{}) ([]ucfg.Option, options, error) {
diff --git a/internal/pkg/config/config_test.go b/internal/pkg/config/config_test.go
index cfbf8c76394..55f5d60e7c8 100644
--- a/internal/pkg/config/config_test.go
+++ b/internal/pkg/config/config_test.go
@@ -12,7 +12,10 @@ import (
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"go.opentelemetry.io/collector/confmap"
 	"gopkg.in/yaml.v2"
+
+	"github.com/elastic/go-ucfg"
 )
 
 func TestConfig(t *testing.T) {
@@ -154,3 +157,214 @@ func TestDollarSignsInInputs(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, in, out)
 }
+
+func TestConfigUnpack(t *testing.T) {
+	c := &struct {
+		// go-ucfg will call the Unpacker interface
+		Inner *Config
+	}{}
+	in := map[string]interface{}{
+		"inner": map[string]interface{}{
+			"key": "value",
+		},
+	}
+	cfg := MustNewConfigFrom(in)
+	require.NoError(t, cfg.UnpackTo(c))
+
+	require.NotNil(t, c.Inner.Agent)
+	val, err := c.Inner.Agent.String("key", 0)
+	require.NoError(t, err)
+	assert.Equal(t, "value", val)
+}
+
+func TestConfigOTelNNil(t *testing.T) {
+	c, err := NewConfigFrom(map[string]interface{}{
+		"outputs": map[string]interface{}{
+			"default": map[string]interface{}{
+				"type":     "elasticsearch",
+				"hosts":    []interface{}{"127.0.0.1:9200"},
+				"username": "elastic",
+				"password": "changeme",
+			},
+		},
+		"inputs": []interface{}{
+			map[string]interface{}{
+				"type": "logfile",
+				"streams": []interface{}{
+					map[string]interface{}{
+						"paths": []interface{}{"/var/log/syslog"},
+					},
+				},
+			},
+		},
+	})
+	require.NoError(t, err)
+	assert.NotNil(t, c.Agent)
+	assert.Nil(t, c.OTel)
+}
+
+func TestConfigOTelNotNil(t *testing.T) {
+	c, err := NewConfigFrom(map[string]interface{}{
+		"outputs": map[string]interface{}{
+			"default": map[string]interface{}{
+				"type":     "elasticsearch",
+				"hosts":    []interface{}{"127.0.0.1:9200"},
+				"username": "elastic",
+				"password": "changeme",
+			},
+		},
+		"inputs": []interface{}{
+			map[string]interface{}{
+				"type": "logfile",
+				"streams": []interface{}{
+					map[string]interface{}{
+						"paths": []interface{}{"/var/log/syslog"},
+					},
+				},
+			},
+		},
+		"connectors": map[string]interface{}{
+			"count": map[string]interface{}{},
+		},
+		"receivers": map[string]interface{}{
+			"otlp": map[string]interface{}{
+				"protocols": map[string]interface{}{
+					"grpc": map[string]interface{}{
+						"endpoint": "0.0.0.0:4317",
+					},
+				},
+			},
+		},
+		"processors": map[string]interface{}{
+			"batch": map[string]interface{}{},
+		},
+		"exporters": map[string]interface{}{
+			"otlp": map[string]interface{}{
+				"endpoint": "otelcol:4317",
+			},
+		},
+		"extensions": map[string]interface{}{
+			"health_check": map[string]interface{}{},
+			"pprof":        map[string]interface{}{},
+		},
+		"service": map[string]interface{}{
+			"extensions": []string{"health_check", "pprof"},
+			"pipelines": map[string]interface{}{
+				"traces": map[string]interface{}{
+					"receivers":  []string{"otlp"},
+					"processors": []string{"batch"},
+					"exporters":  []string{"otlp"},
+				},
+				"metrics": map[string]interface{}{
+					"receivers":  []string{"otlp"},
+					"processors": []string{"batch"},
+					"exporters":  []string{"otlp"},
+				},
+				"logs": map[string]interface{}{
+					"receivers":  []string{"otlp"},
+					"processors": []string{"batch"},
+					"exporters":  []string{"otlp"},
+				},
+			},
+		},
+	})
+	require.NoError(t, err)
+	require.NotNil(t, c.Agent)
+
+	require.NotNil(t, c.OTel)
+	assert.NotNil(t, c.OTel.Get("connectors"))
+	assert.NotNil(t, c.OTel.Get("receivers"))
+	assert.NotNil(t, c.OTel.Get("processors"))
+	assert.NotNil(t, c.OTel.Get("exporters"))
+	assert.NotNil(t, c.OTel.Get("extensions"))
+	assert.NotNil(t, c.OTel.Get("service"))
+}
+
+func TestConfigMerge(t *testing.T) {
+	scenarios := []struct {
+		Name   string
+		Into   *Config
+		From   *Config
+		Result *Config
+	}{
+		{
+			Name: "no otel",
+			Into: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"a": "value-a",
+				},
+			}), nil),
+			From: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"b": "value-b",
+				},
+			}), nil),
+			Result: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"a": "value-a",
+					"b": "value-b",
+				},
+			}), nil),
+		},
+		{
+			Name: "otel set",
+			Into: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"a": "value-a",
+				},
+			}), nil),
+			From: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"b": "value-b",
+				},
+			}), confmap.NewFromStringMap(map[string]interface{}{
+				"extensions": []interface{}{"health_check", "pprof"},
+			})),
+			Result: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"a": "value-a",
+					"b": "value-b",
+				},
+			}), confmap.NewFromStringMap(map[string]interface{}{
+				"extensions": []interface{}{"health_check", "pprof"},
+			})),
+		},
+		{
+			Name: "otel merge",
+			Into: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"a": "value-a",
+				},
+			}), confmap.NewFromStringMap(map[string]interface{}{
+				"extensions": []interface{}{"health_check", "pprof"},
+			})),
+			From: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"b": "value-b",
+				},
+			}), confmap.NewFromStringMap(map[string]interface{}{
+				"receivers": map[string]interface{}{
+					"filelog": map[string]interface{}{},
+				},
+			})),
+			Result: newConfigFrom(ucfg.MustNewFrom(map[string]interface{}{
+				"agent": map[string]interface{}{
+					"a": "value-a",
+					"b": "value-b",
+				},
+			}), confmap.NewFromStringMap(map[string]interface{}{
+				"extensions": []interface{}{"health_check", "pprof"},
+				"receivers": map[string]interface{}{
+					"filelog": map[string]interface{}{},
+				},
+			})),
+		},
+	}
+	for _, s := range scenarios {
+		t.Run(s.Name, func(t *testing.T) {
+			err := s.Into.Merge(s.From)
+			require.NoError(t, err)
+			assert.Equal(t, s.Result, s.Into)
+		})
+	}
+}
diff --git a/internal/pkg/config/loader.go b/internal/pkg/config/loader.go
index 4591684a301..00b6552b1e2 100644
--- a/internal/pkg/config/loader.go
+++ b/internal/pkg/config/loader.go
@@ -8,6 +8,8 @@ import (
 	"fmt"
 	"path/filepath"
 
+	"go.opentelemetry.io/collector/confmap"
+
 	"github.com/elastic/elastic-agent/pkg/core/logger"
 	"github.com/elastic/go-ucfg"
 	"github.com/elastic/go-ucfg/cfgutil"
@@ -34,6 +36,7 @@ func NewLoader(logger *logger.Logger, inputsFolder string) *Loader {
 func (l *Loader) Load(files []string) (*Config, error) {
 	inputsList := make([]*ucfg.Config, 0)
 	merger := cfgutil.NewCollector(nil)
+	var otelCfg *confmap.Conf
 	for _, f := range files {
 		cfg, err := LoadFile(f)
 		if err != nil {
@@ -55,6 +58,9 @@ func (l *Loader) Load(files []string) (*Config, error) {
 				return nil, fmt.Errorf("failed to merge configuration file '%s' to existing one: %w", f, err)
 			}
 			l.logger.Debugf("Merged configuration from %s into result", f)
+			if cfg.OTel != nil {
+				otelCfg = cfg.OTel
+			}
 		}
 	}
 	config := merger.Config()
@@ -62,7 +68,7 @@ func (l *Loader) Load(files []string) (*Config, error) {
 	// if there is no input configuration, return what we have collected.
 	if len(inputsList) == 0 {
 		l.logger.Debugf("Merged all configuration files from %v, no external input files", files)
-		return newConfigFrom(config), nil
+		return newConfigFrom(config, otelCfg), nil
 	}
 
 	// merge inputs sections from the last standalone configuration
@@ -82,7 +88,7 @@ func (l *Loader) Load(files []string) (*Config, error) {
 	}
 
 	l.logger.Debugf("Merged all configuration files from %v, with external input files", files)
-	return newConfigFrom(config), nil
+	return newConfigFrom(config, otelCfg), nil
 }
 
 func getInput(c *Config) ([]*ucfg.Config, error) {
@@ -90,7 +96,7 @@ func getInput(c *Config) ([]*ucfg.Config, error) {
 		Inputs []*ucfg.Config `config:"inputs"`
 	}{make([]*ucfg.Config, 0)}
 
-	if err := c.Unpack(&tmpConfig); err != nil {
+	if err := c.UnpackTo(&tmpConfig); err != nil {
 		return nil, fmt.Errorf("failed to parse inputs section from configuration: %w", err)
 	}
 	return tmpConfig.Inputs, nil
diff --git a/internal/pkg/core/monitoring/config/config_test.go b/internal/pkg/core/monitoring/config/config_test.go
index 47006777b46..efe490ab723 100644
--- a/internal/pkg/core/monitoring/config/config_test.go
+++ b/internal/pkg/core/monitoring/config/config_test.go
@@ -99,7 +99,7 @@ metrics: true`,
 			require.NoError(t, err, "failed to create config")
 
 			cfg := testCase.startingCfg
-			err = c.Unpack(&cfg)
+			err = c.UnpackTo(&cfg)
 			require.NoError(t, err, "failed to unpack config")
 
 			assert.Equal(t, testCase.expectedEnabled, cfg.HTTP.Enabled, "enabled incorrect")
@@ -151,7 +151,7 @@ http:
 			require.NoError(t, err, "failed to create config")
 
 			cfg := DefaultConfig()
-			err = c.Unpack(&cfg)
+			err = c.UnpackTo(&cfg)
 			require.NoError(t, err, "failed to unpack config")
 
 			require.Equal(t, tc.expectedHost, cfg.HTTP.Host)
@@ -222,7 +222,7 @@ func TestAPMConfig(t *testing.T) {
 			require.NoError(t, err)
 
 			cfg := DefaultConfig()
-			require.NoError(t, in.Unpack(cfg))
+			require.NoError(t, in.UnpackTo(cfg))
 			require.NotNil(t, cfg)
 
 			assert.Equal(t, tc.out, cfg.APM)
diff --git a/internal/pkg/otel/agentprovider/provider.go b/internal/pkg/otel/agentprovider/provider.go
new file mode 100644
index 00000000000..02cf3e3b399
--- /dev/null
+++ b/internal/pkg/otel/agentprovider/provider.go
@@ -0,0 +1,112 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package agentprovider
+
+import (
+	"context"
+	"fmt"
+	"sync"
+
+	"github.com/gofrs/uuid/v5"
+	"go.opentelemetry.io/collector/confmap"
+)
+
+const schemeName = "elasticagent"
+
+// Provider is a fixed provider that has a factory but only returns the same provider.
+type Provider struct {
+	uri string
+
+	cfg     *confmap.Conf
+	cfgMu   sync.RWMutex
+	updated chan struct{}
+
+	canceller   context.CancelFunc
+	cancelledMu sync.Mutex
+}
+
+// NewProvider creates a `agentprovider.Provider`.
+func NewProvider(cfg *confmap.Conf) *Provider {
+	uri := fmt.Sprintf("%s:%s", schemeName, uuid.Must(uuid.NewV4()).String())
+	return &Provider{
+		uri:     uri,
+		cfg:     cfg,
+		updated: make(chan struct{}, 1), // buffer of 1, stores the updated state
+	}
+}
+
+// NewFactory provides a factory.
+//
+// This factory doesn't create a new provider on each call. It always returns the same provider.
+func (p *Provider) NewFactory() confmap.ProviderFactory {
+	return confmap.NewProviderFactory(func(_ confmap.ProviderSettings) confmap.Provider {
+		return p
+	})
+}
+
+// Update updates the latest configuration in the provider.
+func (p *Provider) Update(cfg *confmap.Conf) {
+	p.cfgMu.Lock()
+	p.cfg = cfg
+	p.cfgMu.Unlock()
+	select {
+	case p.updated <- struct{}{}:
+	default:
+		// already has an updated state
+	}
+}
+
+// Retrieve returns the latest configuration.
+func (p *Provider) Retrieve(ctx context.Context, uri string, watcher confmap.WatcherFunc) (*confmap.Retrieved, error) {
+	if uri != p.uri {
+		return nil, fmt.Errorf("%q uri doesn't equal defined %q provider", uri, schemeName)
+	}
+
+	// get latest cfg at time of call
+	p.cfgMu.RLock()
+	cfg := p.cfg
+	p.cfgMu.RUnlock()
+
+	// don't use passed in context, as the cancel comes from Shutdown
+	ctx, cancel := context.WithCancel(context.Background())
+	p.replaceCanceller(cancel)
+	go func() {
+		defer p.replaceCanceller(nil) // ensure the context is always cleaned up
+		select {
+		case <-ctx.Done():
+			return
+		case <-p.updated:
+			watcher(&confmap.ChangeEvent{})
+		}
+	}()
+
+	return confmap.NewRetrieved(cfg.ToStringMap())
+}
+
+// Scheme is the scheme for this provider.
+func (p *Provider) Scheme() string {
+	return schemeName
+}
+
+// Shutdown called by collect when stopping.
+func (p *Provider) Shutdown(ctx context.Context) error {
+	p.replaceCanceller(nil)
+	return nil
+}
+
+// URI returns the URI to be used for this provider.
+func (p *Provider) URI() string {
+	return p.uri
+}
+
+func (p *Provider) replaceCanceller(replace context.CancelFunc) {
+	p.cancelledMu.Lock()
+	canceller := p.canceller
+	p.canceller = replace
+	p.cancelledMu.Unlock()
+	if canceller != nil {
+		canceller()
+	}
+}
diff --git a/internal/pkg/otel/agentprovider/provider_test.go b/internal/pkg/otel/agentprovider/provider_test.go
new file mode 100644
index 00000000000..5b6cea50439
--- /dev/null
+++ b/internal/pkg/otel/agentprovider/provider_test.go
@@ -0,0 +1,99 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package agentprovider
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"go.opentelemetry.io/collector/confmap"
+)
+
+func TestProvider_NewFactory(t *testing.T) {
+	p := NewProvider(nil)
+	assert.Equal(t, p, p.NewFactory().Create(confmap.ProviderSettings{}))
+}
+
+func TestProvider_Schema(t *testing.T) {
+	p := NewProvider(nil)
+	assert.Equal(t, schemeName, p.Scheme())
+}
+
+func TestProvider_URI(t *testing.T) {
+	p := NewProvider(nil)
+	assert.Equal(t, p.uri, p.URI())
+}
+
+func TestProvider_Update(t *testing.T) {
+	cfg := confmap.New()
+	cfg2 := confmap.New()
+	cfg3 := confmap.New()
+
+	p := NewProvider(cfg)
+	p.Update(cfg2) // should not block
+	p.Update(cfg3) // should not block
+}
+
+func TestProvider_Retrieve(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	cfg := confmap.New()
+
+	p := NewProvider(cfg)
+	ret, err := p.Retrieve(ctx, p.URI(), func(event *confmap.ChangeEvent) {})
+	require.NoError(t, err)
+	retCfg, err := ret.AsConf()
+	require.NoError(t, err)
+	require.Equal(t, cfg, retCfg)
+}
+
+func TestProvider_Retrieve_Update(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	cfg := confmap.New()
+	cfg2 := confmap.New()
+
+	ch := make(chan *confmap.ChangeEvent, 1)
+
+	p := NewProvider(cfg)
+	ret, err := p.Retrieve(ctx, p.URI(), func(event *confmap.ChangeEvent) {
+		ch <- event
+	})
+	require.NoError(t, err)
+	retCfg, err := ret.AsConf()
+	require.NoError(t, err)
+	require.Equal(t, cfg, retCfg)
+
+	p.Update(cfg2)
+	evt := <-ch
+	require.NotNil(t, evt)
+
+	ret2, err := p.Retrieve(ctx, p.URI(), func(event *confmap.ChangeEvent) {})
+	require.NoError(t, err)
+	retCfg2, err := ret2.AsConf()
+	require.NoError(t, err)
+	assert.Equal(t, cfg2, retCfg2)
+}
+
+func TestProvider_Shutdown(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	cfg := confmap.New()
+
+	p := NewProvider(cfg)
+	ret, err := p.Retrieve(ctx, p.URI(), func(event *confmap.ChangeEvent) {})
+	require.NoError(t, err)
+	retCfg, err := ret.AsConf()
+	require.NoError(t, err)
+	require.Equal(t, cfg, retCfg)
+
+	err = p.Shutdown(ctx)
+	require.NoError(t, err)
+}
diff --git a/internal/pkg/otel/components.go b/internal/pkg/otel/components.go
index 42cf27581bc..06e4c89c239 100644
--- a/internal/pkg/otel/components.go
+++ b/internal/pkg/otel/components.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package otel
 
 import (
@@ -62,75 +60,80 @@ import (
 	"github.com/elastic/opentelemetry-collector-components/connector/signaltometricsconnector"
 )
 
-func components() (otelcol.Factories, error) {
-	var err error
-	factories := otelcol.Factories{}
-
-	// Receivers
-	factories.Receivers, err = receiver.MakeFactoryMap(
-		otlpreceiver.NewFactory(),
-		filelogreceiver.NewFactory(),
-		kubeletstatsreceiver.NewFactory(),
-		k8sclusterreceiver.NewFactory(),
-		hostmetricsreceiver.NewFactory(),
-		httpcheckreceiver.NewFactory(),
-		k8sobjectsreceiver.NewFactory(),
-		prometheusreceiver.NewFactory(),
-		jaegerreceiver.NewFactory(),
-		zipkinreceiver.NewFactory(),
-		fbreceiver.NewFactory(),
-	)
-	if err != nil {
-		return otelcol.Factories{}, err
-	}
-
-	// Processors
-	factories.Processors, err = processor.MakeFactoryMap(
-		batchprocessor.NewFactory(),
-		resourceprocessor.NewFactory(),
-		attributesprocessor.NewFactory(),
-		transformprocessor.NewFactory(),
-		filterprocessor.NewFactory(),
-		k8sattributesprocessor.NewFactory(),
-		elasticinframetricsprocessor.NewFactory(),
-		resourcedetectionprocessor.NewFactory(),
-		memorylimiterprocessor.NewFactory(),
-		lsmintervalprocessor.NewFactory(),
-		elastictraceprocessor.NewFactory(),
-	)
-	if err != nil {
-		return otelcol.Factories{}, err
-	}
-
-	// Exporters
-	factories.Exporters, err = exporter.MakeFactoryMap(
-		otlpexporter.NewFactory(),
-		debugexporter.NewFactory(),
-		fileexporter.NewFactory(),
-		elasticsearchexporter.NewFactory(),
-		otlphttpexporter.NewFactory(),
-	)
-	if err != nil {
-		return otelcol.Factories{}, err
+func components(extensionFactories ...extension.Factory) func() (otelcol.Factories, error) {
+	return func() (otelcol.Factories, error) {
+
+		var err error
+		factories := otelcol.Factories{}
+
+		// Receivers
+		factories.Receivers, err = receiver.MakeFactoryMap(
+			otlpreceiver.NewFactory(),
+			filelogreceiver.NewFactory(),
+			kubeletstatsreceiver.NewFactory(),
+			k8sclusterreceiver.NewFactory(),
+			hostmetricsreceiver.NewFactory(),
+			httpcheckreceiver.NewFactory(),
+			k8sobjectsreceiver.NewFactory(),
+			prometheusreceiver.NewFactory(),
+			jaegerreceiver.NewFactory(),
+			zipkinreceiver.NewFactory(),
+			fbreceiver.NewFactory(),
+		)
+		if err != nil {
+			return otelcol.Factories{}, err
+		}
+
+		// Processors
+		factories.Processors, err = processor.MakeFactoryMap(
+			batchprocessor.NewFactory(),
+			resourceprocessor.NewFactory(),
+			attributesprocessor.NewFactory(),
+			transformprocessor.NewFactory(),
+			filterprocessor.NewFactory(),
+			k8sattributesprocessor.NewFactory(),
+			elasticinframetricsprocessor.NewFactory(),
+			resourcedetectionprocessor.NewFactory(),
+			memorylimiterprocessor.NewFactory(),
+			lsmintervalprocessor.NewFactory(),
+			elastictraceprocessor.NewFactory(),
+		)
+		if err != nil {
+			return otelcol.Factories{}, err
+		}
+
+		// Exporters
+		factories.Exporters, err = exporter.MakeFactoryMap(
+			otlpexporter.NewFactory(),
+			debugexporter.NewFactory(),
+			fileexporter.NewFactory(),
+			elasticsearchexporter.NewFactory(),
+			otlphttpexporter.NewFactory(),
+		)
+		if err != nil {
+			return otelcol.Factories{}, err
+		}
+
+		factories.Connectors, err = connector.MakeFactoryMap(
+			spanmetricsconnector.NewFactory(),
+			signaltometricsconnector.NewFactory(),
+		)
+		if err != nil {
+			return otelcol.Factories{}, err
+		}
+
+		extensions := []extension.Factory{
+			memorylimiterextension.NewFactory(),
+			filestorage.NewFactory(),
+			healthcheckextension.NewFactory(),
+			pprofextension.NewFactory(),
+		}
+		extensions = append(extensions, extensionFactories...)
+		factories.Extensions, err = extension.MakeFactoryMap(extensions...)
+		if err != nil {
+			return otelcol.Factories{}, err
+		}
+
+		return factories, err
 	}
-
-	factories.Connectors, err = connector.MakeFactoryMap(
-		spanmetricsconnector.NewFactory(),
-		signaltometricsconnector.NewFactory(),
-	)
-	if err != nil {
-		return otelcol.Factories{}, err
-	}
-
-	factories.Extensions, err = extension.MakeFactoryMap(
-		memorylimiterextension.NewFactory(),
-		filestorage.NewFactory(),
-		healthcheckextension.NewFactory(),
-		pprofextension.NewFactory(),
-	)
-	if err != nil {
-		return otelcol.Factories{}, err
-	}
-
-	return factories, err
 }
diff --git a/internal/pkg/otel/config_file_provider.go b/internal/pkg/otel/config_file_provider.go
deleted file mode 100644
index 7a85f532986..00000000000
--- a/internal/pkg/otel/config_file_provider.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
-// or more contributor license agreements. Licensed under the Elastic License 2.0;
-// you may not use this file except in compliance with the Elastic License 2.0.
-
-//go:build !windows
-
-package otel
-
-import (
-	"context"
-	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"go.opentelemetry.io/collector/confmap"
-
-	"github.com/elastic/elastic-agent/internal/pkg/config"
-)
-
-const schemeName = "file"
-
-type provider struct{}
-
-func NewFileProviderWithDefaults() confmap.Provider {
-	return &provider{}
-}
-
-func (fmp *provider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) {
-	if !strings.HasPrefix(uri, schemeName+":") {
-		return nil, fmt.Errorf("%q uri is not supported by %q provider", uri, schemeName)
-	}
-
-	// Clean the path before using it.
-	content, err := os.ReadFile(filepath.Clean(uri[len(schemeName)+1:]))
-	if err != nil {
-		return nil, fmt.Errorf("unable to read the file %v: %w", uri, err)
-	}
-
-	config, err := config.NewConfigFrom(content)
-	if err != nil {
-		return nil, err
-	}
-
-	rawConf := defaultOtelConfig()
-	if err := config.Unpack(rawConf); err != nil {
-		return nil, err
-	}
-	return confmap.NewRetrieved(rawConf)
-}
-
-func (*provider) Scheme() string {
-	return schemeName
-}
-
-func (*provider) Shutdown(context.Context) error {
-	return nil
-}
-
-func defaultOtelConfig() map[string]any {
-	defaultConfig := map[string]any{
-		"service": map[string]any{
-			"telemetry": map[string]any{
-				"logs": map[string]any{
-					"output_paths": []string{"stdout"},
-				},
-			},
-		},
-	}
-
-	return defaultConfig
-}
diff --git a/internal/pkg/otel/config_file_provider_test.go b/internal/pkg/otel/config_file_provider_test.go
deleted file mode 100644
index d20533bdf5b..00000000000
--- a/internal/pkg/otel/config_file_provider_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
-// or more contributor license agreements. Licensed under the Elastic License 2.0;
-// you may not use this file except in compliance with the Elastic License 2.0.
-
-//go:build !windows
-
-package otel
-
-import (
-	"context"
-	"path/filepath"
-	"testing"
-
-	"github.com/stretchr/testify/require"
-)
-
-func TestContentFileProviderOutput(t *testing.T) {
-	testCases := []struct {
-		name            string
-		configFile      string
-		expectedOutputs []string
-	}{
-		{"default", "otel.yml", []string{"stdout"}},
-		{"stderr", "otlp.yml", []string{"stderr"}},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			cp := NewFileProviderWithDefaults()
-			confMap, err := cp.Retrieve(context.TODO(), "file:"+filepath.Join(".", "testdata", tc.configFile), nil)
-			require.NoError(t, err)
-
-			conf, err := confMap.AsConf()
-			require.NoError(t, err)
-			val := conf.Get("service::telemetry::logs::output_paths")
-			require.NotNil(t, val)
-
-			valStrArray, ok := val.([]string)
-			require.True(t, ok)
-			require.EqualValues(t, tc.expectedOutputs, valStrArray)
-		})
-	}
-}
diff --git a/internal/pkg/otel/config_manager.go b/internal/pkg/otel/config_manager.go
deleted file mode 100644
index 3af1c845ca2..00000000000
--- a/internal/pkg/otel/config_manager.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
-// or more contributor license agreements. Licensed under the Elastic License 2.0;
-// you may not use this file except in compliance with the Elastic License 2.0.
-
-package otel
-
-import (
-	"context"
-
-	"github.com/elastic/elastic-agent/internal/pkg/agent/application/coordinator"
-	"github.com/elastic/elastic-agent/internal/pkg/config"
-)
-
-// OtelModeConfigManager serves as a config manager for OTel use cases
-// In this case agent should ignore all configuration coming from elastic-agent.yml file
-// or other sources.
-type OtelModeConfigManager struct {
-	ch    chan coordinator.ConfigChange
-	errCh chan error
-}
-
-// NewOtelModeConfigManager creates new OtelModeConfigManager ignoring
-// configuration coming from other sources.
-func NewOtelModeConfigManager() *OtelModeConfigManager {
-	return &OtelModeConfigManager{
-		ch:    make(chan coordinator.ConfigChange),
-		errCh: make(chan error),
-	}
-}
-
-func (t *OtelModeConfigManager) Run(ctx context.Context) error {
-	// send config to transition from STARTING to HEALTHY
-	select {
-	case t.ch <- &otelConfigChange{}:
-	case <-ctx.Done():
-	}
-	<-ctx.Done()
-	return ctx.Err()
-}
-
-func (t *OtelModeConfigManager) Errors() <-chan error {
-	return t.errCh
-}
-
-// ActionErrors returns the error channel for actions.
-// Returns nil channel.
-func (t *OtelModeConfigManager) ActionErrors() <-chan error {
-	return nil
-}
-
-func (t *OtelModeConfigManager) Watch() <-chan coordinator.ConfigChange {
-	return t.ch
-}
-
-type otelConfigChange struct {
-}
-
-func (l *otelConfigChange) Config() *config.Config {
-	return config.New()
-}
-
-func (l *otelConfigChange) Ack() error {
-	// do nothing
-	return nil
-}
-
-func (l *otelConfigChange) Fail(_ error) {
-	// do nothing
-}
diff --git a/internal/pkg/otel/manager/extension.go b/internal/pkg/otel/manager/extension.go
new file mode 100644
index 00000000000..59d968df053
--- /dev/null
+++ b/internal/pkg/otel/manager/extension.go
@@ -0,0 +1,188 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package manager
+
+import (
+	"context"
+
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component"
+	"go.opentelemetry.io/collector/component/componentstatus"
+	"go.opentelemetry.io/collector/extension"
+	"go.uber.org/zap"
+)
+
+var AgentStatusExtensionType = component.MustNewType("agent_status")
+
+type evtPair struct {
+	source *componentstatus.InstanceID
+	event  *componentstatus.Event
+}
+
+type AgentStatusExtension struct {
+	mgr        *OTelManager
+	telemetry  component.TelemetrySettings
+	aggregator *status.Aggregator
+	eventCh    chan *evtPair
+	readyCh    chan struct{}
+	kickCh     chan struct{}
+	ctx        context.Context
+	canceller  context.CancelFunc
+	host       component.Host
+}
+
+// validate that the extension implements the required interfaces
+var _ component.Component = (*AgentStatusExtension)(nil)
+var _ componentstatus.Watcher = (*AgentStatusExtension)(nil)
+
+// NewAgentStatusExtension returns the agent_status extension to be used by the
+// OTel collector when running in hybrid mode.
+func NewAgentStatusExtension(ctx context.Context, set extension.Settings, mgr *OTelManager) *AgentStatusExtension {
+	ctx, cancel := context.WithCancel(ctx)
+	aggregator := status.NewAggregator(status.PriorityRecoverable)
+	as := &AgentStatusExtension{
+		mgr:        mgr,
+		telemetry:  set.TelemetrySettings,
+		aggregator: aggregator,
+		eventCh:    make(chan *evtPair),
+		readyCh:    make(chan struct{}),
+		kickCh:     make(chan struct{}, 1),
+		ctx:        ctx,
+		canceller:  cancel,
+	}
+
+	// start processing early as ComponentStatusChanged will be called before Start is called
+	go as.eventLoop(ctx)
+
+	return as
+}
+
+// NewAgentStatusFactory provides a factory for creating the AgentStatusExtension.
+func NewAgentStatusFactory(mgr *OTelManager) extension.Factory {
+	return extension.NewFactory(
+		AgentStatusExtensionType,
+		func() component.Config {
+			return nil
+		},
+		func(ctx context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) {
+			return NewAgentStatusExtension(ctx, set, mgr), nil
+		},
+		component.StabilityLevelDevelopment,
+	)
+}
+
+// Start implements the component.Component interface.
+func (as *AgentStatusExtension) Start(ctx context.Context, host component.Host) error {
+	as.telemetry.Logger.Debug("Starting agent status extension")
+	as.host = host
+	return nil
+}
+
+// Shutdown implements the component.Component interface.
+func (as *AgentStatusExtension) Shutdown(ctx context.Context) error {
+	// preemptively send the stopped event, so it can be exported before shutdown
+	componentstatus.ReportStatus(as.host, componentstatus.NewEvent(componentstatus.StatusStopped))
+	as.canceller()
+	return nil
+}
+
+// Ready implements the extension.PipelineWatcher interface.
+func (as *AgentStatusExtension) Ready() error {
+	close(as.readyCh)
+	return nil
+}
+
+// NotReady implements the extension.PipelineWatcher interface.
+func (as *AgentStatusExtension) NotReady() error {
+	return nil
+}
+
+// ComponentStatusChanged implements the extension.StatusWatcher interface.
+func (as *AgentStatusExtension) ComponentStatusChanged(
+	source *componentstatus.InstanceID,
+	event *componentstatus.Event,
+) {
+	// this extension is always force loaded and not by the user, so status
+	// information should be hidden as they didn't directly enable it
+	if source.ComponentID().String() == AgentStatusExtensionType.String() {
+		return
+	}
+	// possible that even after Shutdown is called that this function is still
+	// called by the coordinator
+	defer func() {
+		if r := recover(); r != nil {
+			as.telemetry.Logger.Info(
+				"discarding event received after shutdown",
+				zap.Any("source", source),
+				zap.Any("event", event),
+			)
+		}
+	}()
+	select {
+	case as.eventCh <- &evtPair{source: source, event: event}:
+	case <-as.ctx.Done():
+	}
+}
+
+func (as *AgentStatusExtension) eventLoop(ctx context.Context) {
+	// prevent aggregate statuses from flapping between StatusStarting and StatusOK
+	// as components are started individually by the service.
+	//
+	// follows the same pattern that is being used by the healthcheckv2extension
+	// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/extension/healthcheckv2extension/extension.go#L168
+	var eventQueue []*evtPair
+
+LOOP:
+	for {
+		select {
+		case esp := <-as.eventCh:
+			if esp.event.Status() != componentstatus.StatusStarting {
+				eventQueue = append(eventQueue, esp)
+				continue
+			}
+			as.aggregator.RecordStatus(esp.source, esp.event)
+			as.triggerKickCh()
+		case <-as.readyCh:
+			if len(eventQueue) > 0 {
+				for _, esp := range eventQueue {
+					as.aggregator.RecordStatus(esp.source, esp.event)
+				}
+				as.triggerKickCh()
+			}
+			break LOOP
+		case <-as.kickCh:
+			as.publishStatus()
+		case <-ctx.Done():
+			as.aggregator.Close()
+			return
+		}
+	}
+
+	// After PipelineWatcher.Ready, record statuses as they are received.
+	for {
+		select {
+		case esp := <-as.eventCh:
+			as.aggregator.RecordStatus(esp.source, esp.event)
+			as.triggerKickCh()
+		case <-as.kickCh:
+			as.publishStatus()
+		case <-ctx.Done():
+			as.aggregator.Close()
+			return
+		}
+	}
+}
+
+func (as *AgentStatusExtension) triggerKickCh() {
+	select {
+	case as.kickCh <- struct{}{}:
+	default:
+	}
+}
+
+func (as *AgentStatusExtension) publishStatus() {
+	current, _ := as.aggregator.AggregateStatus(status.ScopeAll, status.Verbose)
+	as.mgr.statusCh <- current
+}
diff --git a/internal/pkg/otel/manager/force_extension_converter.go b/internal/pkg/otel/manager/force_extension_converter.go
new file mode 100644
index 00000000000..11732d42229
--- /dev/null
+++ b/internal/pkg/otel/manager/force_extension_converter.go
@@ -0,0 +1,81 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package manager
+
+import (
+	"context"
+	"fmt"
+
+	"go.opentelemetry.io/collector/confmap"
+)
+
+// forceExtension is a Converter that forces that an extension is enabled in the OTel configuration.
+type forceExtension struct {
+	name string
+}
+
+func (fe *forceExtension) Convert(ctx context.Context, conf *confmap.Conf) error {
+	err := func() error {
+		err := conf.Merge(confmap.NewFromStringMap(map[string]interface{}{
+			"extensions": map[string]interface{}{
+				fe.name: nil,
+			},
+		}))
+		if err != nil {
+			return fmt.Errorf("merge into extensions failed: %w", err)
+		}
+		serviceConf, err := conf.Sub("service")
+		if err != nil {
+			//nolint:nilerr // ignore the error, no service defined in the configuration
+			// this is going to error by the collector any way no reason to pollute with more
+			// error information that is not really related to the issue at the moment
+			return nil
+		}
+		extensionsRaw := serviceConf.Get("extensions")
+		if extensionsRaw == nil {
+			// no extensions defined on service (easily add it)
+			err = conf.Merge(confmap.NewFromStringMap(map[string]interface{}{
+				"service": map[string]interface{}{
+					"extensions": []interface{}{fe.name},
+				},
+			}))
+			if err != nil {
+				return fmt.Errorf("merge into service::extensions failed: %w", err)
+			}
+			return nil
+		}
+		extensionsSlice, ok := extensionsRaw.([]interface{})
+		if !ok {
+			return fmt.Errorf("merge into service::extensions failed: expected []interface{}, got %T", extensionsRaw)
+		}
+		for _, extensionRaw := range extensionsSlice {
+			extension, ok := extensionRaw.(string)
+			if ok && extension == fe.name {
+				// already present, nothing to do
+				return nil
+			}
+		}
+		extensionsSlice = append(extensionsSlice, fe.name)
+		err = conf.Merge(confmap.NewFromStringMap(map[string]interface{}{
+			"service": map[string]interface{}{
+				"extensions": extensionsSlice,
+			},
+		}))
+		if err != nil {
+			return fmt.Errorf("merge into service::extensions failed: %w", err)
+		}
+		return nil
+	}()
+	if err != nil {
+		return fmt.Errorf("failed to force enable %s extension: %w", fe.name, err)
+	}
+	return nil
+}
+
+func NewForceExtensionConverterFactory(name string) confmap.ConverterFactory {
+	return confmap.NewConverterFactory(func(_ confmap.ConverterSettings) confmap.Converter {
+		return &forceExtension{name}
+	})
+}
diff --git a/internal/pkg/otel/manager/manager.go b/internal/pkg/otel/manager/manager.go
new file mode 100644
index 00000000000..af5a8052cec
--- /dev/null
+++ b/internal/pkg/otel/manager/manager.go
@@ -0,0 +1,228 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package manager
+
+import (
+	"context"
+	"errors"
+
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/confmap"
+	"go.opentelemetry.io/collector/otelcol"
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+
+	"github.com/elastic/elastic-agent/internal/pkg/otel"
+	"github.com/elastic/elastic-agent/internal/pkg/otel/agentprovider"
+	"github.com/elastic/elastic-agent/internal/pkg/release"
+	"github.com/elastic/elastic-agent/pkg/core/logger"
+)
+
+// OTelManager is a manager that manages the lifecycle of the OTel collector inside of the Elastic Agent.
+type OTelManager struct {
+	logger *logger.Logger
+	errCh  chan error
+
+	// The current configuration that the OTel collector is using. In the case that
+	// the cfg is nil then the collector is not running.
+	cfg *confmap.Conf
+
+	// cfg is changed by sending its new value on cfgCh, where it is
+	// handled by (*OTelManager).Run.
+	cfgCh chan *confmap.Conf
+
+	// stateCh passes the state information of the collector.
+	statusCh chan *status.AggregateStatus
+
+	// doneChan is closed when Run is stopped to signal that any
+	// pending update calls should be ignored.
+	doneChan chan struct{}
+}
+
+// NewOTelManager returns a OTelManager.
+func NewOTelManager(logger *logger.Logger) *OTelManager {
+	return &OTelManager{
+		logger:   logger,
+		errCh:    make(chan error),
+		cfgCh:    make(chan *confmap.Conf),
+		statusCh: make(chan *status.AggregateStatus),
+		doneChan: make(chan struct{}),
+	}
+}
+
+// Run runs the lifecycle of the manager.
+func (m *OTelManager) Run(ctx context.Context) error {
+	var err error
+	var cancel context.CancelFunc
+	var provider *agentprovider.Provider
+
+	// signal that the run loop is ended to unblock any incoming update calls
+	defer close(m.doneChan)
+
+	runErrCh := make(chan error)
+	for {
+		select {
+		case <-ctx.Done():
+			if cancel != nil {
+				cancel()
+				<-runErrCh // wait for collector to be stopped
+			}
+			return ctx.Err()
+		case err = <-runErrCh:
+			if err == nil {
+				// err is nil but there is a configuration
+				//
+				// in this rare case the collector stopped running but a configuration was
+				// provided and the collector stopped with a clean exit
+				cancel()
+				cancel, provider, err = m.startCollector(m.cfg, runErrCh)
+				if err != nil {
+					// failed to create the collector (this is different then
+					// it's failing to run). we do not retry creation on failure
+					// as it will always fail a new configuration is required for
+					// it not to fail (a new configuration will result in the retry)
+					select {
+					case m.errCh <- err:
+					case <-ctx.Done():
+					}
+				} else {
+					// all good at the moment (possible that it will fail)
+					select {
+					case m.errCh <- nil:
+					case <-ctx.Done():
+					}
+				}
+			} else {
+				// error occurred while running the collector, this occurs in the
+				// case that the configuration is invalid once the collector is started
+				// or the context for running the collector is cancelled.
+				//
+				// in the case that the configuration is invalid there is no reason to
+				// try again as it will keep failing so we do not trigger a restart
+				if cancel != nil {
+					cancel()
+					cancel = nil
+					provider = nil
+					// don't wait here for <-runErrCh, already occurred
+					// clear status, no longer running
+					select {
+					case m.statusCh <- nil:
+					case <-ctx.Done():
+					}
+				}
+				// pass the error to the errCh so the coordinator, unless it's a cancel error
+				if !errors.Is(err, context.Canceled) {
+					select {
+					case m.errCh <- nil:
+					case <-ctx.Done():
+					}
+				}
+			}
+		case cfg := <-m.cfgCh:
+			m.cfg = cfg
+			if cfg == nil {
+				// no configuration then the collector should not be
+				// running. if a cancel exists then it is running
+				// this cancels the context that will stop the running
+				// collector (this configuration does not get passed
+				// to the agent provider as an update)
+				if cancel != nil {
+					cancel()
+					cancel = nil
+					provider = nil
+					<-runErrCh // wait for collector to be stopped
+					// clear status, no longer running
+					select {
+					case m.statusCh <- nil:
+					case <-ctx.Done():
+					}
+				}
+				// ensure that the coordinator knows that there is no error
+				// as the collector is not running anymore
+				select {
+				case m.errCh <- nil:
+				case <-ctx.Done():
+				}
+			} else {
+				// either a new configuration or the first configuration
+				// that results in the collector being started
+				if cancel == nil {
+					// no cancel exists so the collector has not been
+					// started. start the collector with this configuration
+					cancel, provider, err = m.startCollector(m.cfg, runErrCh)
+					if err != nil {
+						// failed to create the collector (this is different then
+						// it's failing to run). we do not retry creation on failure
+						// as it will always fail a new configuration is required for
+						// it not to fail (a new configuration will result in the retry)
+						select {
+						case m.errCh <- err:
+						case <-ctx.Done():
+						}
+					} else {
+						// all good at the moment (possible that it will fail)
+						select {
+						case m.errCh <- nil:
+						case <-ctx.Done():
+						}
+					}
+				} else {
+					// collector is already running so only the configuration
+					// needs to be updated in the collector
+					provider.Update(m.cfg)
+				}
+			}
+		}
+	}
+}
+
+// Errors returns channel that can send an error that affects the state of the running agent.
+func (m *OTelManager) Errors() <-chan error {
+	return m.errCh
+}
+
+// Update updates the configuration.
+//
+// When nil is passed for the cfg, then the collector is stopped.
+func (m *OTelManager) Update(cfg *confmap.Conf) {
+	select {
+	case m.cfgCh <- cfg:
+	case <-m.doneChan:
+		// shutting down, ignore the update
+	}
+}
+
+// Watch returns a channel to watch for state information.
+//
+// This must be called and the channel must be read from, or it will block this manager.
+func (m *OTelManager) Watch() <-chan *status.AggregateStatus {
+	return m.statusCh
+}
+
+func (m *OTelManager) startCollector(cfg *confmap.Conf, errCh chan error) (context.CancelFunc, *agentprovider.Provider, error) {
+	ctx, cancel := context.WithCancel(context.Background())
+	ap := agentprovider.NewProvider(cfg)
+
+	// NewForceExtensionConverterFactory is used to ensure that the agent_status extension is always enabled.
+	// It is required for the Elastic Agent to extract the status out of the OTel collector.
+	settings := otel.NewSettings(
+		release.Version(), []string{ap.URI()},
+		otel.WithConfigProviderFactory(ap.NewFactory()),
+		otel.WithConfigConvertorFactory(NewForceExtensionConverterFactory(AgentStatusExtensionType.String())),
+		otel.WithExtensionFactory(NewAgentStatusFactory(m)))
+	settings.DisableGracefulShutdown = true // managed by this manager
+	settings.LoggingOptions = []zap.Option{zap.WrapCore(func(zapcore.Core) zapcore.Core {
+		return m.logger.Core() // use same zap as agent
+	})}
+	svc, err := otelcol.NewCollector(*settings)
+	if err != nil {
+		cancel()
+		return nil, nil, err
+	}
+	go func() {
+		errCh <- svc.Run(ctx)
+	}()
+	return cancel, ap, nil
+}
diff --git a/internal/pkg/otel/manager/manager_test.go b/internal/pkg/otel/manager/manager_test.go
new file mode 100644
index 00000000000..1b105e47d2c
--- /dev/null
+++ b/internal/pkg/otel/manager/manager_test.go
@@ -0,0 +1,184 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package manager
+
+import (
+	"context"
+	"errors"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component/componentstatus"
+	"go.opentelemetry.io/collector/confmap"
+
+	"github.com/elastic/elastic-agent/pkg/core/logger/loggertest"
+)
+
+var (
+	testConfig = map[string]interface{}{
+		"receivers": map[string]interface{}{
+			"otlp": map[string]interface{}{
+				"protocols": map[string]interface{}{
+					"grpc": map[string]interface{}{
+						"endpoint": "0.0.0.0:4317",
+					},
+				},
+			},
+		},
+		"processors": map[string]interface{}{
+			"batch": map[string]interface{}{},
+		},
+		"exporters": map[string]interface{}{
+			"otlp": map[string]interface{}{
+				"endpoint": "otelcol:4317",
+			},
+		},
+		"service": map[string]interface{}{
+			"pipelines": map[string]interface{}{
+				"traces": map[string]interface{}{
+					"receivers":  []string{"otlp"},
+					"processors": []string{"batch"},
+					"exporters":  []string{"otlp"},
+				},
+				"metrics": map[string]interface{}{
+					"receivers":  []string{"otlp"},
+					"processors": []string{"batch"},
+					"exporters":  []string{"otlp"},
+				},
+				"logs": map[string]interface{}{
+					"receivers":  []string{"otlp"},
+					"processors": []string{"batch"},
+					"exporters":  []string{"otlp"},
+				},
+			},
+		},
+	}
+)
+
+func TestOTelManager_Run(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	l, _ := loggertest.New("otel")
+	m := NewOTelManager(l)
+
+	var errMx sync.Mutex
+	var err error
+	go func() {
+		for {
+			select {
+			case <-ctx.Done():
+				return
+			case e := <-m.Errors():
+				if e != nil {
+					// no error should be produced (any error is a failure)
+					errMx.Lock()
+					err = e
+					errMx.Unlock()
+				}
+			}
+		}
+	}()
+	getLatestErr := func() error {
+		errMx.Lock()
+		defer errMx.Unlock()
+		return err
+	}
+
+	var latestMx sync.Mutex
+	var latest *status.AggregateStatus
+	go func() {
+		for {
+			select {
+			case <-ctx.Done():
+				return
+			case c := <-m.Watch():
+				latestMx.Lock()
+				latest = c
+				latestMx.Unlock()
+			}
+		}
+	}()
+	getLatestStatus := func() *status.AggregateStatus {
+		latestMx.Lock()
+		defer latestMx.Unlock()
+		return latest
+	}
+
+	var runWg sync.WaitGroup
+	var runErr error
+	runWg.Add(1)
+	go func() {
+		defer runWg.Done()
+		runErr = m.Run(ctx)
+	}()
+
+	ensureHealthy := func() {
+		if !assert.Eventuallyf(t, func() bool {
+			err := getLatestErr()
+			if err != nil {
+				// return now (but not for the correct reasons)
+				return true
+			}
+			latest := getLatestStatus()
+			if latest == nil || latest.Event.Status() != componentstatus.StatusOK {
+				return false
+			}
+			return true
+		}, 5*time.Minute, 1*time.Second, "otel collector never got healthy") {
+			lastStatus := getLatestStatus()
+			lastErr := getLatestErr()
+
+			// never got healthy, stop the manager and wait for it to end
+			cancel()
+			runWg.Wait()
+
+			// if a run error happened then report that
+			if !errors.Is(runErr, context.Canceled) {
+				t.Fatalf("otel manager never got healthy and the otel manager returned unexpected error: %v (latest status: %+v) (latest err: %v)", runErr, lastStatus, lastErr)
+			}
+			t.Fatalf("otel collector never got healthy: %+v (latest err: %v)", lastStatus, lastErr)
+		}
+		latestErr := getLatestErr()
+		require.NoError(t, latestErr, "runtime errored")
+	}
+
+	ensureOff := func() {
+		require.Eventuallyf(t, func() bool {
+			err := getLatestErr()
+			if err != nil {
+				// return now (but not for the correct reasons)
+				return true
+			}
+			latest := getLatestStatus()
+			return latest == nil
+		}, 5*time.Minute, 1*time.Second, "otel collector never stopped")
+		latestErr := getLatestErr()
+		require.NoError(t, latestErr, "runtime errored")
+	}
+
+	// ensure that it got healthy
+	cfg := confmap.NewFromStringMap(testConfig)
+	m.Update(cfg)
+	ensureHealthy()
+
+	// trigger update (no config compare is due externally to otel collector)
+	m.Update(cfg)
+	ensureHealthy()
+
+	// no configuration should stop the runner
+	m.Update(nil)
+	ensureOff()
+
+	cancel()
+	runWg.Wait()
+	if !errors.Is(runErr, context.Canceled) {
+		t.Errorf("otel manager returned unexpected error: %v", runErr)
+	}
+}
diff --git a/internal/pkg/otel/otelhelpers/status.go b/internal/pkg/otel/otelhelpers/status.go
new file mode 100644
index 00000000000..f11b4d9744c
--- /dev/null
+++ b/internal/pkg/otel/otelhelpers/status.go
@@ -0,0 +1,64 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package otelhelpers
+
+import (
+	"fmt"
+
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component/componentstatus"
+
+	"github.com/elastic/elastic-agent-client/v7/pkg/client"
+)
+
+// HasStatus returns true when the status contains that component status.
+func HasStatus(current *status.AggregateStatus, s componentstatus.Status) bool {
+	if current == nil {
+		return false
+	}
+	if current.Status() == s {
+		return true
+	}
+	for _, comp := range current.ComponentStatusMap {
+		return HasStatus(comp, s)
+	}
+	return false
+}
+
+// StateWithMessage returns a `client.UnitState` and message for the current status.
+func StateWithMessage(current *status.AggregateStatus) (client.UnitState, string) {
+	s := current.Status()
+	switch s {
+	case componentstatus.StatusNone:
+		// didn't report a status, we assume with no status
+		// that it is healthy
+		return client.UnitStateHealthy, "Healthy"
+	case componentstatus.StatusStarting:
+		return client.UnitStateStarting, "Starting"
+	case componentstatus.StatusOK:
+		return client.UnitStateHealthy, "Healthy"
+	case componentstatus.StatusRecoverableError:
+		if current.Err() != nil {
+			return client.UnitStateDegraded, fmt.Sprintf("Recoverable: %s", current.Err())
+		}
+		return client.UnitStateDegraded, "Unknown recoverable error"
+	case componentstatus.StatusPermanentError:
+		if current.Err() != nil {
+			return client.UnitStateFailed, fmt.Sprintf("Permanent: %s", current.Err())
+		}
+		return client.UnitStateFailed, "Unknown permanent error"
+	case componentstatus.StatusFatalError:
+		if current.Err() != nil {
+			return client.UnitStateFailed, fmt.Sprintf("Fatal: %s", current.Err())
+		}
+		return client.UnitStateFailed, "Unknown fatal error"
+	case componentstatus.StatusStopping:
+		return client.UnitStateStopping, "Stopping"
+	case componentstatus.StatusStopped:
+		return client.UnitStateStopped, "Stopped"
+	}
+	// if we hit this case, then a new status was added that we don't know about
+	return client.UnitStateFailed, fmt.Sprintf("Unknown component status: %s", s)
+}
diff --git a/internal/pkg/otel/otelhelpers/status_test.go b/internal/pkg/otel/otelhelpers/status_test.go
new file mode 100644
index 00000000000..f1858109596
--- /dev/null
+++ b/internal/pkg/otel/otelhelpers/status_test.go
@@ -0,0 +1,78 @@
+// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+// or more contributor license agreements. Licensed under the Elastic License 2.0;
+// you may not use this file except in compliance with the Elastic License 2.0.
+
+package otelhelpers
+
+import (
+	"testing"
+
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"github.com/stretchr/testify/assert"
+	"go.opentelemetry.io/collector/component/componentstatus"
+)
+
+func TestHasStatus(t *testing.T) {
+	scenarios := []struct {
+		Name   string
+		Result bool
+		Has    componentstatus.Status
+		Status *status.AggregateStatus
+	}{
+		{
+			Name:   "empty",
+			Result: false,
+			Has:    componentstatus.StatusOK,
+			Status: nil,
+		},
+		{
+			Name:   "has status",
+			Result: true,
+			Has:    componentstatus.StatusOK,
+			Status: &status.AggregateStatus{
+				Event: componentstatus.NewEvent(componentstatus.StatusOK),
+			},
+		},
+		{
+			Name:   "doesn't have status",
+			Result: false,
+			Has:    componentstatus.StatusRecoverableError,
+			Status: &status.AggregateStatus{
+				Event: componentstatus.NewEvent(componentstatus.StatusOK),
+			},
+		},
+		{
+			Name:   "sub-component has status",
+			Result: true,
+			Has:    componentstatus.StatusRecoverableError,
+			Status: &status.AggregateStatus{
+				Event: componentstatus.NewEvent(componentstatus.StatusOK),
+				ComponentStatusMap: map[string]*status.AggregateStatus{
+					"test-component": &status.AggregateStatus{
+						Event: componentstatus.NewEvent(componentstatus.StatusRecoverableError),
+					},
+				},
+			},
+		},
+		{
+			Name:   "sub-component doesn't have status",
+			Result: false,
+			Has:    componentstatus.StatusPermanentError,
+			Status: &status.AggregateStatus{
+				Event: componentstatus.NewEvent(componentstatus.StatusRecoverableError),
+				ComponentStatusMap: map[string]*status.AggregateStatus{
+					"test-component": &status.AggregateStatus{
+						Event: componentstatus.NewEvent(componentstatus.StatusRecoverableError),
+					},
+				},
+			},
+		},
+	}
+
+	for _, scenario := range scenarios {
+		t.Run(scenario.Name, func(t *testing.T) {
+			observed := HasStatus(scenario.Status, scenario.Has)
+			assert.Equal(t, scenario.Result, observed)
+		})
+	}
+}
diff --git a/internal/pkg/otel/run.go b/internal/pkg/otel/run.go
index 2beb819c21c..c647810bba1 100644
--- a/internal/pkg/otel/run.go
+++ b/internal/pkg/otel/run.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package otel
 
 import (
@@ -11,14 +9,15 @@ import (
 	"fmt"
 	"os"
 
-	"go.opentelemetry.io/collector/component"
-	"go.opentelemetry.io/collector/confmap"
-	"go.opentelemetry.io/collector/confmap/converter/expandconverter"
 	"go.opentelemetry.io/collector/confmap/provider/envprovider"
 	"go.opentelemetry.io/collector/confmap/provider/fileprovider"
 	"go.opentelemetry.io/collector/confmap/provider/httpprovider"
 	"go.opentelemetry.io/collector/confmap/provider/httpsprovider"
 	"go.opentelemetry.io/collector/confmap/provider/yamlprovider"
+	"go.opentelemetry.io/collector/extension"
+
+	"go.opentelemetry.io/collector/component"
+	"go.opentelemetry.io/collector/confmap"
 	"go.opentelemetry.io/collector/otelcol"
 
 	"github.com/elastic/elastic-agent/internal/pkg/release"
@@ -28,11 +27,7 @@ const buildDescription = "Elastic opentelemetry-collector distribution"
 
 func Run(ctx context.Context, stop chan bool, configFiles []string) error {
 	fmt.Fprintln(os.Stdout, "Starting in otel mode")
-	settings, err := newSettings(release.Version(), configFiles)
-	if err != nil {
-		return err
-	}
-
+	settings := NewSettings(release.Version(), configFiles)
 	svc, err := otelcol.NewCollector(*settings)
 	if err != nil {
 		return err
@@ -49,34 +44,69 @@ func Run(ctx context.Context, stop chan bool, configFiles []string) error {
 	return svc.Run(cancelCtx)
 }
 
-func newSettings(version string, configPaths []string) (*otelcol.CollectorSettings, error) {
+type options struct {
+	resolverConfigProviders    []confmap.ProviderFactory
+	resolverConverterFactories []confmap.ConverterFactory
+	extensionFactories         []extension.Factory
+}
+
+type SettingOpt func(o *options)
+
+func WithConfigProviderFactory(provider confmap.ProviderFactory) SettingOpt {
+	return func(o *options) {
+		o.resolverConfigProviders = append(o.resolverConfigProviders, provider)
+	}
+}
+
+func WithConfigConvertorFactory(converter confmap.ConverterFactory) SettingOpt {
+	return func(o *options) {
+		o.resolverConverterFactories = append(o.resolverConverterFactories, converter)
+	}
+}
+
+func WithExtensionFactory(factory extension.Factory) SettingOpt {
+	return func(o *options) {
+		o.extensionFactories = append(o.extensionFactories, factory)
+	}
+}
+
+func NewSettings(version string, configPaths []string, opts ...SettingOpt) *otelcol.CollectorSettings {
 	buildInfo := component.BuildInfo{
 		Command:     os.Args[0],
 		Description: buildDescription,
 		Version:     version,
 	}
+
+	var o options
+	for _, opt := range opts {
+		opt(&o)
+	}
+
+	providerFactories := []confmap.ProviderFactory{
+		fileprovider.NewFactory(),
+		envprovider.NewFactory(),
+		yamlprovider.NewFactory(),
+		httpprovider.NewFactory(),
+		httpsprovider.NewFactory(),
+	}
+	providerFactories = append(providerFactories, o.resolverConfigProviders...)
+	var converterFactories []confmap.ConverterFactory
+	converterFactories = append(converterFactories, o.resolverConverterFactories...)
 	configProviderSettings := otelcol.ConfigProviderSettings{
 		ResolverSettings: confmap.ResolverSettings{
-			URIs: configPaths,
-			ProviderFactories: []confmap.ProviderFactory{
-				fileprovider.NewFactory(),
-				envprovider.NewFactory(),
-				yamlprovider.NewFactory(),
-				httpprovider.NewFactory(),
-				httpsprovider.NewFactory(),
-			},
-			ConverterFactories: []confmap.ConverterFactory{
-				expandconverter.NewFactory(),
-			},
+			URIs:               configPaths,
+			ProviderFactories:  providerFactories,
+			DefaultScheme:      "env",
+			ConverterFactories: converterFactories,
 		},
 	}
 
 	return &otelcol.CollectorSettings{
-		Factories:              components,
+		Factories:              components(o.extensionFactories...),
 		BuildInfo:              buildInfo,
 		ConfigProviderSettings: configProviderSettings,
 		// we're handling DisableGracefulShutdown via the cancelCtx being passed
 		// to the collector's Run method in the Run function
 		DisableGracefulShutdown: true,
-	}, nil
+	}
 }
diff --git a/internal/pkg/otel/run_test.go b/internal/pkg/otel/run_test.go
index 1ab5594e82a..45adc51af85 100644
--- a/internal/pkg/otel/run_test.go
+++ b/internal/pkg/otel/run_test.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package otel
 
 import (
@@ -39,8 +37,7 @@ func TestStartCollector(t *testing.T) {
 	for _, tc := range testCases {
 		t.Run(tc.configFile, func(t *testing.T) {
 			configFiles := getConfigFiles(tc.configFile)
-			settings, err := newSettings("test", configFiles)
-			require.NoError(t, err)
+			settings := NewSettings("test", configFiles)
 
 			collector, err := otelcol.NewCollector(*settings)
 			require.NoError(t, err)
diff --git a/internal/pkg/otel/validate.go b/internal/pkg/otel/validate.go
index 543d9aad9f6..eedb0d07454 100644
--- a/internal/pkg/otel/validate.go
+++ b/internal/pkg/otel/validate.go
@@ -2,8 +2,6 @@
 // or more contributor license agreements. Licensed under the Elastic License 2.0;
 // you may not use this file except in compliance with the Elastic License 2.0.
 
-//go:build !windows
-
 package otel
 
 import (
@@ -15,15 +13,10 @@ import (
 )
 
 func Validate(ctx context.Context, configPaths []string) error {
-	settings, err := newSettings(release.Version(), configPaths)
-	if err != nil {
-		return err
-	}
-
+	settings := NewSettings(release.Version(), configPaths)
 	col, err := otelcol.NewCollector(*settings)
 	if err != nil {
 		return err
 	}
 	return col.DryRun(ctx)
-
 }
diff --git a/internal/pkg/remote/client.go b/internal/pkg/remote/client.go
index bd6ff7d26ad..3f31b25078b 100644
--- a/internal/pkg/remote/client.go
+++ b/internal/pkg/remote/client.go
@@ -87,7 +87,7 @@ func NewWithRawConfig(log *logger.Logger, config *config.Config, wrapper wrapper
 	}
 
 	cfg := Config{}
-	if err := config.Unpack(&cfg); err != nil {
+	if err := config.UnpackTo(&cfg); err != nil {
 		return nil, fmt.Errorf("invalidate configuration: %w", err)
 	}
 
diff --git a/pkg/component/config.go b/pkg/component/config.go
index fc84c423b71..3ff4ee787a4 100644
--- a/pkg/component/config.go
+++ b/pkg/component/config.go
@@ -45,7 +45,7 @@ func (c ComponentLimits) AsProto() *proto.ComponentLimits {
 	}
 
 	return &proto.ComponentLimits{
-		GoMaxProcs: uint64(c.GoMaxProcs),
+		GoMaxProcs: uint64(c.GoMaxProcs), //nolint:gosec // will never be negative
 		Source:     source,
 	}
 }
@@ -119,8 +119,8 @@ func deDotDataStream(ds *proto.DataStream, source *structpb.Struct) (*proto.Data
 	}
 
 	// Create a temporary struct to unpack the configuration.
-	// Unpack correctly handles any flattened fields like
-	// data_stream.type. So all we need to do is to call Unpack,
+	// UnpackTo correctly handles any flattened fields like
+	// data_stream.type. So all we need to do is to call UnpackTo,
 	// ensure the DataStream does not have a different value,
 	// them merge them both.
 	tmp := struct {
diff --git a/pkg/control/v1/proto/control_v1.pb.go b/pkg/control/v1/proto/control_v1.pb.go
index 0a79a2912cb..20321c5e0f0 100644
--- a/pkg/control/v1/proto/control_v1.pb.go
+++ b/pkg/control/v1/proto/control_v1.pb.go
@@ -5,7 +5,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.28.1
-// 	protoc        v5.27.1
+// 	protoc        v4.25.3
 // source: control_v1.proto
 
 // proto namespace/package name is shared with elastic-agent-client
diff --git a/pkg/control/v1/proto/control_v1_grpc.pb.go b/pkg/control/v1/proto/control_v1_grpc.pb.go
index b0e8f51b1e8..4af413bfec7 100644
--- a/pkg/control/v1/proto/control_v1_grpc.pb.go
+++ b/pkg/control/v1/proto/control_v1_grpc.pb.go
@@ -5,7 +5,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
 // - protoc-gen-go-grpc v1.2.0
-// - protoc             v5.27.1
+// - protoc             v4.25.3
 // source: control_v1.proto
 
 package proto
diff --git a/pkg/control/v2/client/client.go b/pkg/control/v2/client/client.go
index 35b9b7e6a8e..8e2b56f5842 100644
--- a/pkg/control/v2/client/client.go
+++ b/pkg/control/v2/client/client.go
@@ -26,6 +26,9 @@ type UnitType = cproto.UnitType
 // State is the state codes
 type State = cproto.State
 
+// CollectorComponentStatus is the status of a collector component
+type CollectorComponentStatus = cproto.CollectorComponentStatus
+
 // AdditionalMetrics is the type for additional diagnostic requests
 type AdditionalMetrics = cproto.AdditionalDiagnosticRequest
 
@@ -57,6 +60,25 @@ const (
 	Rollback State = cproto.State_ROLLBACK
 )
 
+const (
+	// CollectorComponentStatusNone is when the collector component doesn't report a status.
+	CollectorComponentStatusNone CollectorComponentStatus = cproto.CollectorComponentStatus_StatusNone
+	// CollectorComponentStatusStarting is when the collector component is starting.
+	CollectorComponentStatusStarting CollectorComponentStatus = cproto.CollectorComponentStatus_StatusStarting
+	// CollectorComponentStatusOK is when the collector component is in good health.
+	CollectorComponentStatusOK CollectorComponentStatus = cproto.CollectorComponentStatus_StatusOK
+	// CollectorComponentStatusRecoverableError is when the collector component had an error but can recover.
+	CollectorComponentStatusRecoverableError CollectorComponentStatus = cproto.CollectorComponentStatus_StatusRecoverableError
+	// CollectorComponentStatusPermanentError is when the collector component had a permanent error.
+	CollectorComponentStatusPermanentError CollectorComponentStatus = cproto.CollectorComponentStatus_StatusPermanentError
+	// CollectorComponentStatusFatalError is when the collector component had a fatal error.
+	CollectorComponentStatusFatalError CollectorComponentStatus = cproto.CollectorComponentStatus_StatusFatalError
+	// CollectorComponentStatusStopping is when the collector component is stopping.
+	CollectorComponentStatusStopping CollectorComponentStatus = cproto.CollectorComponentStatus_StatusStopping
+	// CollectorComponentStatusStopped is when the collector component is stopped.
+	CollectorComponentStatusStopped CollectorComponentStatus = cproto.CollectorComponentStatus_StatusStopped
+)
+
 const (
 	// CPU requests additional CPU diagnostics
 	CPU AdditionalMetrics = cproto.AdditionalDiagnosticRequest_CPU
@@ -97,6 +119,14 @@ type ComponentState struct {
 	VersionInfo ComponentVersionInfo `json:"version_info" yaml:"version_info"`
 }
 
+// CollectorComponent is a state of a collector component managed by the Elastic Agent.
+type CollectorComponent struct {
+	Status             CollectorComponentStatus       `json:"status" yaml:"status"`
+	Error              string                         `json:"error,omitempty" yaml:"error,omitempty"`
+	Timestamp          time.Time                      `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`
+	ComponentStatusMap map[string]*CollectorComponent `json:"components,omitempty" yaml:"components,omitempty"`
+}
+
 // AgentStateInfo is the overall information about the Elastic Agent.
 type AgentStateInfo struct {
 	ID           string `json:"id" yaml:"id"`
@@ -118,6 +148,7 @@ type AgentState struct {
 	FleetState     State                  `yaml:"fleet_state"`
 	FleetMessage   string                 `yaml:"fleet_message"`
 	UpgradeDetails *cproto.UpgradeDetails `json:"upgrade_details,omitempty" yaml:"upgrade_details,omitempty"`
+	Collector      *CollectorComponent    `json:"collector,omitempty" yaml:"collector,omitempty"`
 }
 
 // DiagnosticFileResult is a diagnostic file result.
@@ -516,5 +547,39 @@ func toState(res *cproto.StateResponse) (*AgentState, error) {
 		}
 		s.Components = append(s.Components, cs)
 	}
+	if res.Collector != nil {
+		cs, err := collectorToState(res.Collector)
+		if err != nil {
+			return nil, err
+		}
+		s.Collector = cs
+	}
 	return s, nil
 }
+
+func collectorToState(res *cproto.CollectorComponent) (*CollectorComponent, error) {
+	var t time.Time
+	var err error
+	if res.Timestamp != "" {
+		t, err = time.Parse(time.RFC3339Nano, res.Timestamp)
+		if err != nil {
+			return nil, err
+		}
+	}
+	cc := &CollectorComponent{
+		Status:    res.Status,
+		Error:     res.Error,
+		Timestamp: t,
+	}
+	if res.ComponentStatusMap != nil {
+		cc.ComponentStatusMap = make(map[string]*CollectorComponent, len(res.ComponentStatusMap))
+		for id, compStatus := range res.ComponentStatusMap {
+			cs, err := collectorToState(compStatus)
+			if err != nil {
+				return nil, err
+			}
+			cc.ComponentStatusMap[id] = cs
+		}
+	}
+	return cc, nil
+}
diff --git a/pkg/control/v2/cproto/control_v2.pb.go b/pkg/control/v2/cproto/control_v2.pb.go
index c5958f67981..802b79aed16 100644
--- a/pkg/control/v2/cproto/control_v2.pb.go
+++ b/pkg/control/v2/cproto/control_v2.pb.go
@@ -5,7 +5,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.28.1
-// 	protoc        v5.27.1
+// 	protoc        v4.25.3
 // source: control_v2.proto
 
 package cproto
@@ -94,6 +94,71 @@ func (State) EnumDescriptor() ([]byte, []int) {
 	return file_control_v2_proto_rawDescGZIP(), []int{0}
 }
 
+// CollectorComponentStatus used for OTel collector components.
+type CollectorComponentStatus int32
+
+const (
+	CollectorComponentStatus_StatusNone             CollectorComponentStatus = 0
+	CollectorComponentStatus_StatusStarting         CollectorComponentStatus = 1
+	CollectorComponentStatus_StatusOK               CollectorComponentStatus = 2
+	CollectorComponentStatus_StatusRecoverableError CollectorComponentStatus = 3
+	CollectorComponentStatus_StatusPermanentError   CollectorComponentStatus = 4
+	CollectorComponentStatus_StatusFatalError       CollectorComponentStatus = 5
+	CollectorComponentStatus_StatusStopping         CollectorComponentStatus = 6
+	CollectorComponentStatus_StatusStopped          CollectorComponentStatus = 7
+)
+
+// Enum value maps for CollectorComponentStatus.
+var (
+	CollectorComponentStatus_name = map[int32]string{
+		0: "StatusNone",
+		1: "StatusStarting",
+		2: "StatusOK",
+		3: "StatusRecoverableError",
+		4: "StatusPermanentError",
+		5: "StatusFatalError",
+		6: "StatusStopping",
+		7: "StatusStopped",
+	}
+	CollectorComponentStatus_value = map[string]int32{
+		"StatusNone":             0,
+		"StatusStarting":         1,
+		"StatusOK":               2,
+		"StatusRecoverableError": 3,
+		"StatusPermanentError":   4,
+		"StatusFatalError":       5,
+		"StatusStopping":         6,
+		"StatusStopped":          7,
+	}
+)
+
+func (x CollectorComponentStatus) Enum() *CollectorComponentStatus {
+	p := new(CollectorComponentStatus)
+	*p = x
+	return p
+}
+
+func (x CollectorComponentStatus) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (CollectorComponentStatus) Descriptor() protoreflect.EnumDescriptor {
+	return file_control_v2_proto_enumTypes[1].Descriptor()
+}
+
+func (CollectorComponentStatus) Type() protoreflect.EnumType {
+	return &file_control_v2_proto_enumTypes[1]
+}
+
+func (x CollectorComponentStatus) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use CollectorComponentStatus.Descriptor instead.
+func (CollectorComponentStatus) EnumDescriptor() ([]byte, []int) {
+	return file_control_v2_proto_rawDescGZIP(), []int{1}
+}
+
 // Unit Type running inside a component.
 type UnitType int32
 
@@ -125,11 +190,11 @@ func (x UnitType) String() string {
 }
 
 func (UnitType) Descriptor() protoreflect.EnumDescriptor {
-	return file_control_v2_proto_enumTypes[1].Descriptor()
+	return file_control_v2_proto_enumTypes[2].Descriptor()
 }
 
 func (UnitType) Type() protoreflect.EnumType {
-	return &file_control_v2_proto_enumTypes[1]
+	return &file_control_v2_proto_enumTypes[2]
 }
 
 func (x UnitType) Number() protoreflect.EnumNumber {
@@ -138,7 +203,7 @@ func (x UnitType) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use UnitType.Descriptor instead.
 func (UnitType) EnumDescriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{1}
+	return file_control_v2_proto_rawDescGZIP(), []int{2}
 }
 
 // Action status codes for restart and upgrade response.
@@ -174,11 +239,11 @@ func (x ActionStatus) String() string {
 }
 
 func (ActionStatus) Descriptor() protoreflect.EnumDescriptor {
-	return file_control_v2_proto_enumTypes[2].Descriptor()
+	return file_control_v2_proto_enumTypes[3].Descriptor()
 }
 
 func (ActionStatus) Type() protoreflect.EnumType {
-	return &file_control_v2_proto_enumTypes[2]
+	return &file_control_v2_proto_enumTypes[3]
 }
 
 func (x ActionStatus) Number() protoreflect.EnumNumber {
@@ -187,7 +252,7 @@ func (x ActionStatus) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use ActionStatus.Descriptor instead.
 func (ActionStatus) EnumDescriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{2}
+	return file_control_v2_proto_rawDescGZIP(), []int{3}
 }
 
 // pprof endpoint that can be requested.
@@ -242,11 +307,11 @@ func (x PprofOption) String() string {
 }
 
 func (PprofOption) Descriptor() protoreflect.EnumDescriptor {
-	return file_control_v2_proto_enumTypes[3].Descriptor()
+	return file_control_v2_proto_enumTypes[4].Descriptor()
 }
 
 func (PprofOption) Type() protoreflect.EnumType {
-	return &file_control_v2_proto_enumTypes[3]
+	return &file_control_v2_proto_enumTypes[4]
 }
 
 func (x PprofOption) Number() protoreflect.EnumNumber {
@@ -255,7 +320,7 @@ func (x PprofOption) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use PprofOption.Descriptor instead.
 func (PprofOption) EnumDescriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{3}
+	return file_control_v2_proto_rawDescGZIP(), []int{4}
 }
 
 // DiagnosticAgentRequestAdditional is an enum of additional diagnostic metrics that can be requested from Elastic Agent.
@@ -289,11 +354,11 @@ func (x AdditionalDiagnosticRequest) String() string {
 }
 
 func (AdditionalDiagnosticRequest) Descriptor() protoreflect.EnumDescriptor {
-	return file_control_v2_proto_enumTypes[4].Descriptor()
+	return file_control_v2_proto_enumTypes[5].Descriptor()
 }
 
 func (AdditionalDiagnosticRequest) Type() protoreflect.EnumType {
-	return &file_control_v2_proto_enumTypes[4]
+	return &file_control_v2_proto_enumTypes[5]
 }
 
 func (x AdditionalDiagnosticRequest) Number() protoreflect.EnumNumber {
@@ -302,7 +367,7 @@ func (x AdditionalDiagnosticRequest) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use AdditionalDiagnosticRequest.Descriptor instead.
 func (AdditionalDiagnosticRequest) EnumDescriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{4}
+	return file_control_v2_proto_rawDescGZIP(), []int{5}
 }
 
 // Empty message.
@@ -990,6 +1055,82 @@ func (x *StateAgentInfo) GetIsManaged() bool {
 	return false
 }
 
+// CollectorComponent is the status of an OTel collector component.
+type CollectorComponent struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Status of the component.
+	Status CollectorComponentStatus `protobuf:"varint,1,opt,name=status,proto3,enum=cproto.CollectorComponentStatus" json:"status,omitempty"`
+	// Error is set to the reported error.
+	Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
+	// Timestamp of status.
+	Timestamp string `protobuf:"bytes,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+	// Status information for sub-components of this component.
+	ComponentStatusMap map[string]*CollectorComponent `protobuf:"bytes,4,rep,name=ComponentStatusMap,proto3" json:"ComponentStatusMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *CollectorComponent) Reset() {
+	*x = CollectorComponent{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_control_v2_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CollectorComponent) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CollectorComponent) ProtoMessage() {}
+
+func (x *CollectorComponent) ProtoReflect() protoreflect.Message {
+	mi := &file_control_v2_proto_msgTypes[9]
+	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 CollectorComponent.ProtoReflect.Descriptor instead.
+func (*CollectorComponent) Descriptor() ([]byte, []int) {
+	return file_control_v2_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *CollectorComponent) GetStatus() CollectorComponentStatus {
+	if x != nil {
+		return x.Status
+	}
+	return CollectorComponentStatus_StatusNone
+}
+
+func (x *CollectorComponent) GetError() string {
+	if x != nil {
+		return x.Error
+	}
+	return ""
+}
+
+func (x *CollectorComponent) GetTimestamp() string {
+	if x != nil {
+		return x.Timestamp
+	}
+	return ""
+}
+
+func (x *CollectorComponent) GetComponentStatusMap() map[string]*CollectorComponent {
+	if x != nil {
+		return x.ComponentStatusMap
+	}
+	return nil
+}
+
 // StateResponse is the current state of Elastic Agent.
 // Next unused id: 8
 type StateResponse struct {
@@ -1011,12 +1152,14 @@ type StateResponse struct {
 	Components []*ComponentState `protobuf:"bytes,4,rep,name=components,proto3" json:"components,omitempty"`
 	// Upgrade details
 	UpgradeDetails *UpgradeDetails `protobuf:"bytes,7,opt,name=upgrade_details,json=upgradeDetails,proto3" json:"upgrade_details,omitempty"`
+	// OTel collector component status information.
+	Collector *CollectorComponent `protobuf:"bytes,8,opt,name=collector,proto3" json:"collector,omitempty"`
 }
 
 func (x *StateResponse) Reset() {
 	*x = StateResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[9]
+		mi := &file_control_v2_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1029,7 +1172,7 @@ func (x *StateResponse) String() string {
 func (*StateResponse) ProtoMessage() {}
 
 func (x *StateResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[9]
+	mi := &file_control_v2_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1042,7 +1185,7 @@ func (x *StateResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use StateResponse.ProtoReflect.Descriptor instead.
 func (*StateResponse) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{9}
+	return file_control_v2_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *StateResponse) GetInfo() *StateAgentInfo {
@@ -1094,6 +1237,13 @@ func (x *StateResponse) GetUpgradeDetails() *UpgradeDetails {
 	return nil
 }
 
+func (x *StateResponse) GetCollector() *CollectorComponent {
+	if x != nil {
+		return x.Collector
+	}
+	return nil
+}
+
 // UpgradeDetails captures the details of an ongoing Agent upgrade.
 type UpgradeDetails struct {
 	state         protoimpl.MessageState
@@ -1113,7 +1263,7 @@ type UpgradeDetails struct {
 func (x *UpgradeDetails) Reset() {
 	*x = UpgradeDetails{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[10]
+		mi := &file_control_v2_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1126,7 +1276,7 @@ func (x *UpgradeDetails) String() string {
 func (*UpgradeDetails) ProtoMessage() {}
 
 func (x *UpgradeDetails) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[10]
+	mi := &file_control_v2_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1139,7 +1289,7 @@ func (x *UpgradeDetails) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpgradeDetails.ProtoReflect.Descriptor instead.
 func (*UpgradeDetails) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{10}
+	return file_control_v2_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *UpgradeDetails) GetTargetVersion() string {
@@ -1199,7 +1349,7 @@ type UpgradeDetailsMetadata struct {
 func (x *UpgradeDetailsMetadata) Reset() {
 	*x = UpgradeDetailsMetadata{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[11]
+		mi := &file_control_v2_proto_msgTypes[12]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1212,7 +1362,7 @@ func (x *UpgradeDetailsMetadata) String() string {
 func (*UpgradeDetailsMetadata) ProtoMessage() {}
 
 func (x *UpgradeDetailsMetadata) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[11]
+	mi := &file_control_v2_proto_msgTypes[12]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1225,7 +1375,7 @@ func (x *UpgradeDetailsMetadata) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UpgradeDetailsMetadata.ProtoReflect.Descriptor instead.
 func (*UpgradeDetailsMetadata) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{11}
+	return file_control_v2_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *UpgradeDetailsMetadata) GetScheduledAt() string {
@@ -1293,7 +1443,7 @@ type DiagnosticFileResult struct {
 func (x *DiagnosticFileResult) Reset() {
 	*x = DiagnosticFileResult{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[12]
+		mi := &file_control_v2_proto_msgTypes[13]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1306,7 +1456,7 @@ func (x *DiagnosticFileResult) String() string {
 func (*DiagnosticFileResult) ProtoMessage() {}
 
 func (x *DiagnosticFileResult) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[12]
+	mi := &file_control_v2_proto_msgTypes[13]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1319,7 +1469,7 @@ func (x *DiagnosticFileResult) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticFileResult.ProtoReflect.Descriptor instead.
 func (*DiagnosticFileResult) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{12}
+	return file_control_v2_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *DiagnosticFileResult) GetName() string {
@@ -1376,7 +1526,7 @@ type DiagnosticAgentRequest struct {
 func (x *DiagnosticAgentRequest) Reset() {
 	*x = DiagnosticAgentRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[13]
+		mi := &file_control_v2_proto_msgTypes[14]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1389,7 +1539,7 @@ func (x *DiagnosticAgentRequest) String() string {
 func (*DiagnosticAgentRequest) ProtoMessage() {}
 
 func (x *DiagnosticAgentRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[13]
+	mi := &file_control_v2_proto_msgTypes[14]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1402,7 +1552,7 @@ func (x *DiagnosticAgentRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticAgentRequest.ProtoReflect.Descriptor instead.
 func (*DiagnosticAgentRequest) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{13}
+	return file_control_v2_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *DiagnosticAgentRequest) GetAdditionalMetrics() []AdditionalDiagnosticRequest {
@@ -1425,7 +1575,7 @@ type DiagnosticComponentsRequest struct {
 func (x *DiagnosticComponentsRequest) Reset() {
 	*x = DiagnosticComponentsRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[14]
+		mi := &file_control_v2_proto_msgTypes[15]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1438,7 +1588,7 @@ func (x *DiagnosticComponentsRequest) String() string {
 func (*DiagnosticComponentsRequest) ProtoMessage() {}
 
 func (x *DiagnosticComponentsRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[14]
+	mi := &file_control_v2_proto_msgTypes[15]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1451,7 +1601,7 @@ func (x *DiagnosticComponentsRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticComponentsRequest.ProtoReflect.Descriptor instead.
 func (*DiagnosticComponentsRequest) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{14}
+	return file_control_v2_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *DiagnosticComponentsRequest) GetComponents() []*DiagnosticComponentRequest {
@@ -1481,7 +1631,7 @@ type DiagnosticComponentRequest struct {
 func (x *DiagnosticComponentRequest) Reset() {
 	*x = DiagnosticComponentRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[15]
+		mi := &file_control_v2_proto_msgTypes[16]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1494,7 +1644,7 @@ func (x *DiagnosticComponentRequest) String() string {
 func (*DiagnosticComponentRequest) ProtoMessage() {}
 
 func (x *DiagnosticComponentRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[15]
+	mi := &file_control_v2_proto_msgTypes[16]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1507,7 +1657,7 @@ func (x *DiagnosticComponentRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticComponentRequest.ProtoReflect.Descriptor instead.
 func (*DiagnosticComponentRequest) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{15}
+	return file_control_v2_proto_rawDescGZIP(), []int{16}
 }
 
 func (x *DiagnosticComponentRequest) GetComponentId() string {
@@ -1530,7 +1680,7 @@ type DiagnosticAgentResponse struct {
 func (x *DiagnosticAgentResponse) Reset() {
 	*x = DiagnosticAgentResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[16]
+		mi := &file_control_v2_proto_msgTypes[17]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1543,7 +1693,7 @@ func (x *DiagnosticAgentResponse) String() string {
 func (*DiagnosticAgentResponse) ProtoMessage() {}
 
 func (x *DiagnosticAgentResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[16]
+	mi := &file_control_v2_proto_msgTypes[17]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1556,7 +1706,7 @@ func (x *DiagnosticAgentResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticAgentResponse.ProtoReflect.Descriptor instead.
 func (*DiagnosticAgentResponse) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{16}
+	return file_control_v2_proto_rawDescGZIP(), []int{17}
 }
 
 func (x *DiagnosticAgentResponse) GetResults() []*DiagnosticFileResult {
@@ -1583,7 +1733,7 @@ type DiagnosticUnitRequest struct {
 func (x *DiagnosticUnitRequest) Reset() {
 	*x = DiagnosticUnitRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[17]
+		mi := &file_control_v2_proto_msgTypes[18]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1596,7 +1746,7 @@ func (x *DiagnosticUnitRequest) String() string {
 func (*DiagnosticUnitRequest) ProtoMessage() {}
 
 func (x *DiagnosticUnitRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[17]
+	mi := &file_control_v2_proto_msgTypes[18]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1609,7 +1759,7 @@ func (x *DiagnosticUnitRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticUnitRequest.ProtoReflect.Descriptor instead.
 func (*DiagnosticUnitRequest) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{17}
+	return file_control_v2_proto_rawDescGZIP(), []int{18}
 }
 
 func (x *DiagnosticUnitRequest) GetComponentId() string {
@@ -1646,7 +1796,7 @@ type DiagnosticUnitsRequest struct {
 func (x *DiagnosticUnitsRequest) Reset() {
 	*x = DiagnosticUnitsRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[18]
+		mi := &file_control_v2_proto_msgTypes[19]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1659,7 +1809,7 @@ func (x *DiagnosticUnitsRequest) String() string {
 func (*DiagnosticUnitsRequest) ProtoMessage() {}
 
 func (x *DiagnosticUnitsRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[18]
+	mi := &file_control_v2_proto_msgTypes[19]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1672,7 +1822,7 @@ func (x *DiagnosticUnitsRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticUnitsRequest.ProtoReflect.Descriptor instead.
 func (*DiagnosticUnitsRequest) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{18}
+	return file_control_v2_proto_rawDescGZIP(), []int{19}
 }
 
 func (x *DiagnosticUnitsRequest) GetUnits() []*DiagnosticUnitRequest {
@@ -1703,7 +1853,7 @@ type DiagnosticUnitResponse struct {
 func (x *DiagnosticUnitResponse) Reset() {
 	*x = DiagnosticUnitResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[19]
+		mi := &file_control_v2_proto_msgTypes[20]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1716,7 +1866,7 @@ func (x *DiagnosticUnitResponse) String() string {
 func (*DiagnosticUnitResponse) ProtoMessage() {}
 
 func (x *DiagnosticUnitResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[19]
+	mi := &file_control_v2_proto_msgTypes[20]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1729,7 +1879,7 @@ func (x *DiagnosticUnitResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticUnitResponse.ProtoReflect.Descriptor instead.
 func (*DiagnosticUnitResponse) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{19}
+	return file_control_v2_proto_rawDescGZIP(), []int{20}
 }
 
 func (x *DiagnosticUnitResponse) GetComponentId() string {
@@ -1784,7 +1934,7 @@ type DiagnosticComponentResponse struct {
 func (x *DiagnosticComponentResponse) Reset() {
 	*x = DiagnosticComponentResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[20]
+		mi := &file_control_v2_proto_msgTypes[21]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1797,7 +1947,7 @@ func (x *DiagnosticComponentResponse) String() string {
 func (*DiagnosticComponentResponse) ProtoMessage() {}
 
 func (x *DiagnosticComponentResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[20]
+	mi := &file_control_v2_proto_msgTypes[21]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1810,7 +1960,7 @@ func (x *DiagnosticComponentResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticComponentResponse.ProtoReflect.Descriptor instead.
 func (*DiagnosticComponentResponse) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{20}
+	return file_control_v2_proto_rawDescGZIP(), []int{21}
 }
 
 func (x *DiagnosticComponentResponse) GetComponentId() string {
@@ -1847,7 +1997,7 @@ type DiagnosticUnitsResponse struct {
 func (x *DiagnosticUnitsResponse) Reset() {
 	*x = DiagnosticUnitsResponse{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[21]
+		mi := &file_control_v2_proto_msgTypes[22]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1860,7 +2010,7 @@ func (x *DiagnosticUnitsResponse) String() string {
 func (*DiagnosticUnitsResponse) ProtoMessage() {}
 
 func (x *DiagnosticUnitsResponse) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[21]
+	mi := &file_control_v2_proto_msgTypes[22]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1873,7 +2023,7 @@ func (x *DiagnosticUnitsResponse) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use DiagnosticUnitsResponse.ProtoReflect.Descriptor instead.
 func (*DiagnosticUnitsResponse) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{21}
+	return file_control_v2_proto_rawDescGZIP(), []int{22}
 }
 
 func (x *DiagnosticUnitsResponse) GetUnits() []*DiagnosticUnitResponse {
@@ -1896,7 +2046,7 @@ type ConfigureRequest struct {
 func (x *ConfigureRequest) Reset() {
 	*x = ConfigureRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_control_v2_proto_msgTypes[22]
+		mi := &file_control_v2_proto_msgTypes[23]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1909,7 +2059,7 @@ func (x *ConfigureRequest) String() string {
 func (*ConfigureRequest) ProtoMessage() {}
 
 func (x *ConfigureRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_control_v2_proto_msgTypes[22]
+	mi := &file_control_v2_proto_msgTypes[23]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1922,7 +2072,7 @@ func (x *ConfigureRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ConfigureRequest.ProtoReflect.Descriptor instead.
 func (*ConfigureRequest) Descriptor() ([]byte, []int) {
-	return file_control_v2_proto_rawDescGZIP(), []int{22}
+	return file_control_v2_proto_rawDescGZIP(), []int{23}
 }
 
 func (x *ConfigureRequest) GetConfig() string {
@@ -2021,204 +2171,240 @@ var file_control_v2_proto_rawDesc = []byte{
 	0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x6e, 0x70, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67,
 	0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64, 0x18,
 	0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x64,
-	0x22, 0xc6, 0x02, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x16, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41,
-	0x67, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x23,
-	0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e,
-	0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74,
-	0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a,
-	0x0a, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x0e, 0x32, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65,
-	0x52, 0x0a, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x0c,
-	0x66, 0x6c, 0x65, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x0c, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
-	0x12, 0x36, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f,
-	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x63, 0x6f,
-	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3f, 0x0a, 0x0f, 0x75, 0x70, 0x67, 0x72,
-	0x61, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x16, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61,
-	0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0e, 0x75, 0x70, 0x67, 0x72, 0x61,
-	0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0xa6, 0x01, 0x0a, 0x0e, 0x55, 0x70,
-	0x67, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e,
-	0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73,
-	0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x63, 0x74,
-	0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63,
-	0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
-	0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73,
-	0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
-	0x74, 0x61, 0x22, 0xef, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65,
-	0x74, 0x61, 0x69, 0x6c, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a,
-	0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x41, 0x74,
-	0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x70, 0x65, 0x72,
-	0x63, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0f, 0x64, 0x6f, 0x77, 0x6e,
-	0x6c, 0x6f, 0x61, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66,
-	0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b,
-	0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x26, 0x0a, 0x0f, 0x72,
-	0x65, 0x74, 0x72, 0x79, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x05,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x45, 0x72, 0x72, 0x6f, 0x72,
-	0x4d, 0x73, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x75, 0x6e, 0x74,
-	0x69, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x74, 0x72, 0x79, 0x55,
-	0x6e, 0x74, 0x69, 0x6c, 0x22, 0xdf, 0x01, 0x0a, 0x14, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
-	0x74, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a,
-	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
-	0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a,
-	0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12,
-	0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
-	0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79,
-	0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20,
-	0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09,
-	0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x67, 0x65, 0x6e,
-	0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x22, 0x6c, 0x0a, 0x16, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
-	0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x12, 0x52, 0x0a, 0x12, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d,
-	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
-	0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x52, 0x11, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x1b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
-	0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
-	0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70,
-	0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, 0x63, 0x6f,
-	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x52, 0x0a, 0x12, 0x61, 0x64, 0x64, 0x69,
-	0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02,
-	0x20, 0x03, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64,
-	0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
-	0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x11, 0x61, 0x64, 0x64, 0x69, 0x74,
-	0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x3f, 0x0a, 0x1a,
-	0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
-	0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f,
-	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x51, 0x0a,
-	0x17, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75,
-	0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x46, 0x69, 0x6c,
-	0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73,
-	0x22, 0x82, 0x01, 0x0a, 0x15, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55,
-	0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f,
-	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x2d, 0x0a,
-	0x09, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e,
-	0x32, 0x10, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x6e, 0x69, 0x74, 0x54, 0x79,
-	0x70, 0x65, 0x52, 0x08, 0x75, 0x6e, 0x69, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07,
-	0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75,
-	0x6e, 0x69, 0x74, 0x49, 0x64, 0x22, 0x4d, 0x0a, 0x16, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
-	0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
-	0x33, 0x0a, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d,
+	0x22, 0xc9, 0x02, 0x0a, 0x12, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f,
+	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
+	0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73,
+	0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
+	0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x62, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65,
+	0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x61, 0x70, 0x18, 0x04, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x32, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65,
+	0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x6f,
+	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x61, 0x70,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
+	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x61, 0x70, 0x1a, 0x61, 0x0a, 0x17, 0x43, 0x6f, 0x6d,
+	0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4d, 0x61, 0x70, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43,
+	0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
+	0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x80, 0x03, 0x0a,
+	0x0d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a,
+	0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x23, 0x0a, 0x05, 0x73, 0x74,
+	0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12,
+	0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2d, 0x0a, 0x0a, 0x66, 0x6c, 0x65,
+	0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e,
+	0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x66, 0x6c,
+	0x65, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x66, 0x6c, 0x65, 0x65,
+	0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
+	0x66, 0x6c, 0x65, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x36, 0x0a, 0x0a,
+	0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x16, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
+	0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
+	0x65, 0x6e, 0x74, 0x73, 0x12, 0x3f, 0x0a, 0x0f, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x5f,
+	0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e,
+	0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65,
+	0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x0e, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65,
+	0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74,
+	0x6f, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x70, 0x6f,
+	0x6e, 0x65, 0x6e, 0x74, 0x52, 0x09, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22,
+	0xa6, 0x01, 0x0a, 0x0e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69,
+	0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x76, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67,
+	0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61,
+	0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12,
+	0x1b, 0x0a, 0x09, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x08,
+	0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e,
+	0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x44,
+	0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08,
+	0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xef, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x67,
+	0x72, 0x61, 0x64, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x4d, 0x65, 0x74, 0x61, 0x64,
+	0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64,
+	0x5f, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64,
+	0x75, 0x6c, 0x65, 0x64, 0x41, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f,
+	0x61, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02,
+	0x52, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e,
+	0x74, 0x12, 0x21, 0x0a, 0x0c, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74,
+	0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x53,
+	0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x73,
+	0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73,
+	0x67, 0x12, 0x26, 0x0a, 0x0f, 0x72, 0x65, 0x74, 0x72, 0x79, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72,
+	0x5f, 0x6d, 0x73, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x74, 0x72,
+	0x79, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x73, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x74,
+	0x72, 0x79, 0x5f, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
+	0x72, 0x65, 0x74, 0x72, 0x79, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x22, 0xdf, 0x01, 0x0a, 0x14, 0x44,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73,
+	0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e,
+	0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69,
+	0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+	0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e,
+	0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74,
+	0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+	0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
+	0x70, 0x52, 0x09, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x22, 0x6c, 0x0a, 0x16,
+	0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x52, 0x0a, 0x12, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69,
+	0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03,
+	0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x69,
+	0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x11, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f,
+	0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xb5, 0x01, 0x0a, 0x1b, 0x44,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65,
+	0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0a, 0x63, 0x6f,
+	0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22,
 	0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
-	0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x05, 0x75,
-	0x6e, 0x69, 0x74, 0x73, 0x22, 0xd1, 0x01, 0x0a, 0x16, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
-	0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
-	0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
-	0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55,
-	0x6e, 0x69, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x75, 0x6e, 0x69, 0x74, 0x54, 0x79, 0x70,
-	0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72,
-	0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
-	0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e,
-	0x6f, 0x73, 0x74, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52,
-	0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x1b, 0x44, 0x69, 0x61,
-	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70,
-	0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
-	0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65,
-	0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f,
-	0x72, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67,
-	0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
-	0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x4f, 0x0a, 0x17, 0x44, 0x69, 0x61,
-	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61,
-	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
-	0x6e, 0x73, 0x65, 0x52, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x22, 0x2a, 0x0a, 0x10, 0x43, 0x6f,
-	0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16,
-	0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
-	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2a, 0x85, 0x01, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65,
-	0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0f,
-	0x0a, 0x0b, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12,
-	0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08,
-	0x44, 0x45, 0x47, 0x52, 0x41, 0x44, 0x45, 0x44, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41,
-	0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x49,
-	0x4e, 0x47, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10,
-	0x06, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x50, 0x47, 0x52, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x07,
-	0x12, 0x0c, 0x0a, 0x08, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41, 0x43, 0x4b, 0x10, 0x08, 0x2a, 0x21,
-	0x0a, 0x08, 0x55, 0x6e, 0x69, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e,
-	0x50, 0x55, 0x54, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x10,
-	0x01, 0x2a, 0x28, 0x0a, 0x0c, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75,
-	0x73, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0b,
-	0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52, 0x45, 0x10, 0x01, 0x2a, 0x7f, 0x0a, 0x0b, 0x50,
-	0x70, 0x72, 0x6f, 0x66, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4c,
-	0x4c, 0x4f, 0x43, 0x53, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10,
-	0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4d, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x02, 0x12, 0x0d,
-	0x0a, 0x09, 0x47, 0x4f, 0x52, 0x4f, 0x55, 0x54, 0x49, 0x4e, 0x45, 0x10, 0x03, 0x12, 0x08, 0x0a,
-	0x04, 0x48, 0x45, 0x41, 0x50, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x55, 0x54, 0x45, 0x58,
-	0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x4f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x06, 0x12,
-	0x10, 0x0a, 0x0c, 0x54, 0x48, 0x52, 0x45, 0x41, 0x44, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10,
-	0x07, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x08, 0x2a, 0x30, 0x0a, 0x1b,
-	0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
-	0x73, 0x74, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x07, 0x0a, 0x03, 0x43,
-	0x50, 0x55, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x4f, 0x4e, 0x4e, 0x10, 0x01, 0x32, 0xdf,
-	0x04, 0x0a, 0x13, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43,
-	0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x31, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
-	0x6e, 0x12, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
-	0x1a, 0x17, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
-	0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x53, 0x74, 0x61,
-	0x74, 0x65, 0x12, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74,
-	0x79, 0x1a, 0x15, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74,
-	0x65, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
-	0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53,
-	0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x31,
-	0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f,
+	0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x52,
+	0x0a, 0x12, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x69,
+	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52,
+	0x11, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x22, 0x3f, 0x0a, 0x1a, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
+	0x74, 0x49, 0x64, 0x22, 0x51, 0x0a, 0x17, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69,
+	0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36,
+	0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x1c, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
+	0x74, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72,
+	0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x82, 0x01, 0x0a, 0x15, 0x44, 0x69, 0x61, 0x67, 0x6e,
+	0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e,
+	0x74, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+	0x55, 0x6e, 0x69, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x75, 0x6e, 0x69, 0x74, 0x54, 0x79,
+	0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x6e, 0x69, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x74, 0x49, 0x64, 0x22, 0x4d, 0x0a, 0x16, 0x44,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x33, 0x0a, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69,
+	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x52, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x22, 0xd1, 0x01, 0x0a, 0x16, 0x44,
+	0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65,
+	0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6d,
+	0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x75, 0x6e, 0x69, 0x74,
+	0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x63, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x6e, 0x69, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x75,
+	0x6e, 0x69, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x6e, 0x69, 0x74, 0x5f,
+	0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x6e, 0x69, 0x74, 0x49, 0x64,
+	0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
+	0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52,
+	0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x8e,
+	0x01, 0x0a, 0x1b, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d,
+	0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21,
+	0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x49,
+	0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c,
+	0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x46, 0x69, 0x6c, 0x65,
+	0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22,
+	0x4f, 0x0a, 0x17, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69,
+	0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x05, 0x75, 0x6e,
+	0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x05, 0x75, 0x6e, 0x69, 0x74, 0x73,
+	0x22, 0x2a, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2a, 0x85, 0x01, 0x0a,
+	0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49,
+	0x4e, 0x47, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52,
+	0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x45, 0x41, 0x4c, 0x54, 0x48, 0x59,
+	0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x45, 0x47, 0x52, 0x41, 0x44, 0x45, 0x44, 0x10, 0x03,
+	0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08,
+	0x53, 0x54, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54,
+	0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x50, 0x47, 0x52, 0x41,
+	0x44, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x4f, 0x4c, 0x4c, 0x42, 0x41,
+	0x43, 0x4b, 0x10, 0x08, 0x2a, 0xbf, 0x01, 0x0a, 0x18, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74,
+	0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4e, 0x6f, 0x6e, 0x65, 0x10,
+	0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x74, 0x61, 0x72, 0x74,
+	0x69, 0x6e, 0x67, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4f,
+	0x4b, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x63,
+	0x6f, 0x76, 0x65, 0x72, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x03, 0x12,
+	0x18, 0x0a, 0x14, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x65,
+	0x6e, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x74, 0x61,
+	0x74, 0x75, 0x73, 0x46, 0x61, 0x74, 0x61, 0x6c, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x05, 0x12,
+	0x12, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x74, 0x6f, 0x70, 0x70, 0x69, 0x6e,
+	0x67, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x74, 0x6f,
+	0x70, 0x70, 0x65, 0x64, 0x10, 0x07, 0x2a, 0x21, 0x0a, 0x08, 0x55, 0x6e, 0x69, 0x74, 0x54, 0x79,
+	0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x10, 0x00, 0x12, 0x0a, 0x0a,
+	0x06, 0x4f, 0x55, 0x54, 0x50, 0x55, 0x54, 0x10, 0x01, 0x2a, 0x28, 0x0a, 0x0c, 0x41, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43,
+	0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x55, 0x52,
+	0x45, 0x10, 0x01, 0x2a, 0x7f, 0x0a, 0x0b, 0x50, 0x70, 0x72, 0x6f, 0x66, 0x4f, 0x70, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4c, 0x4c, 0x4f, 0x43, 0x53, 0x10, 0x00, 0x12, 0x09,
+	0x0a, 0x05, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4d, 0x44,
+	0x4c, 0x49, 0x4e, 0x45, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x47, 0x4f, 0x52, 0x4f, 0x55, 0x54,
+	0x49, 0x4e, 0x45, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x45, 0x41, 0x50, 0x10, 0x04, 0x12,
+	0x09, 0x0a, 0x05, 0x4d, 0x55, 0x54, 0x45, 0x58, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52,
+	0x4f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x48, 0x52, 0x45, 0x41,
+	0x44, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x07, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41,
+	0x43, 0x45, 0x10, 0x08, 0x2a, 0x30, 0x0a, 0x1b, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e,
+	0x61, 0x6c, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x07, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04,
+	0x43, 0x4f, 0x4e, 0x4e, 0x10, 0x01, 0x32, 0xdf, 0x04, 0x0a, 0x13, 0x45, 0x6c, 0x61, 0x73, 0x74,
+	0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x31,
+	0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f,
 	0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x3a, 0x0a, 0x07, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x12, 0x16, 0x2e, 0x63,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70,
-	0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a,
-	0x0f, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74,
-	0x12, 0x1e, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
-	0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x1f, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
-	0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x12, 0x53, 0x0a, 0x0f, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55,
-	0x6e, 0x69, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69,
-	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69,
-	0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x62, 0x0a, 0x14, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f,
-	0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x23,
-	0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74,
-	0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61,
-	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74,
-	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x34, 0x0a, 0x09, 0x43, 0x6f,
-	0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x12, 0x18, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
-	0x42, 0x29, 0x5a, 0x24, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6b, 0x67,
-	0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2f, 0x76,
-	0x32, 0x2f, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x6f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x12, 0x2d, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x2e, 0x63, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x63, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x12, 0x34, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x65, 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x0d,
+	0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e,
+	0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x31, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72,
+	0x74, 0x12, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
+	0x1a, 0x17, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x55, 0x70, 0x67,
+	0x72, 0x61, 0x64, 0x65, 0x12, 0x16, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70,
+	0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x0f, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73,
+	0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x1e, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e,
+	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x41, 0x67, 0x65, 0x6e,
+	0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x0f, 0x44, 0x69, 0x61,
+	0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x55, 0x6e, 0x69, 0x74, 0x73, 0x12, 0x1e, 0x2e, 0x63,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x55, 0x6e, 0x69, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63,
+	0x55, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x62,
+	0x0a, 0x14, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70,
+	0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
+	0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e,
+	0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x63, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x43,
+	0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x30, 0x01, 0x12, 0x34, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x12,
+	0x18, 0x2e, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
+	0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0d, 0x2e, 0x63, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x29, 0x5a, 0x24, 0x69, 0x6e, 0x74, 0x65,
+	0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x63,
+	0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -2233,89 +2419,96 @@ func file_control_v2_proto_rawDescGZIP() []byte {
 	return file_control_v2_proto_rawDescData
 }
 
-var file_control_v2_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
-var file_control_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
+var file_control_v2_proto_enumTypes = make([]protoimpl.EnumInfo, 6)
+var file_control_v2_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
 var file_control_v2_proto_goTypes = []interface{}{
 	(State)(0),                          // 0: cproto.State
-	(UnitType)(0),                       // 1: cproto.UnitType
-	(ActionStatus)(0),                   // 2: cproto.ActionStatus
-	(PprofOption)(0),                    // 3: cproto.PprofOption
-	(AdditionalDiagnosticRequest)(0),    // 4: cproto.AdditionalDiagnosticRequest
-	(*Empty)(nil),                       // 5: cproto.Empty
-	(*VersionResponse)(nil),             // 6: cproto.VersionResponse
-	(*RestartResponse)(nil),             // 7: cproto.RestartResponse
-	(*UpgradeRequest)(nil),              // 8: cproto.UpgradeRequest
-	(*UpgradeResponse)(nil),             // 9: cproto.UpgradeResponse
-	(*ComponentUnitState)(nil),          // 10: cproto.ComponentUnitState
-	(*ComponentVersionInfo)(nil),        // 11: cproto.ComponentVersionInfo
-	(*ComponentState)(nil),              // 12: cproto.ComponentState
-	(*StateAgentInfo)(nil),              // 13: cproto.StateAgentInfo
-	(*StateResponse)(nil),               // 14: cproto.StateResponse
-	(*UpgradeDetails)(nil),              // 15: cproto.UpgradeDetails
-	(*UpgradeDetailsMetadata)(nil),      // 16: cproto.UpgradeDetailsMetadata
-	(*DiagnosticFileResult)(nil),        // 17: cproto.DiagnosticFileResult
-	(*DiagnosticAgentRequest)(nil),      // 18: cproto.DiagnosticAgentRequest
-	(*DiagnosticComponentsRequest)(nil), // 19: cproto.DiagnosticComponentsRequest
-	(*DiagnosticComponentRequest)(nil),  // 20: cproto.DiagnosticComponentRequest
-	(*DiagnosticAgentResponse)(nil),     // 21: cproto.DiagnosticAgentResponse
-	(*DiagnosticUnitRequest)(nil),       // 22: cproto.DiagnosticUnitRequest
-	(*DiagnosticUnitsRequest)(nil),      // 23: cproto.DiagnosticUnitsRequest
-	(*DiagnosticUnitResponse)(nil),      // 24: cproto.DiagnosticUnitResponse
-	(*DiagnosticComponentResponse)(nil), // 25: cproto.DiagnosticComponentResponse
-	(*DiagnosticUnitsResponse)(nil),     // 26: cproto.DiagnosticUnitsResponse
-	(*ConfigureRequest)(nil),            // 27: cproto.ConfigureRequest
-	nil,                                 // 28: cproto.ComponentVersionInfo.MetaEntry
-	(*timestamppb.Timestamp)(nil),       // 29: google.protobuf.Timestamp
+	(CollectorComponentStatus)(0),       // 1: cproto.CollectorComponentStatus
+	(UnitType)(0),                       // 2: cproto.UnitType
+	(ActionStatus)(0),                   // 3: cproto.ActionStatus
+	(PprofOption)(0),                    // 4: cproto.PprofOption
+	(AdditionalDiagnosticRequest)(0),    // 5: cproto.AdditionalDiagnosticRequest
+	(*Empty)(nil),                       // 6: cproto.Empty
+	(*VersionResponse)(nil),             // 7: cproto.VersionResponse
+	(*RestartResponse)(nil),             // 8: cproto.RestartResponse
+	(*UpgradeRequest)(nil),              // 9: cproto.UpgradeRequest
+	(*UpgradeResponse)(nil),             // 10: cproto.UpgradeResponse
+	(*ComponentUnitState)(nil),          // 11: cproto.ComponentUnitState
+	(*ComponentVersionInfo)(nil),        // 12: cproto.ComponentVersionInfo
+	(*ComponentState)(nil),              // 13: cproto.ComponentState
+	(*StateAgentInfo)(nil),              // 14: cproto.StateAgentInfo
+	(*CollectorComponent)(nil),          // 15: cproto.CollectorComponent
+	(*StateResponse)(nil),               // 16: cproto.StateResponse
+	(*UpgradeDetails)(nil),              // 17: cproto.UpgradeDetails
+	(*UpgradeDetailsMetadata)(nil),      // 18: cproto.UpgradeDetailsMetadata
+	(*DiagnosticFileResult)(nil),        // 19: cproto.DiagnosticFileResult
+	(*DiagnosticAgentRequest)(nil),      // 20: cproto.DiagnosticAgentRequest
+	(*DiagnosticComponentsRequest)(nil), // 21: cproto.DiagnosticComponentsRequest
+	(*DiagnosticComponentRequest)(nil),  // 22: cproto.DiagnosticComponentRequest
+	(*DiagnosticAgentResponse)(nil),     // 23: cproto.DiagnosticAgentResponse
+	(*DiagnosticUnitRequest)(nil),       // 24: cproto.DiagnosticUnitRequest
+	(*DiagnosticUnitsRequest)(nil),      // 25: cproto.DiagnosticUnitsRequest
+	(*DiagnosticUnitResponse)(nil),      // 26: cproto.DiagnosticUnitResponse
+	(*DiagnosticComponentResponse)(nil), // 27: cproto.DiagnosticComponentResponse
+	(*DiagnosticUnitsResponse)(nil),     // 28: cproto.DiagnosticUnitsResponse
+	(*ConfigureRequest)(nil),            // 29: cproto.ConfigureRequest
+	nil,                                 // 30: cproto.ComponentVersionInfo.MetaEntry
+	nil,                                 // 31: cproto.CollectorComponent.ComponentStatusMapEntry
+	(*timestamppb.Timestamp)(nil),       // 32: google.protobuf.Timestamp
 }
 var file_control_v2_proto_depIdxs = []int32{
-	2,  // 0: cproto.RestartResponse.status:type_name -> cproto.ActionStatus
-	2,  // 1: cproto.UpgradeResponse.status:type_name -> cproto.ActionStatus
-	1,  // 2: cproto.ComponentUnitState.unit_type:type_name -> cproto.UnitType
+	3,  // 0: cproto.RestartResponse.status:type_name -> cproto.ActionStatus
+	3,  // 1: cproto.UpgradeResponse.status:type_name -> cproto.ActionStatus
+	2,  // 2: cproto.ComponentUnitState.unit_type:type_name -> cproto.UnitType
 	0,  // 3: cproto.ComponentUnitState.state:type_name -> cproto.State
-	28, // 4: cproto.ComponentVersionInfo.meta:type_name -> cproto.ComponentVersionInfo.MetaEntry
+	30, // 4: cproto.ComponentVersionInfo.meta:type_name -> cproto.ComponentVersionInfo.MetaEntry
 	0,  // 5: cproto.ComponentState.state:type_name -> cproto.State
-	10, // 6: cproto.ComponentState.units:type_name -> cproto.ComponentUnitState
-	11, // 7: cproto.ComponentState.version_info:type_name -> cproto.ComponentVersionInfo
-	13, // 8: cproto.StateResponse.info:type_name -> cproto.StateAgentInfo
-	0,  // 9: cproto.StateResponse.state:type_name -> cproto.State
-	0,  // 10: cproto.StateResponse.fleetState:type_name -> cproto.State
-	12, // 11: cproto.StateResponse.components:type_name -> cproto.ComponentState
-	15, // 12: cproto.StateResponse.upgrade_details:type_name -> cproto.UpgradeDetails
-	16, // 13: cproto.UpgradeDetails.metadata:type_name -> cproto.UpgradeDetailsMetadata
-	29, // 14: cproto.DiagnosticFileResult.generated:type_name -> google.protobuf.Timestamp
-	4,  // 15: cproto.DiagnosticAgentRequest.additional_metrics:type_name -> cproto.AdditionalDiagnosticRequest
-	20, // 16: cproto.DiagnosticComponentsRequest.components:type_name -> cproto.DiagnosticComponentRequest
-	4,  // 17: cproto.DiagnosticComponentsRequest.additional_metrics:type_name -> cproto.AdditionalDiagnosticRequest
-	17, // 18: cproto.DiagnosticAgentResponse.results:type_name -> cproto.DiagnosticFileResult
-	1,  // 19: cproto.DiagnosticUnitRequest.unit_type:type_name -> cproto.UnitType
-	22, // 20: cproto.DiagnosticUnitsRequest.units:type_name -> cproto.DiagnosticUnitRequest
-	1,  // 21: cproto.DiagnosticUnitResponse.unit_type:type_name -> cproto.UnitType
-	17, // 22: cproto.DiagnosticUnitResponse.results:type_name -> cproto.DiagnosticFileResult
-	17, // 23: cproto.DiagnosticComponentResponse.results:type_name -> cproto.DiagnosticFileResult
-	24, // 24: cproto.DiagnosticUnitsResponse.units:type_name -> cproto.DiagnosticUnitResponse
-	5,  // 25: cproto.ElasticAgentControl.Version:input_type -> cproto.Empty
-	5,  // 26: cproto.ElasticAgentControl.State:input_type -> cproto.Empty
-	5,  // 27: cproto.ElasticAgentControl.StateWatch:input_type -> cproto.Empty
-	5,  // 28: cproto.ElasticAgentControl.Restart:input_type -> cproto.Empty
-	8,  // 29: cproto.ElasticAgentControl.Upgrade:input_type -> cproto.UpgradeRequest
-	18, // 30: cproto.ElasticAgentControl.DiagnosticAgent:input_type -> cproto.DiagnosticAgentRequest
-	23, // 31: cproto.ElasticAgentControl.DiagnosticUnits:input_type -> cproto.DiagnosticUnitsRequest
-	19, // 32: cproto.ElasticAgentControl.DiagnosticComponents:input_type -> cproto.DiagnosticComponentsRequest
-	27, // 33: cproto.ElasticAgentControl.Configure:input_type -> cproto.ConfigureRequest
-	6,  // 34: cproto.ElasticAgentControl.Version:output_type -> cproto.VersionResponse
-	14, // 35: cproto.ElasticAgentControl.State:output_type -> cproto.StateResponse
-	14, // 36: cproto.ElasticAgentControl.StateWatch:output_type -> cproto.StateResponse
-	7,  // 37: cproto.ElasticAgentControl.Restart:output_type -> cproto.RestartResponse
-	9,  // 38: cproto.ElasticAgentControl.Upgrade:output_type -> cproto.UpgradeResponse
-	21, // 39: cproto.ElasticAgentControl.DiagnosticAgent:output_type -> cproto.DiagnosticAgentResponse
-	24, // 40: cproto.ElasticAgentControl.DiagnosticUnits:output_type -> cproto.DiagnosticUnitResponse
-	25, // 41: cproto.ElasticAgentControl.DiagnosticComponents:output_type -> cproto.DiagnosticComponentResponse
-	5,  // 42: cproto.ElasticAgentControl.Configure:output_type -> cproto.Empty
-	34, // [34:43] is the sub-list for method output_type
-	25, // [25:34] is the sub-list for method input_type
-	25, // [25:25] is the sub-list for extension type_name
-	25, // [25:25] is the sub-list for extension extendee
-	0,  // [0:25] is the sub-list for field type_name
+	11, // 6: cproto.ComponentState.units:type_name -> cproto.ComponentUnitState
+	12, // 7: cproto.ComponentState.version_info:type_name -> cproto.ComponentVersionInfo
+	1,  // 8: cproto.CollectorComponent.status:type_name -> cproto.CollectorComponentStatus
+	31, // 9: cproto.CollectorComponent.ComponentStatusMap:type_name -> cproto.CollectorComponent.ComponentStatusMapEntry
+	14, // 10: cproto.StateResponse.info:type_name -> cproto.StateAgentInfo
+	0,  // 11: cproto.StateResponse.state:type_name -> cproto.State
+	0,  // 12: cproto.StateResponse.fleetState:type_name -> cproto.State
+	13, // 13: cproto.StateResponse.components:type_name -> cproto.ComponentState
+	17, // 14: cproto.StateResponse.upgrade_details:type_name -> cproto.UpgradeDetails
+	15, // 15: cproto.StateResponse.collector:type_name -> cproto.CollectorComponent
+	18, // 16: cproto.UpgradeDetails.metadata:type_name -> cproto.UpgradeDetailsMetadata
+	32, // 17: cproto.DiagnosticFileResult.generated:type_name -> google.protobuf.Timestamp
+	5,  // 18: cproto.DiagnosticAgentRequest.additional_metrics:type_name -> cproto.AdditionalDiagnosticRequest
+	22, // 19: cproto.DiagnosticComponentsRequest.components:type_name -> cproto.DiagnosticComponentRequest
+	5,  // 20: cproto.DiagnosticComponentsRequest.additional_metrics:type_name -> cproto.AdditionalDiagnosticRequest
+	19, // 21: cproto.DiagnosticAgentResponse.results:type_name -> cproto.DiagnosticFileResult
+	2,  // 22: cproto.DiagnosticUnitRequest.unit_type:type_name -> cproto.UnitType
+	24, // 23: cproto.DiagnosticUnitsRequest.units:type_name -> cproto.DiagnosticUnitRequest
+	2,  // 24: cproto.DiagnosticUnitResponse.unit_type:type_name -> cproto.UnitType
+	19, // 25: cproto.DiagnosticUnitResponse.results:type_name -> cproto.DiagnosticFileResult
+	19, // 26: cproto.DiagnosticComponentResponse.results:type_name -> cproto.DiagnosticFileResult
+	26, // 27: cproto.DiagnosticUnitsResponse.units:type_name -> cproto.DiagnosticUnitResponse
+	15, // 28: cproto.CollectorComponent.ComponentStatusMapEntry.value:type_name -> cproto.CollectorComponent
+	6,  // 29: cproto.ElasticAgentControl.Version:input_type -> cproto.Empty
+	6,  // 30: cproto.ElasticAgentControl.State:input_type -> cproto.Empty
+	6,  // 31: cproto.ElasticAgentControl.StateWatch:input_type -> cproto.Empty
+	6,  // 32: cproto.ElasticAgentControl.Restart:input_type -> cproto.Empty
+	9,  // 33: cproto.ElasticAgentControl.Upgrade:input_type -> cproto.UpgradeRequest
+	20, // 34: cproto.ElasticAgentControl.DiagnosticAgent:input_type -> cproto.DiagnosticAgentRequest
+	25, // 35: cproto.ElasticAgentControl.DiagnosticUnits:input_type -> cproto.DiagnosticUnitsRequest
+	21, // 36: cproto.ElasticAgentControl.DiagnosticComponents:input_type -> cproto.DiagnosticComponentsRequest
+	29, // 37: cproto.ElasticAgentControl.Configure:input_type -> cproto.ConfigureRequest
+	7,  // 38: cproto.ElasticAgentControl.Version:output_type -> cproto.VersionResponse
+	16, // 39: cproto.ElasticAgentControl.State:output_type -> cproto.StateResponse
+	16, // 40: cproto.ElasticAgentControl.StateWatch:output_type -> cproto.StateResponse
+	8,  // 41: cproto.ElasticAgentControl.Restart:output_type -> cproto.RestartResponse
+	10, // 42: cproto.ElasticAgentControl.Upgrade:output_type -> cproto.UpgradeResponse
+	23, // 43: cproto.ElasticAgentControl.DiagnosticAgent:output_type -> cproto.DiagnosticAgentResponse
+	26, // 44: cproto.ElasticAgentControl.DiagnosticUnits:output_type -> cproto.DiagnosticUnitResponse
+	27, // 45: cproto.ElasticAgentControl.DiagnosticComponents:output_type -> cproto.DiagnosticComponentResponse
+	6,  // 46: cproto.ElasticAgentControl.Configure:output_type -> cproto.Empty
+	38, // [38:47] is the sub-list for method output_type
+	29, // [29:38] is the sub-list for method input_type
+	29, // [29:29] is the sub-list for extension type_name
+	29, // [29:29] is the sub-list for extension extendee
+	0,  // [0:29] is the sub-list for field type_name
 }
 
 func init() { file_control_v2_proto_init() }
@@ -2433,7 +2626,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*StateResponse); i {
+			switch v := v.(*CollectorComponent); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2445,7 +2638,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*UpgradeDetails); i {
+			switch v := v.(*StateResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2457,7 +2650,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*UpgradeDetailsMetadata); i {
+			switch v := v.(*UpgradeDetails); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2469,7 +2662,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticFileResult); i {
+			switch v := v.(*UpgradeDetailsMetadata); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2481,7 +2674,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticAgentRequest); i {
+			switch v := v.(*DiagnosticFileResult); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2493,7 +2686,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticComponentsRequest); i {
+			switch v := v.(*DiagnosticAgentRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2505,7 +2698,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticComponentRequest); i {
+			switch v := v.(*DiagnosticComponentsRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2517,7 +2710,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticAgentResponse); i {
+			switch v := v.(*DiagnosticComponentRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2529,7 +2722,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticUnitRequest); i {
+			switch v := v.(*DiagnosticAgentResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2541,7 +2734,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticUnitsRequest); i {
+			switch v := v.(*DiagnosticUnitRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2553,7 +2746,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticUnitResponse); i {
+			switch v := v.(*DiagnosticUnitsRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2565,7 +2758,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticComponentResponse); i {
+			switch v := v.(*DiagnosticUnitResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2577,7 +2770,7 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*DiagnosticUnitsResponse); i {
+			switch v := v.(*DiagnosticComponentResponse); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2589,6 +2782,18 @@ func file_control_v2_proto_init() {
 			}
 		}
 		file_control_v2_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*DiagnosticUnitsResponse); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_control_v2_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*ConfigureRequest); i {
 			case 0:
 				return &v.state
@@ -2606,8 +2811,8 @@ func file_control_v2_proto_init() {
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_control_v2_proto_rawDesc,
-			NumEnums:      5,
-			NumMessages:   24,
+			NumEnums:      6,
+			NumMessages:   26,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/pkg/control/v2/cproto/control_v2_grpc.pb.go b/pkg/control/v2/cproto/control_v2_grpc.pb.go
index a631e031cdb..90936b35785 100644
--- a/pkg/control/v2/cproto/control_v2_grpc.pb.go
+++ b/pkg/control/v2/cproto/control_v2_grpc.pb.go
@@ -5,7 +5,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
 // - protoc-gen-go-grpc v1.2.0
-// - protoc             v5.27.1
+// - protoc             v4.25.3
 // source: control_v2.proto
 
 package cproto
diff --git a/pkg/control/v2/server/server.go b/pkg/control/v2/server/server.go
index 866862f65bd..c6a1ad8cbd5 100644
--- a/pkg/control/v2/server/server.go
+++ b/pkg/control/v2/server/server.go
@@ -13,6 +13,9 @@ import (
 	"os"
 	"time"
 
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component/componentstatus"
+
 	"github.com/elastic/elastic-agent/pkg/control"
 	"github.com/elastic/elastic-agent/pkg/control/v1/proto"
 	v1server "github.com/elastic/elastic-agent/pkg/control/v1/server"
@@ -395,7 +398,7 @@ func stateToProto(state *coordinator.State, agentInfo info.Agent) (*cproto.State
 			Commit:       release.Commit(),
 			BuildTime:    release.BuildTime().Format(control.TimeFormat()),
 			Snapshot:     release.Snapshot(),
-			Pid:          int32(os.Getpid()),
+			Pid:          int32(os.Getpid()), //nolint:gosec // not going to have a pid greater than 32bit integer
 			Unprivileged: agentInfo.Unprivileged(),
 			IsManaged:    !agentInfo.IsStandalone(),
 		},
@@ -405,5 +408,48 @@ func stateToProto(state *coordinator.State, agentInfo info.Agent) (*cproto.State
 		FleetMessage:   state.FleetMessage,
 		Components:     components,
 		UpgradeDetails: upgradeDetails,
+		Collector:      collectorToProto(state.Collector),
 	}, nil
 }
+
+func collectorToProto(s *status.AggregateStatus) *cproto.CollectorComponent {
+	if s == nil {
+		return nil
+	}
+	r := &cproto.CollectorComponent{
+		Status:    otelComponentStatusToProto(s.Status()),
+		Timestamp: s.Timestamp().Format(time.RFC3339Nano),
+	}
+	if s.Err() != nil {
+		r.Error = s.Err().Error()
+	}
+	if len(s.ComponentStatusMap) > 0 {
+		r.ComponentStatusMap = make(map[string]*cproto.CollectorComponent, len(s.ComponentStatusMap))
+		for id, nested := range s.ComponentStatusMap {
+			r.ComponentStatusMap[id] = collectorToProto(nested)
+		}
+	}
+	return r
+}
+
+func otelComponentStatusToProto(s componentstatus.Status) cproto.CollectorComponentStatus {
+	switch s {
+	case componentstatus.StatusNone:
+		return cproto.CollectorComponentStatus_StatusNone
+	case componentstatus.StatusStarting:
+		return cproto.CollectorComponentStatus_StatusStarting
+	case componentstatus.StatusOK:
+		return cproto.CollectorComponentStatus_StatusOK
+	case componentstatus.StatusRecoverableError:
+		return cproto.CollectorComponentStatus_StatusRecoverableError
+	case componentstatus.StatusPermanentError:
+		return cproto.CollectorComponentStatus_StatusPermanentError
+	case componentstatus.StatusFatalError:
+		return cproto.CollectorComponentStatus_StatusFatalError
+	case componentstatus.StatusStopping:
+		return cproto.CollectorComponentStatus_StatusStopping
+	case componentstatus.StatusStopped:
+		return cproto.CollectorComponentStatus_StatusStopped
+	}
+	return cproto.CollectorComponentStatus_StatusNone
+}
diff --git a/pkg/control/v2/server/server_test.go b/pkg/control/v2/server/server_test.go
index abfc63e68a3..c6059575b46 100644
--- a/pkg/control/v2/server/server_test.go
+++ b/pkg/control/v2/server/server_test.go
@@ -8,6 +8,9 @@ import (
 	"testing"
 	"time"
 
+	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/status"
+	"go.opentelemetry.io/collector/component/componentstatus"
+
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
@@ -122,6 +125,19 @@ func TestStateMapping(t *testing.T) {
 						},
 					},
 				},
+				Collector: &status.AggregateStatus{
+					Event: componentstatus.NewEvent(componentstatus.StatusOK),
+					ComponentStatusMap: map[string]*status.AggregateStatus{
+						"some-pipeline": &status.AggregateStatus{
+							Event: componentstatus.NewEvent(componentstatus.StatusOK),
+							ComponentStatusMap: map[string]*status.AggregateStatus{
+								"receiver": &status.AggregateStatus{
+									Event: componentstatus.NewEvent(componentstatus.StatusOK),
+								},
+							},
+						},
+					},
+				},
 			}
 
 			if tc.upgradeDetails != nil {
@@ -164,6 +180,19 @@ func TestStateMapping(t *testing.T) {
 				}
 				assert.Equal(t, expectedCompState, stateResponse.Components[0])
 			}
+			if assert.NotNil(t, stateResponse.Collector) {
+				assert.Equal(t, cproto.CollectorComponentStatus_StatusOK, stateResponse.Collector.Status)
+				if assert.Contains(t, stateResponse.Collector.ComponentStatusMap, "some-pipeline") {
+					observed := stateResponse.Collector.ComponentStatusMap["some-pipeline"]
+					assert.Equal(t, cproto.CollectorComponentStatus_StatusOK, observed.Status)
+					assert.NotEmpty(t, observed.Timestamp)
+					if assert.Contains(t, observed.ComponentStatusMap, "receiver") {
+						observedReceiver := observed.ComponentStatusMap["receiver"]
+						assert.Equal(t, cproto.CollectorComponentStatus_StatusOK, observedReceiver.Status)
+						assert.NotEmpty(t, observedReceiver.Timestamp)
+					}
+				}
+			}
 
 			if tc.upgradeDetails != nil {
 				expectedMetadata := &cproto.UpgradeDetailsMetadata{
diff --git a/pkg/features/features.go b/pkg/features/features.go
index f079435cd99..1e547e73a47 100644
--- a/pkg/features/features.go
+++ b/pkg/features/features.go
@@ -172,7 +172,7 @@ func Parse(policy any) (*Flags, error) {
 	}
 
 	parsedFlags := cfg{}
-	if err := c.Unpack(&parsedFlags); err != nil {
+	if err := c.UnpackTo(&parsedFlags); err != nil {
 		return nil, fmt.Errorf("could not umpack features config: %w", err)
 	}
 
diff --git a/pkg/limits/limits.go b/pkg/limits/limits.go
index f28a67a3608..9d76e2cf129 100644
--- a/pkg/limits/limits.go
+++ b/pkg/limits/limits.go
@@ -128,7 +128,7 @@ func Parse(policy any) (*LimitsConfig, error) {
 	}
 
 	parsedConfig := rootConfig{}
-	if err := c.Unpack(&parsedConfig); err != nil {
+	if err := c.UnpackTo(&parsedConfig); err != nil {
 		return nil, fmt.Errorf("could not unpack limits config: %w", err)
 	}
 
diff --git a/pkg/testing/fixture.go b/pkg/testing/fixture.go
index 08bd20a8c7c..7d77409048d 100644
--- a/pkg/testing/fixture.go
+++ b/pkg/testing/fixture.go
@@ -810,7 +810,7 @@ func (f *Fixture) IsHealthy(ctx context.Context, opts ...process.CmdOption) erro
 
 	if status.State != int(cproto.State_HEALTHY) {
 		return fmt.Errorf("agent isn't healthy, current status: %s",
-			client.State(status.State))
+			client.State(status.State)) //nolint:gosec // value will never be over 32-bit
 	}
 
 	return nil
@@ -1287,6 +1287,13 @@ func createTempDir(t *testing.T) string {
 	return tempDir
 }
 
+type AgentStatusCollectorOutput struct {
+	Status             int                                    `json:"status"`
+	Error              string                                 `json:"error"`
+	Timestamp          string                                 `json:"timestamp"`
+	ComponentStatusMap map[string]*AgentStatusCollectorOutput `json:"components"`
+}
+
 type AgentStatusOutput struct {
 	Info struct {
 		ID           string `json:"id"`
@@ -1322,9 +1329,10 @@ type AgentStatusOutput struct {
 			} `json:"meta"`
 		} `json:"version_info,omitempty"`
 	} `json:"components"`
-	FleetState     int              `json:"FleetState"`
-	FleetMessage   string           `json:"FleetMessage"`
-	UpgradeDetails *details.Details `json:"upgrade_details"`
+	Collector      *AgentStatusCollectorOutput `json:"collector"`
+	FleetState     int                         `json:"FleetState"`
+	FleetMessage   string                      `json:"FleetMessage"`
+	UpgradeDetails *details.Details            `json:"upgrade_details"`
 }
 
 func (aso *AgentStatusOutput) IsZero() bool {
diff --git a/testing/integration/diagnostics_test.go b/testing/integration/diagnostics_test.go
index 26e53c3d68e..d43dd3f8aa7 100644
--- a/testing/integration/diagnostics_test.go
+++ b/testing/integration/diagnostics_test.go
@@ -44,6 +44,7 @@ var diagnosticsFiles = []string{
 	"heap.pprof.gz",
 	"local-config.yaml",
 	"mutex.pprof.gz",
+	"otel.yaml",
 	"pre-config.yaml",
 	"local-config.yaml",
 	"state.yaml",
diff --git a/testing/integration/otel_test.go b/testing/integration/otel_test.go
index 03edb8954be..3ff827b164e 100644
--- a/testing/integration/otel_test.go
+++ b/testing/integration/otel_test.go
@@ -20,8 +20,10 @@ import (
 	"text/template"
 	"time"
 
+	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
+	"github.com/elastic/elastic-agent/pkg/control/v2/client"
 	aTesting "github.com/elastic/elastic-agent/pkg/testing"
 	"github.com/elastic/elastic-agent/pkg/testing/define"
 	"github.com/elastic/elastic-agent/pkg/testing/tools/estools"
@@ -205,6 +207,131 @@ service:
 	require.True(t, err == nil || err == context.Canceled || err == context.DeadlineExceeded, "Retrieved unexpected error: %s", err.Error())
 }
 
+func TestOtelHybridFileProcessing(t *testing.T) {
+	define.Require(t, define.Requirements{
+		Group: Default,
+		Local: true,
+		OS: []define.OS{
+			// input path missing on windows
+			{Type: define.Linux},
+			{Type: define.Darwin},
+		},
+	})
+
+	// otel mode should be detected automatically
+	tmpDir := t.TempDir()
+	// create input file
+	numEvents := 50
+	inputFile, err := os.CreateTemp(tmpDir, "input.txt")
+	require.NoError(t, err, "failed to create temp file to hold data to ingest")
+	inputFilePath := inputFile.Name()
+	for i := 0; i < numEvents; i++ {
+		_, err = inputFile.Write([]byte(fmt.Sprintf("Line %d\n", i)))
+		require.NoErrorf(t, err, "failed to write line %d to temp file", i)
+	}
+	err = inputFile.Close()
+	require.NoError(t, err, "failed to close data temp file")
+	t.Cleanup(func() {
+		if t.Failed() {
+			contents, err := os.ReadFile(inputFilePath)
+			if err != nil {
+				t.Logf("no data file to import at %s", inputFilePath)
+				return
+			}
+			t.Logf("contents of import file:\n%s\n", string(contents))
+		}
+	})
+	// create output filename
+	outputFilePath := filepath.Join(tmpDir, "output.txt")
+	t.Cleanup(func() {
+		if t.Failed() {
+			contents, err := os.ReadFile(outputFilePath)
+			if err != nil {
+				t.Logf("no output data at %s", inputFilePath)
+				return
+			}
+			t.Logf("contents of output file:\n%s\n", string(contents))
+		}
+	})
+	// create the otel config with input and output
+	type otelConfigOptions struct {
+		InputPath  string
+		OutputPath string
+	}
+	otelConfigTemplate := `receivers:
+  filelog:
+    include:
+      - {{.InputPath}}
+    start_at: beginning
+
+exporters:
+  file:
+    path: {{.OutputPath}}
+service:
+  pipelines:
+    logs:
+      receivers:
+        - filelog
+      exporters:
+        - file
+`
+	var otelConfigBuffer bytes.Buffer
+	require.NoError(t,
+		template.Must(template.New("otelConfig").Parse(otelConfigTemplate)).Execute(&otelConfigBuffer,
+			otelConfigOptions{
+				InputPath:  inputFilePath,
+				OutputPath: outputFilePath,
+			}))
+
+	fixture, err := define.NewFixtureFromLocalBuild(t, define.Version())
+	require.NoError(t, err)
+
+	ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute))
+	defer cancel()
+	err = fixture.Prepare(ctx, fakeComponent)
+	require.NoError(t, err)
+
+	var fixtureWg sync.WaitGroup
+	fixtureWg.Add(1)
+	go func() {
+		defer fixtureWg.Done()
+		err = fixture.Run(ctx, aTesting.State{
+			Configure: otelConfigBuffer.String(),
+			Reached: func(state *client.AgentState) bool {
+				// keep running (context cancel will stop it)
+				return false
+			},
+		})
+	}()
+
+	var content []byte
+	require.Eventually(t,
+		func() bool {
+			// verify file exists
+			content, err = os.ReadFile(outputFilePath)
+			if err != nil || len(content) == 0 {
+				return false
+			}
+
+			found := bytes.Count(content, []byte(filepath.Base(inputFilePath)))
+			return found == numEvents
+		},
+		3*time.Minute, 500*time.Millisecond,
+		fmt.Sprintf("there should be exported logs by now"))
+
+	statusCtx, statusCancel := context.WithTimeout(ctx, 5*time.Second)
+	defer statusCancel()
+	output, err := fixture.ExecStatus(statusCtx)
+	require.NoError(t, err, "status command failed")
+
+	cancel()
+	fixtureWg.Wait()
+	require.True(t, err == nil || err == context.Canceled || err == context.DeadlineExceeded, "Retrieved unexpected error: %s", err.Error())
+
+	assert.NotNil(t, output.Collector)
+	assert.Equal(t, 2, output.Collector.Status, "collector status should have been StatusOK")
+}
+
 func validateCommandIsWorking(t *testing.T, ctx context.Context, fixture *aTesting.Fixture, tempDir string) {
 	fileProcessingConfig := []byte(`receivers:
   filelog: