Skip to main content
AI/MLCrestApps

orchardcore-workflows

Skill for creating and managing Orchard Core workflows. Covers workflow type definitions, custom activities, events, workflow expressions, and workflow triggers. Use this skill when requests mention Orchard Core Workflows, Create a Workflow, Enabling Workflows, Built-in Event Activities, Built-in Task Activities, Creating a Custom Activity, or closely related Orchard Core implementation, setup, extension, or troubleshooting work. Strong matches include work with OrchardCore.Workflows, OrchardCore.Workflows.Http, OrchardCore.Workflows.Timers, OrchardCore.Workflows.Activities, OrchardCore.Workflows.Models, TaskActivity, IStringLocalizer, IEnumerable, WorkflowExecutionContext, ActivityContext, EventActivity, IServiceCollection. It also helps with workflow examples, Built-in Task Activities, Creating a Custom Activity, Creating a Custom Event, plus the code patterns, admin flows, recipe steps, and referenced examples captured in this skill.

Stars
13
Source
CrestApps/CrestApps.AgentSkills
Updated
2026-05-29
Slug
CrestApps--CrestApps.AgentSkills--orchardcore-workflows
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/CrestApps/CrestApps.AgentSkills/HEAD/plugins/orchardcore/skills/orchardcore-workflows/SKILL.md -o .claude/skills/orchardcore-workflows.md

Drops the SKILL.md into .claude/skills/orchardcore-workflows.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Orchard Core Workflows - Prompt Templates

Create a Workflow

You are an Orchard Core expert. Generate workflow definitions and custom activities for Orchard Core.

Guidelines

  • Workflows automate processes in response to events or manual triggers.
  • Enable the OrchardCore.Workflows feature to use workflows.
  • Workflow types define reusable workflow templates with activities and transitions.
  • Activities are the building blocks: tasks (actions) and events (triggers).
  • Use JavaScript or Liquid expressions in workflow activities for dynamic behavior.
  • Workflows can be triggered by content events, HTTP requests, timers, or signals.
  • Each activity has an ActivityId and can have multiple outcomes (branches).

Enabling Workflows

{
  "steps": [
    {
      "name": "Feature",
      "enable": [
        "OrchardCore.Workflows",
        "OrchardCore.Workflows.Http",
        "OrchardCore.Workflows.Timers"
      ],
      "disable": []
    }
  ]
}

Built-in Event Activities

  • ContentCreatedEvent - Triggered when a content item is created.
  • ContentPublishedEvent - Triggered when a content item is published.
  • ContentUpdatedEvent - Triggered when a content item is updated.
  • ContentDeletedEvent - Triggered when a content item is deleted.
  • HttpRequestEvent - Triggered by an incoming HTTP request.
  • TimerEvent - Triggered on a schedule (cron expression).
  • SignalEvent - Triggered by a named signal.
  • UserRegisteredEvent - Triggered when a new user registers.

Built-in Task Activities

  • NotifyTask - Displays a notification message.
  • LogTask - Writes to the application log.
  • SetPropertyTask - Sets a workflow property (supports JavaScript and Liquid syntax).
  • SetOutputTask - Sets a workflow output value (supports JavaScript and Liquid syntax).
  • IfElseTask - Conditional branching (supports JavaScript and Liquid syntax).
  • ForLoopTask - Loop with counter (supports JavaScript and Liquid syntax).
  • ForEachTask - Iterate over a collection (supports JavaScript and Liquid syntax).
  • WhileLoopTask - Loop while condition is true (supports JavaScript and Liquid syntax).
  • ForkTask - Parallel execution branches.
  • JoinTask - Wait for parallel branches to complete.
  • HttpRequestTask - Make an outbound HTTP request.
  • HttpRedirectTask - Redirect the user to a URL.
  • ContentCreateTask - Create a new content item.
  • ContentPublishTask - Publish a content item.
  • SendEmailTask - Send an email notification.
  • ScriptTask - Execute a JavaScript expression and return the result.
  • LiquidTask - Execute a Liquid expression and return the result.

Workflow Script Syntax

Many workflow tasks (IfElseTask, ForLoopTask, ForEachTask, WhileLoopTask, SetPropertyTask, SetOutputTask) now support both JavaScript and Liquid syntax. Each task has a Syntax property that selects between WorkflowScriptSyntax.JavaScript and WorkflowScriptSyntax.Liquid.

  • When JavaScript is selected, the task evaluates the JavaScript expression field.
  • When Liquid is selected, the task evaluates the Liquid expression field instead.
namespace OrchardCore.Workflows.Models;

