This is an automated email from the ASF dual-hosted git repository.

luigidemasi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 2087d760fe89f2dba6a96488b61e3558037ae4cc
Author: Luigi De Masi <[email protected]>
AuthorDate: Fri Nov 13 13:07:21 2026 +0100

    CAMEL-25648: Extract the Semantic Micrometer integration into its own module
    
    Move the exporter and its tests into camel-semantic-micrometer, with normal
    dependencies on camel-semantic and camel-micrometer. Reuse the shared Camel
    context tag and keep semantic evaluation independent of Micrometer.
    
    Move the instrumentation guide to the bridge documentation, register the
    module in the build and catalog, and retain a base-module regression for
    evaluation with no Micrometer on its classpath.
    
    Co-authored-by: OpenAI Codex <[email protected]>
    Signed-off-by: Luigi De Masi <[email protected]>
---
 bom/camel-bom/pom.xml                              |   5 +
 catalog/camel-allcomponents/pom.xml                |   5 +
 .../org/apache/camel/catalog/docs.properties       |   1 +
 .../camel/catalog/docs/semantic-language.adoc      | 159 +-----------------
 .../camel/catalog/docs/semantic-micrometer.adoc    | 177 +++++++++++++++++++++
 .../org/apache/camel/catalog/others.properties     |   1 +
 .../camel/catalog/others/semantic-micrometer.json  |  15 ++
 .../pom.xml                                        |  59 ++-----
 .../services/org/apache/camel/other.properties     |   7 +
 .../generated/resources/semantic-micrometer.json   |  15 ++
 .../src/main/docs/semantic-micrometer.adoc         | 177 +++++++++++++++++++++
 .../micrometer/MicrometerSemanticMetrics.java      |   3 +-
 .../micrometer/MicrometerSemanticMetricsTest.java  |  49 ------
 components/camel-ai/camel-semantic/pom.xml         |  10 --
 .../src/main/docs/semantic-language.adoc           | 159 +-----------------
 .../semantic/SemanticWithoutMicrometerTest.java    |  60 +++++++
 components/camel-ai/pom.xml                        |   1 +
 design/semantic-audit.adoc                         |   2 +
 .../others/examples/json/semantic-micrometer.json  |   1 +
 docs/components/modules/others/nav.adoc            |   1 +
 .../modules/others/pages/semantic-micrometer.adoc  |   1 +
 parent/pom.xml                                     |   5 +
 .../apache/camel/maven/packaging/MojoHelper.java   |   3 +-
 23 files changed, 505 insertions(+), 411 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index 8536c1164318..4ecaadc9926e 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -2232,6 +2232,11 @@
         <artifactId>camel-semantic</artifactId>
         <version>4.24.0-SNAPSHOT</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-semantic-micrometer</artifactId>
+        <version>4.24.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-semantic-openai</artifactId>
diff --git a/catalog/camel-allcomponents/pom.xml 
b/catalog/camel-allcomponents/pom.xml
index fca54f0d854e..a0d095efde54 100644
--- a/catalog/camel-allcomponents/pom.xml
+++ b/catalog/camel-allcomponents/pom.xml
@@ -2012,6 +2012,11 @@
             <artifactId>camel-semantic</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-semantic-micrometer</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-semantic-openai</artifactId>
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties
index 2c98e3f33f4b..97888b9589b9 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs.properties
@@ -576,6 +576,7 @@ script-eip
 seda-component
 selective-consumer
 semantic-language
+semantic-micrometer
 semantic-openai
 semantic-typesafe-ai
 semantic-wolf-defender
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/semantic-language.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/semantic-language.adoc
index 445e1ccc4955..5175ac896296 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/semantic-language.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/semantic-language.adoc
@@ -1507,7 +1507,7 @@ camel semantic monitoring my-app 
--source=departmentMetrics
 The Semantic *Monitoring* sibling, `tui_get_monitoring`, `semantic-monitoring` 
console and CLI read this same
 current-value cache. The TUI offers expert/definition grouping, filters and an 
inspector for counts, durations,
 distributions, meaning, observation times and collection health. It has no 
historical-period, reference or
-comparison controls. Pausing affects the display only. The optional Micrometer 
listener below exports
+comparison controls. Pausing affects the display only. The optional Micrometer 
integration exports
 measurements independently of this viewer. Runtime-specific automatic 
registration and scrape endpoint
 integration are separate from the shared listener.
 
@@ -1520,155 +1520,8 @@ Facades are removed at context shutdown. Monitoring 
also works with JMX disabled
 
 === Optional Micrometer instrumentation
 
