diff --git a/src/clients/Elsa.Api.Client/Resources/ActivityDescriptors/Models/ActivityDescriptor.cs b/src/clients/Elsa.Api.Client/Resources/ActivityDescriptors/Models/ActivityDescriptor.cs
index 8ba4079c82..4f6b68a1de 100644
--- a/src/clients/Elsa.Api.Client/Resources/ActivityDescriptors/Models/ActivityDescriptor.cs
+++ b/src/clients/Elsa.Api.Client/Resources/ActivityDescriptors/Models/ActivityDescriptor.cs
@@ -82,6 +82,11 @@ public record ActivityDescriptor
///
public bool IsBrowsable { get; set; }
+ ///
+ /// Whether this activity type is a start activity.
+ ///
+ public bool IsStart { get; set; }
+
///
/// Whether this activity type is a terminal activity.
///
diff --git a/src/modules/Elsa.Workflows.Core/Activities/Start.cs b/src/modules/Elsa.Workflows.Core/Activities/Start.cs
index 5dcfcbefad..f8f001d611 100644
--- a/src/modules/Elsa.Workflows.Core/Activities/Start.cs
+++ b/src/modules/Elsa.Workflows.Core/Activities/Start.cs
@@ -1,5 +1,6 @@
using System.Runtime.CompilerServices;
using Elsa.Workflows.Attributes;
+using Elsa.Workflows.Contracts;
using JetBrains.Annotations;
namespace Elsa.Workflows.Activities;
@@ -9,7 +10,7 @@ namespace Elsa.Workflows.Activities;
///
[Activity("Elsa", "Flow", "A milestone activity that marks the start of a flowchart.", Kind = ActivityKind.Action)]
[PublicAPI]
-public class Start : CodeActivity
+public class Start : CodeActivity, IStartNode
{
///
public Start([CallerFilePath] string? source = default, [CallerLineNumber] int? line = default) : base(source, line)
diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IStartNode.cs b/src/modules/Elsa.Workflows.Core/Contracts/IStartNode.cs
new file mode 100644
index 0000000000..1f0311c41b
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Core/Contracts/IStartNode.cs
@@ -0,0 +1,8 @@
+namespace Elsa.Workflows.Contracts;
+
+///
+/// Marks an activity as a terminal activity.
+///
+public interface IStartNode
+{
+}
\ No newline at end of file
diff --git a/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs b/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs
index a14e589ff1..cd09df6bd1 100644
--- a/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs
+++ b/src/modules/Elsa.Workflows.Core/Models/ActivityDescriptor.cs
@@ -97,6 +97,11 @@ public class ActivityDescriptor
///
public bool IsBrowsable { get; set; } = true;
+ ///
+ /// Whether this activity type is a start activity.
+ ///
+ public bool IsStart { get; set; }
+
///
/// Whether this activity type is a terminal activity.
///
diff --git a/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs b/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs
index 805fdd4cc4..365f4c5c86 100644
--- a/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs
+++ b/src/modules/Elsa.Workflows.Core/Services/ActivityDescriber.cs
@@ -74,6 +74,7 @@ where typeof(IActivity).IsAssignableFrom(prop.PropertyType)
var isTrigger = activityType.IsAssignableTo(typeof(ITrigger));
var browsableAttr = activityType.GetCustomAttribute();
var isTerminal = activityType.FindInterfaces((type, criteria) => type == typeof(ITerminalNode), null).Any();
+ var isStart = activityType.FindInterfaces((type, criteria) => type == typeof(IStartNode), null).Any();
var attributes = activityType.GetCustomAttributes(true).Cast().ToList();
var outputAttribute = attributes.OfType().FirstOrDefault();
@@ -92,6 +93,7 @@ where typeof(IActivity).IsAssignableFrom(prop.PropertyType)
Outputs = (await DescribeOutputPropertiesAsync(outputProperties, cancellationToken)).ToList(),
IsContainer = typeof(IContainer).IsAssignableFrom(activityType),
IsBrowsable = browsableAttr == null || browsableAttr.Browsable,
+ IsStart = isStart,
IsTerminal = isTerminal,
Attributes = attributes,
Constructor = context =>