public enum WorkflowScriptSyntax
{
    JavaScript,
    Liquid,
}

Creating a Custom Activity

using OrchardCore.Workflows.Abstractions.Models;
using OrchardCore.Workflows.Activities;
using OrchardCore.Workflows.Models;

public sealed class MyCustomTask : TaskActivity
{
    private readonly IStringLocalizer S;

    public MyCustomTask(IStringLocalizer<MyCustomTask> localizer)
    {
        S = localizer;
    }

    public override string Name => "MyCustomTask";

    public override LocalizedString DisplayText => S["My Custom Task"];

    public override LocalizedString Category => S["Custom"];

    public override IEnumerable<Outcome> GetPossibleOutcomes(
        WorkflowExecutionContext workflowContext,
        ActivityContext activityContext)
    {
        return Outcomes(S["Done"], S["Failed"]);
    }

    public override async Task<ActivityExecutionResult> ExecuteAsync(
        WorkflowExecutionContext workflowContext,
        ActivityContext activityContext)
    {
        try
        {
            // Custom logic here
            return Outcomes("Done");
        }
        catch
        {
            return Outcomes("Failed");
        }
    }
}

Creating a Custom Event

using OrchardCore.Workflows.Activities;
using OrchardCore.Workflows.Models;

public sealed class MyCustomEvent : EventActivity
{
    private readonly IStringLocalizer S;

    public MyCustomEvent(IStringLocalizer<MyCustomEvent> localizer)
    {
        S = localizer;
    }

    public override string Name => "MyCustomEvent";

    public override LocalizedString DisplayText => S["My Custom Event"];

    public override LocalizedString Category => S["Custom"];

    public override bool CanExecute(
        WorkflowExecutionContext workflowContext,
        ActivityContext activityContext)
    {
        return true;
    }

    public override IEnumerable<Outcome> GetPossibleOutcomes(
        WorkflowExecutionContext workflowContext,
        ActivityContext activityContext)
    {
        return Outcomes(S["Done"]);
    }
}

Registering Custom Activities

public sealed class Startup : StartupBase
{
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddActivity<MyCustomTask, MyCustomTaskDisplayDriver>();
        services.AddActivity<MyCustomEvent, MyCustomEventDisplayDriver>();
    }
}

Workflow Expressions

Workflows support JavaScript and Liquid expressions. Tasks with dual syntax (IfElseTask, ForLoopTask, etc.) use the Syntax property to select which expression to evaluate.

JavaScript expressions:

// Access workflow input
var contentItem = input("ContentItem");

// Access workflow properties
var count = property("LoopCount");

// Set output
setOutcome("Done");

Liquid expressions:

{{ Workflow.Input.ContentItem.DisplayText }}
{{ Workflow.Properties.MyProperty }}
{% if Workflow.Properties.Count > 0 %}true{% endif %}

LiquidTask Example

LiquidTask is the Liquid counterpart of ScriptTask. It evaluates a Liquid expression and stores the result in WorkflowContext.LastResult:

using OrchardCore.Workflows.Activities;
using OrchardCore.Workflows.Models;
using OrchardCore.Workflows.Services;

public class LiquidTask : TaskActivity<LiquidTask>
{
    private readonly IWorkflowExpressionEvaluator _expressionEvaluator;
    protected readonly IStringLocalizer S;

    public LiquidTask(
        IWorkflowExpressionEvaluator expressionEvaluator,
        IStringLocalizer<LiquidTask> localizer)
    {
        _expressionEvaluator = expressionEvaluator;
        S = localizer;
    }

    public override LocalizedString DisplayText => S["Liquid Task"];
    public override LocalizedString Category => S["Control Flow"];

    public WorkflowExpression<object> Expression
    {
        get => GetProperty(() => new WorkflowExpression<object>());
        set => SetProperty(value);
    }

    public override IEnumerable<Outcome> GetPossibleOutcomes(
        WorkflowExecutionContext workflowContext, ActivityContext activityContext)
        => Outcomes(S["Done"]);

    public override async Task<ActivityExecutionResult> ExecuteAsync(
        WorkflowExecutionContext workflowContext, ActivityContext activityContext)
    {
        workflowContext.LastResult = await _expressionEvaluator.EvaluateAsync(
            Expression, workflowContext, null);
        return Outcomes("Done");
    }
}

Timer Cron Expressions

Timer events use cron expressions:

  • */5 * * * * - Every 5 minutes.
  • 0 * * * * - Every hour.
  • 0 0 * * * - Every day at midnight.
  • 0 0 * * 1 - Every Monday at midnight.
  • 0 0 1 * * - First day of every month.