-`MicrometerSemanticMetrics` consumes typed assessment completion events 
directly. Add `io.micrometer:micrometer-core`
-to your application, or use the registry dependency supplied by your runtime. 
Micrometer is an optional dependency
-of `camel-semantic`; applications that do not register this listener do not 
need it. Prometheus is not a runtime
-dependency of the listener.
-
-Register one listener before starting the context, passing the application's 
existing `MeterRegistry`:
-
-[source,java]
-----
-import org.apache.camel.semantic.micrometer.MicrometerSemanticMetrics;
-
-// registry is the application's existing Micrometer MeterRegistry.
-// Optional, increasing score bucket bounds may include negative values.
-context.getManagementStrategy().addEventNotifier(
-    new MicrometerSemanticMetrics(registry, -1, 0, 0.5, 1, 2, 5));
-----
-
-The listener does not create or close a registry or install an HTTP server. 
The application/runtime owns
-registry configuration, HTTP exposure, authentication and the registry 
lifecycle. Give contexts sharing a registry
-distinct names. Registering more than one listener in a context fails at 
startup to prevent double counting.
-Stop removes meters created by the listener; restarting starts new counters. 
Existing application meters remain.
-
-Each completed assessment member is counted once, including individual batch 
members. Starts, request outcomes
-and locally aggregated `typed_results` snapshots are not counted again. 
Provider attempts/retries are not inferred
-from semantic completions. Audit capture, input capture, JMX, the local 
monitoring cache and UI polling are not
-required. Collection failures are isolated from the assessment and reported by 
the collection health meters.
-The first failure since collector start also logs a warning containing only 
the exception class, without its
-message, stack trace or event payload; subsequent failures only increment the 
error count.
-
-[cols="2,3",options="header"]
-|===
-|Micrometer name |Meaning
-|`camel.semantic.evaluations` |Counter by execution `status`: `success`, 
`failed`, or `not_executed`.
-|`camel.semantic.duration` |Timer recording each available execution duration, 
including failures. Skipped or
-missing durations are not zero-duration observations. Percentile histograms 
use the original durations.
-|`camel.semantic.result.availability` |Successful assessments by 
`availability`: `available` or `unavailable`.
-|`camel.semantic.results` |Counter by returned `answer`. Boolean values are 
final answers, without another
-probability threshold. Choice counts the selected answer, not probability 
entries. Classification counts each
-selected label once per assessment, so membership percentages need not sum to 
100%.
-|`camel.semantic.classification.empty` |Successful classification results with 
no selected labels.
-|`camel.semantic.score.observations` |Count of available finite numeric score 
observations.
-|`camel.semantic.score.sum`, `.minimum`, `.maximum` |Gauges preserving signed, 
fractional scores since collector
-start. The sum can decrease; do not treat it as a monotonic counter.
-|`camel.semantic.score.distribution` |Cumulative counters with inclusive `le` 
bounds supplied to the constructor and a
-`+Inf` bucket. Bounds describe numeric values, not severity or policy 
decisions.
-|`camel.semantic.collection.loss` |Counter by fixed `reason`: 
`population_limit`, `answer_limit`, `invalid_event`,
-or `unsupported_measurement`. Loss is excluded from the corresponding result 
distribution.
-|`camel.semantic.collection.errors` |Number of metric collection failures 
since collector start.
-|===
-
-Assessment meters have `camelContext`, `expert`, `definition`, `operation`, 
`origin` and `result.type` tags.
-Missing identity is the empty string; direct calls remain distinguishable by 
origin and the absence of a definition.
-The listener retains at most 100 distinct combinations and 64 answer labels of 
at most 256 characters per combination.
-Score histograms accept at most 64 finite, strictly increasing bounds; an 
empty array keeps count, sum, minimum,
-maximum and the overflow bucket. Configure identical bounds on instances you 
aggregate together.
-Each population can have both successful and failed duration timers. Default 
percentile histograms can add about
-70 bucket series per timer: the 100-population limit alone can therefore allow 
roughly 14,000 duration bucket
-series. Configure the registry's meter filter before registering the listener 
to choose fewer boundaries, for example:
-
-[source,java]
-----
-import java.time.Duration;
-
-import io.micrometer.core.instrument.Meter;
-import io.micrometer.core.instrument.config.MeterFilter;
-import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
-
-registry.config().meterFilter(new MeterFilter() {
-    @Override
-    public DistributionStatisticConfig configure(Meter.Id id, 
DistributionStatisticConfig config) {
-        if (id.getName().equals("camel.semantic.duration")) {
-            return 
DistributionStatisticConfig.builder().percentilesHistogram(false)
-                .serviceLevelObjectives(Duration.ofMillis(10).toNanos(), 
Duration.ofMillis(100).toNanos(),
-                    Duration.ofSeconds(1).toNanos(), 
Duration.ofSeconds(10).toNanos())
-                .build().merge(config);
-        }
-        return config;
-    }
-});
-----
-
-This example exports five duration buckets per timer in Prometheus, including 
`+Inf`, while retaining every
-observation in the count and sum. Choose boundaries for your latency goals: 
fewer buckets reduce percentile
-resolution. The `camelContext` tag matches Camel's other Micrometer metrics.
-
-Prompts, input, interpretation, exception messages and per-execution 
identifiers are never metric labels.
-Choose stable expert/definition names and result labels. Bounds limit retained 
series, but collection loss still
-means that a distribution may cover only part of the evaluated population. 
Collection error counts do not prove
-that every event was delivered: the shared AI notification contract remains 
synchronous and best effort.
-
-==== Expert-published scalar gauges
-
-The same listener accepts `SemanticMonitoringEvent` snapshots with 
`kind=gauge`, a single finite numeric
-`values.value`, and an explicit unit of `1`, `ratio`, `bytes`, `seconds`, 
`milliseconds`, `nanoseconds`, `count`,
-`requests` or `assessments`. If supplied, `availability` must be `available`. 
It exports
-`camel.semantic.expert.value` with `source`, `measurement` (the snapshot ID), 
`unit` and the supplied
-`expert`, `definition`, `operation`, `provider`, `taskId`, `taskVersion`, 
`revision` dimensions. Missing dimensions
-are empty strings. Other dimension keys are rejected, including correlation 
and message identifiers.
-
-Values replace earlier values for that identity; repeated publication never 
increments a counter. At most 100
-such identities are retained, independently of assessment populations. The 
producer owns meaning and update cadence.
-The last value remains until the next publication or collector shutdown; 
scraping does not refresh it. A publication
-with an unavailable or invalid value marks an existing gauge as `NaN`, rather 
than continuing to expose its old value.
-Only published snapshots are consumed: the listener does not call 
`SemanticMetricSource.snapshots()` or perform I/O
-while an assessment completes. Unsupported kinds, units, shapes or dimensions 
increment `unsupported_measurement`;
-aggregated counts are not guessed to be deltas, and snapshot means are never 
converted to latency observations.
-
-==== Prometheus queries and lifecycle
-
-Expose the supplied registry through the runtime's normal metrics endpoint. 
Prometheus scrapes that endpoint and
-owns time-series retention; it does not depend on the Camel TUI being 
connected. Select a scrape interval that fits
-your operational needs (for example 15 seconds) and use a rate window 
containing several scrapes.
-The shared listener does not provide automatic Main, Spring Boot or Quarkus 
registration, a Prometheus query client,
-historical TUI views or dashboards. Runtime-specific examples and Quarkus 
native validation are follow-up work.
-
-For a Prometheus registry, dots become underscores and counters gain `_total`. 
These example backend queries aggregate
-across instances while retaining the selected expert or definition grouping:
-
-[source,promql]
-----
-# Executed assessment rate per expert; skipped members are excluded.
-sum by (expert) 
(rate(camel_semantic_evaluations_total{status=~"success|failed"}[5m]))
-
-# Failed execution rate per expert and definition.
-sum by (expert, definition) 
(rate(camel_semantic_evaluations_total{status="failed"}[5m]))
-
-# Returned-answer distribution per expert and definition.
-sum by (expert, definition, result_type, answer) 
(rate(camel_semantic_results_total[5m]))
-
-# 95th percentile from actual duration buckets, aggregated across instances.
-histogram_quantile(0.95,
-  sum by (expert, le) (rate(camel_semantic_duration_seconds_bucket[5m])))
-
-# Available score distribution using application-declared bounds.
-sum by (expert, definition, le) 
(rate(camel_semantic_score_distribution_total[5m]))
-
-# Counter resets observed on individual application series.
-resets(camel_semantic_evaluations_total[1h])
-
-# Collection exclusions over the observation window.
-sum by (reason) (increase(camel_semantic_collection_loss_total[5m]))
-----
-
-Apply `rate` or `increase` before summing across instances so resets are 
handled per series. A restart resets these
-counters; Prometheus history remains in Prometheus. The first scrape after 
startup cannot reconstruct evaluations
-that happened before a counter's first observed sample. Backend labels such as 
`job` and `instance` distinguish
-application instances; they are supplied by the scrape configuration, not 
unique evaluation IDs.
-
-Exemplars depend on the runtime's tracing context, registry and exposition 
format. This listener neither fabricates
-trace context nor promises an exemplar for every assessment, particularly for 
detached or asynchronous completions.
-Historical investigations may query independently retained audit records for a 
matching `[since, until)` interval,
-definition/operation and typed result. Audit retention and metric observations 
can cover different populations.
+Add xref:others:semantic-micrometer.adoc[Semantic Micrometer] 
(`camel-semantic-micrometer`) to export
+assessment counts, durations, typed result distributions and supported expert 
measurements to the
+application's Micrometer registry. The integration brings `camel-semantic` and 
`camel-micrometer`
+transitively and documents registration, metric names, cardinality limits, 
lifecycle and PromQL queries.
+`camel-semantic` itself has no Micrometer dependency.
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/semantic-micrometer.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/semantic-micrometer.adoc
new file mode 100644
index 000000000000..c3d175dab600
--- /dev/null
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/semantic-micrometer.adoc
@@ -0,0 +1,177 @@
+= Semantic Micrometer Component
+:doctitle: Semantic Micrometer
+:shortname: semantic-micrometer
+:artifactid: camel-semantic-micrometer
+:description: Export semantic assessments and expert measurements with 
Micrometer
+:since: 4.24
+:supportlevel: Preview
+:tabs-sync-option:
+
+*Since Camel {since}*
+
+This module exports typed assessment completion events and supported expert 
measurements from the
+xref:languages:semantic-language.adoc[Semantic language] to Micrometer. Add 
one dependency to bring
+both `camel-semantic` and `camel-micrometer` transitively, using the same 
version as Camel core:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-semantic-micrometer</artifactId>
+    <version>x.x.x</version>
+</dependency>
+----
+
+`camel-semantic` itself has no Micrometer dependency. This integration has no 
routing endpoint of its own;
+adding the dependency does not automatically register a collector. Prometheus 
is not a runtime dependency
+of this module: supply the registry implementation used by your application.
+
+== Register the collector
+
+Register one listener before starting the context, passing the application's 
existing `MeterRegistry`:
+
+[source,java]
+----
+import org.apache.camel.semantic.micrometer.MicrometerSemanticMetrics;
+
+// registry is the application's existing Micrometer MeterRegistry.
+// Optional, increasing score bucket bounds may include negative values.
+context.getManagementStrategy().addEventNotifier(
+    new MicrometerSemanticMetrics(registry, -1, 0, 0.5, 1, 2, 5));
+----
+
+The listener does not create or close a registry or install an HTTP server. 
The application/runtime owns
+registry configuration, HTTP exposure, authentication and the registry 
lifecycle. Give contexts sharing a registry
+distinct names. Registering more than one listener in a context fails at 
startup to prevent double counting.
+Stop removes meters created by the listener; restarting starts new counters. 
Existing application meters remain.
+
+Each completed assessment member is counted once, including individual batch 
members. Starts, request outcomes
+and locally aggregated `typed_results` snapshots are not counted again. 
Provider attempts/retries are not inferred
+from semantic completions. Audit capture, input capture, JMX, the local 
monitoring cache and UI polling are not
+required. Collection failures are isolated from the assessment and reported by 
the collection health meters.
+The first failure since collector start also logs a warning containing only 
the exception class, without its
+message, stack trace or event payload; subsequent failures only increment the 
error count.
+
+[cols="2,3",options="header"]
+|===
+|Micrometer name |Meaning
+|`camel.semantic.evaluations` |Counter by execution `status`: `success`, 
`failed`, or `not_executed`.
+|`camel.semantic.duration` |Timer recording each available execution duration, 
including failures. Skipped or
+missing durations are not zero-duration observations. Percentile histograms 
use the original durations.
+|`camel.semantic.result.availability` |Successful assessments by 
`availability`: `available` or `unavailable`.
+|`camel.semantic.results` |Counter by returned `answer`. Boolean values are 
final answers, without another
+probability threshold. Choice counts the selected answer, not probability 
entries. Classification counts each
+selected label once per assessment, so membership percentages need not sum to 
100%.
+|`camel.semantic.classification.empty` |Successful classification results with 
no selected labels.
+|`camel.semantic.score.observations` |Count of available finite numeric score 
observations.
+|`camel.semantic.score.sum`, `.minimum`, `.maximum` |Gauges preserving signed, 
fractional scores since collector
+start. The sum can decrease; do not treat it as a monotonic counter.
+|`camel.semantic.score.distribution` |Cumulative counters with inclusive `le` 
bounds supplied to the constructor and a
+`+Inf` bucket. Bounds describe numeric values, not severity or policy 
decisions.
+|`camel.semantic.collection.loss` |Counter by fixed `reason`: 
`population_limit`, `answer_limit`, `invalid_event`,
+or `unsupported_measurement`. Loss is excluded from the corresponding result 
distribution.
+|`camel.semantic.collection.errors` |Number of metric collection failures 
since collector start.
+|===
+
+Assessment meters have `camelContext`, `expert`, `definition`, `operation`, 
`origin` and `result.type` tags.
+Missing identity is the empty string; direct calls remain distinguishable by 
origin and the absence of a definition.
+The listener retains at most 100 distinct combinations and 64 answer labels of 
at most 256 characters per combination.
+Score histograms accept at most 64 finite, strictly increasing bounds; an 
empty array keeps count, sum, minimum,
+maximum and the overflow bucket. Configure identical bounds on instances you 
aggregate together.
+Each population can have both successful and failed duration timers. Default 
percentile histograms can add about
+70 bucket series per timer: the 100-population limit alone can therefore allow 
roughly 14,000 duration bucket
+series. Configure the registry's meter filter before registering the listener 
to choose fewer boundaries, for example:
+
+[source,java]
+----
+import java.time.Duration;
+
+import io.micrometer.core.instrument.Meter;
+import io.micrometer.core.instrument.config.MeterFilter;
+import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
+
+registry.config().meterFilter(new MeterFilter() {
+    @Override
+    public DistributionStatisticConfig configure(Meter.Id id, 
DistributionStatisticConfig config) {
+        if (id.getName().equals("camel.semantic.duration")) {
+            return 
DistributionStatisticConfig.builder().percentilesHistogram(false)
+                .serviceLevelObjectives(Duration.ofMillis(10).toNanos(), 
Duration.ofMillis(100).toNanos(),
+                    Duration.ofSeconds(1).toNanos(), 
Duration.ofSeconds(10).toNanos())
+                .build().merge(config);
+        }
+        return config;
+    }
+});
+----
+
+This example exports five duration buckets per timer in Prometheus, including 
`+Inf`, while retaining every
+observation in the count and sum. Choose boundaries for your latency goals: 
fewer buckets reduce percentile
+resolution. The `camelContext` tag matches Camel's other Micrometer metrics.
+
+Prompts, input, interpretation, exception messages and per-execution 
identifiers are never metric labels.
+Choose stable expert/definition names and result labels. Bounds limit retained 
series, but collection loss still
+means that a distribution may cover only part of the evaluated population. 
Collection error counts do not prove
+that every event was delivered: the shared AI notification contract remains 
synchronous and best effort.
+
+== Expert-published scalar gauges
+
+The same listener accepts `SemanticMonitoringEvent` snapshots with 
`kind=gauge`, a single finite numeric
+`values.value`, and an explicit unit of `1`, `ratio`, `bytes`, `seconds`, 
`milliseconds`, `nanoseconds`, `count`,
+`requests` or `assessments`. If supplied, `availability` must be `available`. 
It exports
+`camel.semantic.expert.value` with `source`, `measurement` (the snapshot ID), 
`unit` and the supplied
+`expert`, `definition`, `operation`, `provider`, `taskId`, `taskVersion`, 
`revision` dimensions. Missing dimensions
+are empty strings. Other dimension keys are rejected, including correlation 
and message identifiers.
+
+Values replace earlier values for that identity; repeated publication never 
increments a counter. At most 100
+such identities are retained, independently of assessment populations. The 
producer owns meaning and update cadence.
+The last value remains until the next publication or collector shutdown; 
scraping does not refresh it. A publication
+with an unavailable or invalid value marks an existing gauge as `NaN`, rather 
than continuing to expose its old value.
+Only published snapshots are consumed: the listener does not call 
`SemanticMetricSource.snapshots()` or perform I/O
+while an assessment completes. Unsupported kinds, units, shapes or dimensions 
increment `unsupported_measurement`;
+aggregated counts are not guessed to be deltas, and snapshot means are never 
converted to latency observations.
+
+== Prometheus queries and lifecycle
+
+Expose the supplied registry through the runtime's normal metrics endpoint. 
Prometheus scrapes that endpoint and
+owns time-series retention; it does not depend on the Camel TUI being 
connected. Select a scrape interval that fits
+your operational needs (for example 15 seconds) and use a rate window 
containing several scrapes.
+The shared listener does not provide automatic Main, Spring Boot or Quarkus 
registration, a Prometheus query client,
+historical TUI views or dashboards. Runtime-specific examples and Quarkus 
native validation are follow-up work.
+
+For a Prometheus registry, dots become underscores and counters gain `_total`. 
These example backend queries aggregate
+across instances while retaining the selected expert or definition grouping:
+
+[source,promql]
+----
+# Executed assessment rate per expert; skipped members are excluded.
+sum by (expert) 
(rate(camel_semantic_evaluations_total{status=~"success|failed"}[5m]))
+
+# Failed execution rate per expert and definition.
+sum by (expert, definition) 
(rate(camel_semantic_evaluations_total{status="failed"}[5m]))
+
+# Returned-answer distribution per expert and definition.
+sum by (expert, definition, result_type, answer) 
(rate(camel_semantic_results_total[5m]))
+
+# 95th percentile from actual duration buckets, aggregated across instances.
+histogram_quantile(0.95,
+  sum by (expert, le) (rate(camel_semantic_duration_seconds_bucket[5m])))
+
+# Available score distribution using application-declared bounds.
+sum by (expert, definition, le) 
(rate(camel_semantic_score_distribution_total[5m]))
+
+# Counter resets observed on individual application series.
+resets(camel_semantic_evaluations_total[1h])
+
+# Collection exclusions over the observation window.
+sum by (reason) (increase(camel_semantic_collection_loss_total[5m]))
+----
+
+Apply `rate` or `increase` before summing across instances so resets are 
handled per series. A restart resets these
+counters; Prometheus history remains in Prometheus. The first scrape after 
startup cannot reconstruct evaluations
+that happened before a counter's first observed sample. Backend labels such as 
`job` and `instance` distinguish
+application instances; they are supplied by the scrape configuration, not 
unique evaluation IDs.
+
+Exemplars depend on the runtime's tracing context, registry and exposition 
format. This listener neither fabricates
+trace context nor promises an exemplar for every assessment, particularly for 
detached or asynchronous completions.
+Historical investigations may query independently retained audit records for a 
matching `[since, until)` interval,
+definition/operation and typed result. Audit retention and metric observations 
can cover different populations.
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
index 350ddcf3fa5d..b4e6e04b1b80 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
@@ -53,6 +53,7 @@ resilience4j-micrometer
 resourceresolver-github
 rxjava
 sanitizer
