diff --git a/src/Persistence/Wolverine.CosmosDb/Internals/Durability/CosmosDbDurabilityAgent.cs b/src/Persistence/Wolverine.CosmosDb/Internals/Durability/CosmosDbDurabilityAgent.cs
index 98baf628b..9a4254f31 100644
--- a/src/Persistence/Wolverine.CosmosDb/Internals/Durability/CosmosDbDurabilityAgent.cs
+++ b/src/Persistence/Wolverine.CosmosDb/Internals/Durability/CosmosDbDurabilityAgent.cs
@@ -157,6 +157,12 @@ public Task StopAsync(CancellationToken cancellationToken)
public Uri Uri { get; set; }
public AgentStatus Status { get; set; }
+ ///
+ /// Human-readable description for monitoring tools — see
+ /// .
+ ///
+ public string Description => $"Wolverine Cosmos DB durability agent for {Uri} — recovers persisted inbox/outbox messages and runs scheduled jobs against the Cosmos DB message store.";
+
///
/// True once has wired up the recovery and scheduled-job
/// background loops. Exposed for diagnostic and test inspection so callers can detect
diff --git a/src/Persistence/Wolverine.Postgresql/Transport/StickyPostgresqlQueueListenerAgent.cs b/src/Persistence/Wolverine.Postgresql/Transport/StickyPostgresqlQueueListenerAgent.cs
index 1e7c34c97..456f916e6 100644
--- a/src/Persistence/Wolverine.Postgresql/Transport/StickyPostgresqlQueueListenerAgent.cs
+++ b/src/Persistence/Wolverine.Postgresql/Transport/StickyPostgresqlQueueListenerAgent.cs
@@ -52,4 +52,10 @@ public async Task StopAsync(CancellationToken cancellationToken)
}
public Uri Uri { get; }
+
+ ///
+ /// Human-readable description for monitoring tools — see
+ /// .
+ ///
+ public string Description => $"Sticky Postgres queue listener — pinned to the per-tenant database '{_databaseName}' for queue '{_queue}'. Only one node listens to each tenant database to avoid duplicate consumption.";
}
\ No newline at end of file
diff --git a/src/Persistence/Wolverine.RDBMS/DurabilityAgent.cs b/src/Persistence/Wolverine.RDBMS/DurabilityAgent.cs
index ab59253b4..df28f7148 100644
--- a/src/Persistence/Wolverine.RDBMS/DurabilityAgent.cs
+++ b/src/Persistence/Wolverine.RDBMS/DurabilityAgent.cs
@@ -149,6 +149,16 @@ public async Task StopAsync(CancellationToken cancellationToken)
public Uri Uri { get; internal set; }
+ ///
+ /// Human-readable description for monitoring tools — see
+ /// . This agent recovers
+ /// persisted inbox / outbox messages from the relational
+ /// message store, runs scheduled jobs, and emits persistence
+ /// metrics. The URI carries the store identity so operators
+ /// can disambiguate when a service has multiple stores.
+ ///
+ public string Description => $"Wolverine durability agent for {Uri} — recovers persisted inbox/outbox messages, runs scheduled jobs, and emits persistence metrics.";
+
public static Uri SimplifyUri(Uri uri)
{
return new Uri($"{PersistenceConstants.AgentScheme}://{uri.Host}");
diff --git a/src/Persistence/Wolverine.RavenDb/Internals/Durability/RavenDbDurabilityAgent.cs b/src/Persistence/Wolverine.RavenDb/Internals/Durability/RavenDbDurabilityAgent.cs
index 164b43fb7..76facd12e 100644
--- a/src/Persistence/Wolverine.RavenDb/Internals/Durability/RavenDbDurabilityAgent.cs
+++ b/src/Persistence/Wolverine.RavenDb/Internals/Durability/RavenDbDurabilityAgent.cs
@@ -139,6 +139,12 @@ public Task StopAsync(CancellationToken cancellationToken)
public Uri Uri { get; set; }
public AgentStatus Status { get; set; }
+ ///
+ /// Human-readable description for monitoring tools — see
+ /// .
+ ///
+ public string Description => $"Wolverine RavenDB durability agent for {Uri} — recovers persisted inbox/outbox messages and runs scheduled jobs against the RavenDB message store.";
+
///
/// True once has wired up the recovery and scheduled-job
/// background loops. Exposed for diagnostic and test inspection so callers can detect
diff --git a/src/Testing/CoreTests/Runtime/Agents/IAgentDescriptionTests.cs b/src/Testing/CoreTests/Runtime/Agents/IAgentDescriptionTests.cs
new file mode 100644
index 000000000..216383da6
--- /dev/null
+++ b/src/Testing/CoreTests/Runtime/Agents/IAgentDescriptionTests.cs
@@ -0,0 +1,87 @@
+using JasperFx;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Shouldly;
+using Wolverine.Runtime.Agents;
+using Xunit;
+
+namespace CoreTests.Runtime.Agents;
+
+///
+/// Coverage for — the human-readable
+/// "what does this agent do" string surfaced to monitoring tools
+/// (e.g. CritterWatch). Verifies the default-interface fallback for
+/// implementations that don't override it, and verifies an explicit
+/// override wins through.
+///
+public class IAgentDescriptionTests
+{
+ [Fact]
+ public void default_description_includes_uri_scheme_and_full_uri()
+ {
+ // Default-interface members are only accessible through the
+ // interface, not the concrete type — so cast deliberately.
+ // The default implementation derives a generic description
+ // from the URI; implementations are expected to override for
+ // anything more specific, but the fallback should always
+ // produce a non-empty string identifying scheme and URI so a
+ // monitoring tool isn't left with a blank tooltip.
+ IAgent agent = new BareBonesAgent(new Uri("test-agent://default"));
+
+ agent.Description.ShouldNotBeNullOrWhiteSpace();
+ agent.Description.ShouldContain("test-agent");
+ agent.Description.ShouldContain(agent.Uri.ToString());
+ }
+
+ [Fact]
+ public void overridden_description_wins_over_default()
+ {
+ IAgent agent = new DescribedAgent(
+ new Uri("test-agent://configured"),
+ "Custom description for this agent");
+
+ agent.Description.ShouldBe("Custom description for this agent");
+ agent.Description.ShouldNotContain("test-agent://configured");
+ }
+
+ ///
+ /// Minimal IAgent that doesn't override Description. The default
+ /// interface member should provide the fallback — covers the
+ /// "existing IAgent implementations stay source-compatible"
+ /// guarantee.
+ ///
+ private sealed class BareBonesAgent : IAgent
+ {
+ public BareBonesAgent(Uri uri)
+ {
+ Uri = uri;
+ }
+
+ public Uri Uri { get; }
+ public AgentStatus Status => AgentStatus.Stopped;
+ public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ }
+
+ ///
+ /// Agent that explicitly overrides the description — exercises
+ /// the implementation-side override path that built-in agents
+ /// (DurabilityAgent, ExclusiveListenerAgent, etc.) use to give
+ /// CritterWatch operators agent-specific tooltip text.
+ ///
+ private sealed class DescribedAgent : IAgent
+ {
+ private readonly string _description;
+
+ public DescribedAgent(Uri uri, string description)
+ {
+ Uri = uri;
+ _description = description;
+ }
+
+ public Uri Uri { get; }
+ public AgentStatus Status => AgentStatus.Stopped;
+ public string Description => _description;
+ public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ }
+}
diff --git a/src/Wolverine/Runtime/Agents/ExclusiveListenerFamily.cs b/src/Wolverine/Runtime/Agents/ExclusiveListenerFamily.cs
index 509e7e8e2..22180377d 100644
--- a/src/Wolverine/Runtime/Agents/ExclusiveListenerFamily.cs
+++ b/src/Wolverine/Runtime/Agents/ExclusiveListenerFamily.cs
@@ -34,6 +34,12 @@ public async Task StopAsync(CancellationToken cancellationToken)
public AgentStatus Status { get; set; } = AgentStatus.Running;
+ ///
+ /// Human-readable description for monitoring tools — see
+ /// .
+ ///
+ public string Description => $"Exclusive listener for {_endpoint.Uri} — only one node at a time holds the listening role for this endpoint, so the cluster avoids competing consumers.";
+
public Task CheckHealthAsync(HealthCheckContext context,
CancellationToken cancellationToken = default)
{
diff --git a/src/Wolverine/Runtime/Agents/IAgent.cs b/src/Wolverine/Runtime/Agents/IAgent.cs
index 118837331..a769ef536 100644
--- a/src/Wolverine/Runtime/Agents/IAgent.cs
+++ b/src/Wolverine/Runtime/Agents/IAgent.cs
@@ -23,6 +23,18 @@ public interface IAgent : IHostedService, IHealthCheck
///
AgentStatus Status { get; }
+ ///
+ /// Human-readable description of what this agent does on a given
+ /// node. Surfaced in monitoring tools (e.g. CritterWatch) so
+ /// operators don't have to recognise an agent purely by its URI
+ /// scheme. The default implementation returns a generic
+ /// "{scheme} agent: {Uri}" string; override in concrete agent
+ /// types to provide more specific text. Kept as a default
+ /// interface member so existing
+ /// implementations stay source-compatible.
+ ///
+ string Description => $"{Uri.Scheme} agent: {Uri}";
+
///
/// Default health check implementation based on agent status.
/// Override in implementations for more specific health reporting.
diff --git a/src/Wolverine/Runtime/Agents/LeaderPinnedAgentFamily.cs b/src/Wolverine/Runtime/Agents/LeaderPinnedAgentFamily.cs
index da16d7791..c2c0bcb49 100644
--- a/src/Wolverine/Runtime/Agents/LeaderPinnedAgentFamily.cs
+++ b/src/Wolverine/Runtime/Agents/LeaderPinnedAgentFamily.cs
@@ -34,6 +34,12 @@ public async Task StopAsync(CancellationToken cancellationToken)
public AgentStatus Status { get; set; } = AgentStatus.Running;
+ ///
+ /// Human-readable description for monitoring tools — see
+ /// .
+ ///
+ public string Description => $"Leader-pinned listener for {_endpoint.Uri} — runs only on the cluster's elected leader node, so the listening role moves with leader elections.";
+
public Task CheckHealthAsync(HealthCheckContext context,
CancellationToken cancellationToken = default)
{