+semantic-micrometer
 semantic-openai
 semantic-typesafe-ai
 semantic-wolf-defender
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/semantic-micrometer.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/semantic-micrometer.json
new file mode 100644
index 000000000000..fae2d80a5032
--- /dev/null
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/semantic-micrometer.json
@@ -0,0 +1,15 @@
+{
+  "other": {
+    "kind": "other",
+    "name": "semantic-micrometer",
+    "title": "Semantic Micrometer",
+    "description": "Export semantic assessments and expert measurements with 
Micrometer",
+    "deprecated": false,
+    "firstVersion": "4.24.0",
+    "label": "ai,monitoring",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-semantic-micrometer",
+    "version": "4.24.0-SNAPSHOT"
+  }
+}
diff --git a/components/camel-ai/camel-semantic/pom.xml 
b/components/camel-ai/camel-semantic-micrometer/pom.xml
similarity index 55%
copy from components/camel-ai/camel-semantic/pom.xml
copy to components/camel-ai/camel-semantic-micrometer/pom.xml
index 508b8c70d295..a8a4ade8b22b 100644
--- a/components/camel-ai/camel-semantic/pom.xml
+++ b/components/camel-ai/camel-semantic-micrometer/pom.xml
@@ -25,42 +25,23 @@
         <artifactId>camel-ai-parent</artifactId>
         <version>4.24.0-SNAPSHOT</version>
     </parent>
-    <artifactId>camel-semantic</artifactId>
-    <name>Camel :: AI :: Semantic Evaluation</name>
-    <description>Invoke named evaluations of message content to produce 
boolean decisions, categories, scores and label sets through provider 
adapters</description>
+    <artifactId>camel-semantic-micrometer</artifactId>
+    <name>Camel :: AI :: Semantic Micrometer</name>
+    <description>Export semantic assessments and expert measurements with 
Micrometer</description>
+    <properties>
+        <firstVersion>4.24.0</firstVersion>
+        <title>Semantic Micrometer</title>
+        <label>ai,monitoring</label>
+        <supportLevel>Preview</supportLevel>
+    </properties>
     <dependencies>
-        <dependency>
-            <groupId>io.micrometer</groupId>
-            <artifactId>micrometer-core</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>io.micrometer</groupId>
-            <artifactId>micrometer-registry-prometheus</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-support</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-core-languages</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-core-model</artifactId>
-            <optional>true</optional>
-        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
-            <artifactId>camel-xml-io</artifactId>
-            <optional>true</optional>
+            <artifactId>camel-semantic</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
-            <artifactId>camel-yaml-dsl-common</artifactId>
-            <optional>true</optional>
+            <artifactId>camel-micrometer</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
@@ -68,23 +49,13 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-xml-io-dsl</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-main</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-management</artifactId>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git 
a/components/camel-ai/camel-semantic-micrometer/src/generated/resources/META-INF/services/org/apache/camel/other.properties
 
b/components/camel-ai/camel-semantic-micrometer/src/generated/resources/META-INF/services/org/apache/camel/other.properties
new file mode 100644
index 000000000000..63614db73621
--- /dev/null
+++ 
b/components/camel-ai/camel-semantic-micrometer/src/generated/resources/META-INF/services/org/apache/camel/other.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+name=semantic-micrometer
+groupId=org.apache.camel
+artifactId=camel-semantic-micrometer
+version=4.24.0-SNAPSHOT
+projectName=Camel :: AI :: Semantic Micrometer
+projectDescription=Export semantic assessments and expert measurements with 
Micrometer
diff --git 
a/components/camel-ai/camel-semantic-micrometer/src/generated/resources/semantic-micrometer.json
 
b/components/camel-ai/camel-semantic-micrometer/src/generated/resources/semantic-micrometer.json
new file mode 100644
index 000000000000..fae2d80a5032
--- /dev/null
+++ 
b/components/camel-ai/camel-semantic-micrometer/src/generated/resources/semantic-micrometer.json
@@ -0,0 +1,15 @@
+{
+  "other": {
+    "kind": "other",
+    "name": "semantic-micrometer",
+    "title": "Semantic Micrometer",
+    "description": "Export semantic assessments and expert measurements with 
Micrometer",
+    "deprecated": false,
+    "firstVersion": "4.24.0",
+    "label": "ai,monitoring",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-semantic-micrometer",
+    "version": "4.24.0-SNAPSHOT"
+  }
+}
diff --git 
a/components/camel-ai/camel-semantic-micrometer/src/main/docs/semantic-micrometer.adoc
 
b/components/camel-ai/camel-semantic-micrometer/src/main/docs/semantic-micrometer.adoc
new file mode 100644
index 000000000000..c3d175dab600
--- /dev/null
+++ 
b/components/camel-ai/camel-semantic-micrometer/src/main/docs/semantic-micrometer.adoc
@@ -0,0 +1,177 @@
+= Semantic Micrometer Component
+:doctitle: Semantic Micrometer
+:shortname: semantic-micrometer
+:artifactid: camel-semantic-micrometer
+:description: Export semantic assessments and expert measurements with 
Micrometer
+:since: 4.24
+:supportlevel: Preview
+:tabs-sync-option:
+
+*Since Camel {since}*
+
+This module exports typed assessment completion events and supported expert 
measurements from the
+xref:languages:semantic-language.adoc[Semantic language] to Micrometer. Add 
one dependency to bring
+both `camel-semantic` and `camel-micrometer` transitively, using the same 
version as Camel core:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-semantic-micrometer</artifactId>
+    <version>x.x.x</version>
+</dependency>
+----
+
+`camel-semantic` itself has no Micrometer dependency. This integration has no 
routing endpoint of its own;
+adding the dependency does not automatically register a collector. Prometheus 
is not a runtime dependency
+of this module: supply the registry implementation used by your application.
+
+== Register the collector
+
+Register one listener before starting the context, passing the application's 
existing `MeterRegistry`:
+
+[source,java]
+----
+import org.apache.camel.semantic.micrometer.MicrometerSemanticMetrics;
+
+// registry is the application's existing Micrometer MeterRegistry.
+// Optional, increasing score bucket bounds may include negative values.
+context.getManagementStrategy().addEventNotifier(
+    new MicrometerSemanticMetrics(registry, -1, 0, 0.5, 1, 2, 5));
+----
+
+The listener does not create or close a registry or install an HTTP server. 
The application/runtime owns
+registry configuration, HTTP exposure, authentication and the registry 
lifecycle. Give contexts sharing a registry
+distinct names. Registering more than one listener in a context fails at 
startup to prevent double counting.
+Stop removes meters created by the listener; restarting starts new counters. 
Existing application meters remain.
+
+Each completed assessment member is counted once, including individual batch 
members. Starts, request outcomes
+and locally aggregated `typed_results` snapshots are not counted again. 
Provider attempts/retries are not inferred
+from semantic completions. Audit capture, input capture, JMX, the local 
monitoring cache and UI polling are not
+required. Collection failures are isolated from the assessment and reported by 
the collection health meters.
+The first failure since collector start also logs a warning containing only 
the exception class, without its
+message, stack trace or event payload; subsequent failures only increment the 
error count.
+
+[cols="2,3",options="header"]
+|===
+|Micrometer name |Meaning
+|`camel.semantic.evaluations` |Counter by execution `status`: `success`, 
`failed`, or `not_executed`.
+|`camel.semantic.duration` |Timer recording each available execution duration, 
including failures. Skipped or
+missing durations are not zero-duration observations. Percentile histograms 
use the original durations.
+|`camel.semantic.result.availability` |Successful assessments by 
`availability`: `available` or `unavailable`.
+|`camel.semantic.results` |Counter by returned `answer`. Boolean values are 
final answers, without another
+probability threshold. Choice counts the selected answer, not probability 
entries. Classification counts each
+selected label once per assessment, so membership percentages need not sum to 
100%.
+|`camel.semantic.classification.empty` |Successful classification results with 
no selected labels.
+|`camel.semantic.score.observations` |Count of available finite numeric score 
observations.
+|`camel.semantic.score.sum`, `.minimum`, `.maximum` |Gauges preserving signed, 
fractional scores since collector
+start. The sum can decrease; do not treat it as a monotonic counter.
+|`camel.semantic.score.distribution` |Cumulative counters with inclusive `le` 
bounds supplied to the constructor and a
+`+Inf` bucket. Bounds describe numeric values, not severity or policy 
decisions.
+|`camel.semantic.collection.loss` |Counter by fixed `reason`: 
`population_limit`, `answer_limit`, `invalid_event`,
+or `unsupported_measurement`. Loss is excluded from the corresponding result 
distribution.
+|`camel.semantic.collection.errors` |Number of metric collection failures 
since collector start.
+|===
+
+Assessment meters have `camelContext`, `expert`, `definition`, `operation`, 
`origin` and `result.type` tags.
+Missing identity is the empty string; direct calls remain distinguishable by 
origin and the absence of a definition.
+The listener retains at most 100 distinct combinations and 64 answer labels of 
at most 256 characters per combination.
+Score histograms accept at most 64 finite, strictly increasing bounds; an 
empty array keeps count, sum, minimum,
+maximum and the overflow bucket. Configure identical bounds on instances you 
aggregate together.
+Each population can have both successful and failed duration timers. Default 
percentile histograms can add about
+70 bucket series per timer: the 100-population limit alone can therefore allow 
roughly 14,000 duration bucket
+series. Configure the registry's meter filter before registering the listener 
to choose fewer boundaries, for example:
+
+[source,java]
+----
+import java.time.Duration;
+
+import io.micrometer.core.instrument.Meter;
+import io.micrometer.core.instrument.config.MeterFilter;
+import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
+
+registry.config().meterFilter(new MeterFilter() {
+    @Override
+    public DistributionStatisticConfig configure(Meter.Id id, 
DistributionStatisticConfig config) {
+        if (id.getName().equals("camel.semantic.duration")) {
+            return 
DistributionStatisticConfig.builder().percentilesHistogram(false)
+                .serviceLevelObjectives(Duration.ofMillis(10).toNanos(), 
Duration.ofMillis(100).toNanos(),
+                    Duration.ofSeconds(1).toNanos(), 
Duration.ofSeconds(10).toNanos())
+                .build().merge(config);
+        }
+        return config;
+    }
+});
+----
+
+This example exports five duration buckets per timer in Prometheus, including 
`+Inf`, while retaining every
+observation in the count and sum. Choose boundaries for your latency goals: 
fewer buckets reduce percentile
+resolution. The `camelContext` tag matches Camel's other Micrometer metrics.
+
+Prompts, input, interpretation, exception messages and per-execution 
identifiers are never metric labels.
+Choose stable expert/definition names and result labels. Bounds limit retained 
series, but collection loss still
+means that a distribution may cover only part of the evaluated population. 
Collection error counts do not prove
+that every event was delivered: the shared AI notification contract remains 
synchronous and best effort.
+
+== Expert-published scalar gauges
+
+The same listener accepts `SemanticMonitoringEvent` snapshots with 
`kind=gauge`, a single finite numeric
+`values.value`, and an explicit unit of `1`, `ratio`, `bytes`, `seconds`, 
`milliseconds`, `nanoseconds`, `count`,
+`requests` or `assessments`. If supplied, `availability` must be `available`. 
It exports
+`camel.semantic.expert.value` with `source`, `measurement` (the snapshot ID), 
`unit` and the supplied
+`expert`, `definition`, `operation`, `provider`, `taskId`, `taskVersion`, 
`revision` dimensions. Missing dimensions
+are empty strings. Other dimension keys are rejected, including correlation 
and message identifiers.
+
+Values replace earlier values for that identity; repeated publication never 
increments a counter. At most 100
+such identities are retained, independently of assessment populations. The 
producer owns meaning and update cadence.
+The last value remains until the next publication or collector shutdown; 
scraping does not refresh it. A publication
+with an unavailable or invalid value marks an existing gauge as `NaN`, rather 
than continuing to expose its old value.
+Only published snapshots are consumed: the listener does not call 
`SemanticMetricSource.snapshots()` or perform I/O
+while an assessment completes. Unsupported kinds, units, shapes or dimensions 
increment `unsupported_measurement`;
+aggregated counts are not guessed to be deltas, and snapshot means are never 
converted to latency observations.
+
+== Prometheus queries and lifecycle
+
+Expose the supplied registry through the runtime's normal metrics endpoint. 
Prometheus scrapes that endpoint and
+owns time-series retention; it does not depend on the Camel TUI being 
connected. Select a scrape interval that fits
+your operational needs (for example 15 seconds) and use a rate window 
containing several scrapes.
+The shared listener does not provide automatic Main, Spring Boot or Quarkus 
registration, a Prometheus query client,
+historical TUI views or dashboards. Runtime-specific examples and Quarkus 
native validation are follow-up work.
+
+For a Prometheus registry, dots become underscores and counters gain `_total`. 
These example backend queries aggregate
+across instances while retaining the selected expert or definition grouping:
+
+[source,promql]
+----
+# Executed assessment rate per expert; skipped members are excluded.
+sum by (expert) 
(rate(camel_semantic_evaluations_total{status=~"success|failed"}[5m]))
+
+# Failed execution rate per expert and definition.
+sum by (expert, definition) 
(rate(camel_semantic_evaluations_total{status="failed"}[5m]))
+
+# Returned-answer distribution per expert and definition.
+sum by (expert, definition, result_type, answer) 
(rate(camel_semantic_results_total[5m]))
+
+# 95th percentile from actual duration buckets, aggregated across instances.
+histogram_quantile(0.95,
+  sum by (expert, le) (rate(camel_semantic_duration_seconds_bucket[5m])))
+
+# Available score distribution using application-declared bounds.
+sum by (expert, definition, le) 
(rate(camel_semantic_score_distribution_total[5m]))
+
+# Counter resets observed on individual application series.
+resets(camel_semantic_evaluations_total[1h])
+
+# Collection exclusions over the observation window.
+sum by (reason) (increase(camel_semantic_collection_loss_total[5m]))
+----
+
+Apply `rate` or `increase` before summing across instances so resets are 
handled per series. A restart resets these
+counters; Prometheus history remains in Prometheus. The first scrape after 
startup cannot reconstruct evaluations
+that happened before a counter's first observed sample. Backend labels such as 
`job` and `instance` distinguish
+application instances; they are supplied by the scrape configuration, not 
unique evaluation IDs.
+
+Exemplars depend on the runtime's tracing context, registry and exposition 
format. This listener neither fabricates
+trace context nor promises an exemplar for every assessment, particularly for 
detached or asynchronous completions.
+Historical investigations may query independently retained audit records for a 
matching `[since, until)` interval,
+definition/operation and typed result. Audit retention and metric observations 
can cover different populations.
diff --git 
a/components/camel-ai/camel-semantic/src/main/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetrics.java
 
b/components/camel-ai/camel-semantic-micrometer/src/main/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetrics.java
similarity index 99%
rename from 
components/camel-ai/camel-semantic/src/main/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetrics.java
rename to 
components/camel-ai/camel-semantic-micrometer/src/main/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetrics.java
index 988d99282729..589e1e8bf3ac 100644
--- 
a/components/camel-ai/camel-semantic/src/main/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetrics.java
+++ 
b/components/camel-ai/camel-semantic-micrometer/src/main/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetrics.java
@@ -40,6 +40,8 @@ import org.apache.camel.support.EventNotifierSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static 
org.apache.camel.component.micrometer.MicrometerConstants.CAMEL_CONTEXT_TAG;
+
 /**
  * Optional Micrometer instrumentation of completed semantic assessment 
members. Register one notifier with the Camel
  * management strategy, supplying the application's registry. The registry 
remains application-owned; this notifier
@@ -49,7 +51,6 @@ import org.slf4j.LoggerFactory;
  */
 public final class MicrometerSemanticMetrics extends EventNotifierSupport {
     private static final Logger LOG = 
LoggerFactory.getLogger(MicrometerSemanticMetrics.class);
-    private static final String CAMEL_CONTEXT_TAG = "camelContext";
     private static final int MAX_POPULATIONS = 100;
     private static final int MAX_ANSWERS = 64;
     private static final Set<String> STATUSES = Set.of("success", "failed", 
"not_executed");
diff --git 
a/components/camel-ai/camel-semantic/src/test/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetricsTest.java
 
b/components/camel-ai/camel-semantic-micrometer/src/test/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetricsTest.java
similarity index 90%
rename from 
components/camel-ai/camel-semantic/src/test/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetricsTest.java
rename to 
components/camel-ai/camel-semantic-micrometer/src/test/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetricsTest.java
index a1d1a3a8cb09..7abf5f1e0adc 100644
--- 
a/components/camel-ai/camel-semantic/src/test/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetricsTest.java
+++ 
b/components/camel-ai/camel-semantic-micrometer/src/test/java/org/apache/camel/semantic/micrometer/MicrometerSemanticMetricsTest.java
@@ -16,9 +16,6 @@
  */
 package org.apache.camel.semantic.micrometer;
 
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -60,35 +57,12 @@ import org.apache.logging.log4j.core.Logger;
 import org.apache.logging.log4j.core.appender.AbstractAppender;
 import org.apache.logging.log4j.core.config.Property;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.Assertions.within;
 
 class MicrometerSemanticMetricsTest {
-    @Test
-    void 
semanticEvaluationDoesNotRequireMicrometerOnTheApplicationClasspath(@TempDir 
Path temporary) throws Exception {
-        List<String> classpath = new ArrayList<>();
-        for (String entry : System.getProperty("surefire.test.class.path", 
System.getProperty("java.class.path"))
-                .split(File.pathSeparator)) {
-            if 
(!Path.of(entry).getFileName().toString().startsWith("micrometer-")) {
-                classpath.add(entry);
-            }
-        }
-        Path output = temporary.resolve("without-micrometer.log");
-        var process = new ProcessBuilder(
-                Path.of(System.getProperty("java.home"), "bin", 
"java").toString(),
-                "-cp", String.join(File.pathSeparator, classpath), 
WithoutMicrometer.class.getName())
-                
.redirectErrorStream(true).redirectOutput(output.toFile()).start();
-        try {
-            assertThat(process.waitFor(30, TimeUnit.SECONDS)).as("isolated 
semantic evaluation completed").isTrue();
-            
assertThat(process.exitValue()).as(Files.readString(output)).isZero();
-        } finally {
-            process.destroyForcibly();
-        }
-    }
-
     @Test
     void rejectsInvalidHistogramConfiguration() {
         var registry = new SimpleMeterRegistry();
@@ -426,27 +400,4 @@ class MicrometerSemanticMetricsTest {
         }
     }
 
-    public static class WithoutMicrometer {
-        public static void main(String[] args) throws Exception {
-            try {
-                Class.forName("io.micrometer.core.instrument.MeterRegistry");
-                throw new IllegalStateException("Micrometer unexpectedly 
present");
-            } catch (ClassNotFoundException expected) {
-                // This process deliberately omits every Micrometer artifact.
-            }
-            try (var context = new DefaultCamelContext()) {
-                context.disableJMX();
-                context.getRegistry().bind("expert", new BooleanExpert());
-                context.start();
-                var language = (SemanticLanguage) 
context.resolveLanguage("semantic");
-                Object result = language.evaluate(new 
SemanticEvaluation("containsText", "expert", null, Map.of()), "hello")
-                        .getValue();
-                if (!Boolean.TRUE.equals(result)) {
-                    throw new IllegalStateException("Semantic evaluation 
failed without Micrometer");
-                }
-            } catch (Exception failure) {
-                throw new IllegalStateException(failure);
-            }
-        }
-    }
 }
diff --git a/components/camel-ai/camel-semantic/pom.xml 
b/components/camel-ai/camel-semantic/pom.xml
index 508b8c70d295..b3571086b700 100644
--- a/components/camel-ai/camel-semantic/pom.xml
+++ b/components/camel-ai/camel-semantic/pom.xml
@@ -29,16 +29,6 @@
     <name>Camel :: AI :: Semantic Evaluation</name>
     <description>Invoke named evaluations of message content to produce 
boolean decisions, categories, scores and label sets through provider 
adapters</description>
     <dependencies>
-        <dependency>
-            <groupId>io.micrometer</groupId>
-            <artifactId>micrometer-core</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>io.micrometer</groupId>
-            <artifactId>micrometer-registry-prometheus</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-support</artifactId>
diff --git 
a/components/camel-ai/camel-semantic/src/main/docs/semantic-language.adoc 
b/components/camel-ai/camel-semantic/src/main/docs/semantic-language.adoc
index 445e1ccc4955..5175ac896296 100644
--- a/components/camel-ai/camel-semantic/src/main/docs/semantic-language.adoc
+++ b/components/camel-ai/camel-semantic/src/main/docs/semantic-language.adoc
@@ -1507,7 +1507,7 @@ camel semantic monitoring my-app 
--source=departmentMetrics
 The Semantic *Monitoring* sibling, `tui_get_monitoring`, `semantic-monitoring` 
console and CLI read this same
 current-value cache. The TUI offers expert/definition grouping, filters and an 
inspector for counts, durations,
 distributions, meaning, observation times and collection health. It has no 
historical-period, reference or
-comparison controls. Pausing affects the display only. The optional Micrometer 
listener below exports
+comparison controls. Pausing affects the display only. The optional Micrometer 
integration exports
 measurements independently of this viewer. Runtime-specific automatic 
registration and scrape endpoint
 integration are separate from the shared listener.
 
@@ -1520,155 +1520,8 @@ Facades are removed at context shutdown. Monitoring 
also works with JMX disabled
 
 === Optional Micrometer instrumentation
 
-`MicrometerSemanticMetrics` consumes typed assessment completion events 
directly. Add `io.micrometer:micrometer-core`
-to your application, or use the registry dependency supplied by your runtime. 
Micrometer is an optional dependency
-of `camel-semantic`; applications that do not register this listener do not 
need it. Prometheus is not a runtime
-dependency of the listener.
-
-Register one listener before starting the context, passing the application's 
existing `MeterRegistry`:
-
-[source,java]
-----
-import org.apache.camel.semantic.micrometer.MicrometerSemanticMetrics;
-
-// registry is the application's existing Micrometer MeterRegistry.
-// Optional, increasing score bucket bounds may include negative values.
-context.getManagementStrategy().addEventNotifier(
-    new MicrometerSemanticMetrics(registry, -1, 0, 0.5, 1, 2, 5));
-----
-
-The listener does not create or close a registry or install an HTTP server. 
The application/runtime owns
-registry configuration, HTTP exposure, authentication and the registry 
lifecycle. Give contexts sharing a registry
-distinct names. Registering more than one listener in a context fails at 
startup to prevent double counting.
-Stop removes meters created by the listener; restarting starts new counters. 
Existing application meters remain.
-
-Each completed assessment member is counted once, including individual batch 
members. Starts, request outcomes
-and locally aggregated `typed_results` snapshots are not counted again. 
Provider attempts/retries are not inferred
-from semantic completions. Audit capture, input capture, JMX, the local 
monitoring cache and UI polling are not
-required. Collection failures are isolated from the assessment and reported by 
the collection health meters.
-The first failure since collector start also logs a warning containing only 
the exception class, without its
-message, stack trace or event payload; subsequent failures only increment the 
error count.
-
-[cols="2,3",options="header"]
-|===
-|Micrometer name |Meaning
-|`camel.semantic.evaluations` |Counter by execution `status`: `success`, 
`failed`, or `not_executed`.
-|`camel.semantic.duration` |Timer recording each available execution duration, 
including failures. Skipped or
-missing durations are not zero-duration observations. Percentile histograms 
use the original durations.
-|`camel.semantic.result.availability` |Successful assessments by 
`availability`: `available` or `unavailable`.
-|`camel.semantic.results` |Counter by returned `answer`. Boolean values are 
final answers, without another
-probability threshold. Choice counts the selected answer, not probability 
entries. Classification counts each
-selected label once per assessment, so membership percentages need not sum to 
100%.
-|`camel.semantic.classification.empty` |Successful classification results with 
no selected labels.
-|`camel.semantic.score.observations` |Count of available finite numeric score 
observations.
-|`camel.semantic.score.sum`, `.minimum`, `.maximum` |Gauges preserving signed, 
fractional scores since collector
-start. The sum can decrease; do not treat it as a monotonic counter.
-|`camel.semantic.score.distribution` |Cumulative counters with inclusive `le` 
bounds supplied to the constructor and a
-`+Inf` bucket. Bounds describe numeric values, not severity or policy 
decisions.
-|`camel.semantic.collection.loss` |Counter by fixed `reason`: 
`population_limit`, `answer_limit`, `invalid_event`,
-or `unsupported_measurement`. Loss is excluded from the corresponding result 
distribution.
-|`camel.semantic.collection.errors` |Number of metric collection failures 
since collector start.
-|===
-
-Assessment meters have `camelContext`, `expert`, `definition`, `operation`, 
`origin` and `result.type` tags.
-Missing identity is the empty string; direct calls remain distinguishable by 
origin and the absence of a definition.
-The listener retains at most 100 distinct combinations and 64 answer labels of 
at most 256 characters per combination.
-Score histograms accept at most 64 finite, strictly increasing bounds; an 
empty array keeps count, sum, minimum,
-maximum and the overflow bucket. Configure identical bounds on instances you 
aggregate together.
-Each population can have both successful and failed duration timers. Default 
percentile histograms can add about
-70 bucket series per timer: the 100-population limit alone can therefore allow 
roughly 14,000 duration bucket
-series. Configure the registry's meter filter before registering the listener 
to choose fewer boundaries, for example:
-
-[source,java]
-----
-import java.time.Duration;
-
-import io.micrometer.core.instrument.Meter;
-import io.micrometer.core.instrument.config.MeterFilter;
-import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
-
-registry.config().meterFilter(new MeterFilter() {
-    @Override
-    public DistributionStatisticConfig configure(Meter.Id id, 
DistributionStatisticConfig config) {
-        if (id.getName().equals("camel.semantic.duration")) {
-            return 
DistributionStatisticConfig.builder().percentilesHistogram(false)
-                .serviceLevelObjectives(Duration.ofMillis(10).toNanos(), 
Duration.ofMillis(100).toNanos(),
-                    Duration.ofSeconds(1).toNanos(), 
Duration.ofSeconds(10).toNanos())
-                .build().merge(config);
-        }
-        return config;
-    }
-});
-----
-
-This example exports five duration buckets per timer in Prometheus, including 
`+Inf`, while retaining every
-observation in the count and sum. Choose boundaries for your latency goals: 
fewer buckets reduce percentile
-resolution. The `camelContext` tag matches Camel's other Micrometer metrics.
-
-Prompts, input, interpretation, exception messages and per-execution 
identifiers are never metric labels.
-Choose stable expert/definition names and result labels. Bounds limit retained 
series, but collection loss still
-means that a distribution may cover only part of the evaluated population. 
Collection error counts do not prove
-that every event was delivered: the shared AI notification contract remains 
synchronous and best effort.
-
-==== Expert-published scalar gauges
-
-The same listener accepts `SemanticMonitoringEvent` snapshots with 
`kind=gauge`, a single finite numeric
-`values.value`, and an explicit unit of `1`, `ratio`, `bytes`, `seconds`, 
`milliseconds`, `nanoseconds`, `count`,
-`requests` or `assessments`. If supplied, `availability` must be `available`. 
It exports
-`camel.semantic.expert.value` with `source`, `measurement` (the snapshot ID), 
`unit` and the supplied
-`expert`, `definition`, `operation`, `provider`, `taskId`, `taskVersion`, 
`revision` dimensions. Missing dimensions
-are empty strings. Other dimension keys are rejected, including correlation 
and message identifiers.
-
-Values replace earlier values for that identity; repeated publication never 
increments a counter. At most 100
-such identities are retained, independently of assessment populations. The 
producer owns meaning and update cadence.
-The last value remains until the next publication or collector shutdown; 
scraping does not refresh it. A publication
-with an unavailable or invalid value marks an existing gauge as `NaN`, rather 
than continuing to expose its old value.
-Only published snapshots are consumed: the listener does not call 
`SemanticMetricSource.snapshots()` or perform I/O
-while an assessment completes. Unsupported kinds, units, shapes or dimensions 
increment `unsupported_measurement`;
-aggregated counts are not guessed to be deltas, and snapshot means are never 
converted to latency observations.
-
-==== Prometheus queries and lifecycle
-
-Expose the supplied registry through the runtime's normal metrics endpoint. 
Prometheus scrapes that endpoint and
-owns time-series retention; it does not depend on the Camel TUI being 
connected. Select a scrape interval that fits
-your operational needs (for example 15 seconds) and use a rate window 
containing several scrapes.
-The shared listener does not provide automatic Main, Spring Boot or Quarkus 
registration, a Prometheus query client,
-historical TUI views or dashboards. Runtime-specific examples and Quarkus 
native validation are follow-up work.
-
-For a Prometheus registry, dots become underscores and counters gain `_total`. 
These example backend queries aggregate
-across instances while retaining the selected expert or definition grouping:
-
-[source,promql]
-----
-# Executed assessment rate per expert; skipped members are excluded.
-sum by (expert) 
(rate(camel_semantic_evaluations_total{status=~"success|failed"}[5m]))
-
-# Failed execution rate per expert and definition.
-sum by (expert, definition) 
(rate(camel_semantic_evaluations_total{status="failed"}[5m]))
-
-# Returned-answer distribution per expert and definition.
-sum by (expert, definition, result_type, answer) 
(rate(camel_semantic_results_total[5m]))
-
-# 95th percentile from actual duration buckets, aggregated across instances.
-histogram_quantile(0.95,
-  sum by (expert, le) (rate(camel_semantic_duration_seconds_bucket[5m])))
-
-# Available score distribution using application-declared bounds.
-sum by (expert, definition, le) 
(rate(camel_semantic_score_distribution_total[5m]))
-
-# Counter resets observed on individual application series.
-resets(camel_semantic_evaluations_total[1h])
-
-# Collection exclusions over the observation window.
-sum by (reason) (increase(camel_semantic_collection_loss_total[5m]))
-----
-
-Apply `rate` or `increase` before summing across instances so resets are 
handled per series. A restart resets these
-counters; Prometheus history remains in Prometheus. The first scrape after 
startup cannot reconstruct evaluations
-that happened before a counter's first observed sample. Backend labels such as 
`job` and `instance` distinguish
-application instances; they are supplied by the scrape configuration, not 
unique evaluation IDs.
-
-Exemplars depend on the runtime's tracing context, registry and exposition 
format. This listener neither fabricates
-trace context nor promises an exemplar for every assessment, particularly for 
detached or asynchronous completions.
-Historical investigations may query independently retained audit records for a 
matching `[since, until)` interval,
-definition/operation and typed result. Audit retention and metric observations 
can cover different populations.
+Add xref:others:semantic-micrometer.adoc[Semantic Micrometer] 
(`camel-semantic-micrometer`) to export
+assessment counts, durations, typed result distributions and supported expert 
measurements to the
+application's Micrometer registry. The integration brings `camel-semantic` and 
`camel-micrometer`
+transitively and documents registration, metric names, cardinality limits, 
lifecycle and PromQL queries.
+`camel-semantic` itself has no Micrometer dependency.
diff --git 
a/components/camel-ai/camel-semantic/src/test/java/org/apache/camel/semantic/SemanticWithoutMicrometerTest.java
 
b/components/camel-ai/camel-semantic/src/test/java/org/apache/camel/semantic/SemanticWithoutMicrometerTest.java
new file mode 100644
index 000000000000..084d749b1ddb
--- /dev/null
+++ 
b/components/camel-ai/camel-semantic/src/test/java/org/apache/camel/semantic/SemanticWithoutMicrometerTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+package org.apache.camel.semantic;
+
+import java.util.Map;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.language.semantic.SemanticLanguage;
+import org.apache.camel.semantic.SemanticExpert.InputType;
+import org.apache.camel.semantic.SemanticExpert.ResultType;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class SemanticWithoutMicrometerTest {
+    @Test
+    void evaluationWorksWithoutMicrometerOnTheModuleClasspath() throws 
Exception {
+        assertThatThrownBy(() -> 
Class.forName("io.micrometer.core.instrument.MeterRegistry"))
+                .isInstanceOf(ClassNotFoundException.class);
+        try (var context = new DefaultCamelContext()) {
+            context.disableJMX();
+            context.getRegistry().bind("expert", new BooleanExpert());
+            context.start();
+            var language = (SemanticLanguage) 
context.resolveLanguage("semantic");
+            assertThat(language.evaluate(new 
SemanticEvaluation("containsText", "expert", null, Map.of()), "hello")
+                    .getValue()).isEqualTo(true);
+        }
+    }
+
+    @SemanticExpert(name = "text", description = "Checks for nonempty text", 
provider = "local", artifactId = "test",
+                    operations = @SemanticOperation(name = "containsText", 
description = "Has text",
+                                                    inputTypes = 
InputType.TEXT, inputRequirements = "Text",
+                                                    resultType = 
ResultType.BOOLEAN, resultMeaning = "Contains text"))
+    static class BooleanExpert implements SemanticAdapter {
+        @Override
+        public void validate(SemanticEvaluation evaluation) {
+            SemanticCapabilities.from(getClass()).validate(evaluation);
+        }
+
+        @Override
+        public SemanticResult evaluate(SemanticEvaluation evaluation, Object 
state) {
+            return new SemanticResult(!state.toString().isBlank(), null, 
Map.of(), null, Map.of());
+        }
+    }
+}
diff --git a/components/camel-ai/pom.xml b/components/camel-ai/pom.xml
index 95c7db233415..51cd19a87d3c 100644
--- a/components/camel-ai/pom.xml
+++ b/components/camel-ai/pom.xml
@@ -45,6 +45,7 @@
         <module>camel-docling</module>
         <module>camel-huggingface</module>
         <module>camel-semantic</module>
+        <module>camel-semantic-micrometer</module>
         <module>camel-semantic-openai</module>
         <module>camel-semantic-typesafe-ai</module>
         <module>camel-typesafe-ai</module>
diff --git a/design/semantic-audit.adoc b/design/semantic-audit.adoc
index ee569eac24f0..e4c1de0ccb80 100644
--- a/design/semantic-audit.adoc
+++ b/design/semantic-audit.adoc
@@ -133,6 +133,8 @@ There are no historical-period or baseline controls. 
Register a bounded number o
 facades per source, never one MBean per event or answer. JMX-disabled 
deployments retain the console.
 
 CAMEL-25648 adds a shared Micrometer instrumentation/export bridge for Camel 
Main, Spring Boot and Quarkus.
+The bridge lives in `camel-semantic-micrometer`, which depends on 
`camel-semantic` and `camel-micrometer`;
+the semantic runtime publishes its events without depending on Micrometer.
 It reuses the runtime registry; Prometheus or another registry backend owns 
monitoring history and queries.
 Correlation, exchange, breadcrumb and invocation IDs are not metric labels. 
They remain audit/log/trace
 context; standard tracing exemplars may supply sampled metric-to-trace 
references where supported. Audit
diff --git 
a/docs/components/modules/others/examples/json/semantic-micrometer.json 
b/docs/components/modules/others/examples/json/semantic-micrometer.json
new file mode 120000
index 000000000000..50be138d1453
--- /dev/null
+++ b/docs/components/modules/others/examples/json/semantic-micrometer.json
@@ -0,0 +1 @@
+../../../../../../components/camel-ai/camel-semantic-micrometer/src/generated/resources/semantic-micrometer.json
\ No newline at end of file
diff --git a/docs/components/modules/others/nav.adoc 
b/docs/components/modules/others/nav.adoc
index 144269846820..eb122b25a6ba 100644
--- a/docs/components/modules/others/nav.adoc
+++ b/docs/components/modules/others/nav.adoc
@@ -89,6 +89,7 @@
 ** xref:salesforce-rest-api.adoc[Salesforce - REST API]
 ** xref:salesforce-streaming.adoc[Salesforce - Streaming and Pub/Sub]
 ** xref:sanitizer.adoc[Sanitizer]
+** xref:semantic-micrometer.adoc[Semantic Micrometer]
 ** xref:semantic-openai.adoc[Semantic OpenAI]
 ** xref:semantic-typesafe-ai.adoc[Semantic TypeSafe AI]
 ** xref:semantic-wolf-defender.adoc[Semantic Wolf Defender]
diff --git a/docs/components/modules/others/pages/semantic-micrometer.adoc 
b/docs/components/modules/others/pages/semantic-micrometer.adoc
new file mode 120000
index 000000000000..465c487ff8b7
--- /dev/null
+++ b/docs/components/modules/others/pages/semantic-micrometer.adoc
@@ -0,0 +1 @@
+../../../../../components/camel-ai/camel-semantic-micrometer/src/main/docs/semantic-micrometer.adoc
\ No newline at end of file
diff --git a/parent/pom.xml b/parent/pom.xml
index a421f5d81cd4..98225275501e 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -2744,6 +2744,11 @@
                 <artifactId>camel-semantic</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-semantic-micrometer</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
                 <artifactId>camel-semantic-openai</artifactId>
diff --git 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
index 552f6cc72686..3ac9fd2a27b4 100644
--- 
a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
+++ 
b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/MojoHelper.java
@@ -42,7 +42,8 @@ public final class MojoHelper {
                         dir.resolve("camel-ai-prompt"), 
dir.resolve("camel-ai-resource"), dir.resolve("camel-ai-tool"),
                         dir.resolve("camel-chatscript"), 
dir.resolve("camel-djl"),
                         dir.resolve("camel-huggingface"),
-                        dir.resolve("camel-semantic"), 
dir.resolve("camel-semantic-openai"),
+                        dir.resolve("camel-semantic"), 
dir.resolve("camel-semantic-micrometer"),
+                        dir.resolve("camel-semantic-openai"),
                         dir.resolve("camel-semantic-typesafe-ai"), 
dir.resolve("camel-semantic-wolf-defender"),
                         dir.resolve("camel-typesafe-ai"),
                         dir.resolve("camel-langchain4j-agent"), 
dir.resolve("camel-langchain4j-chat"),

Reply via email to