Skip to content
Development
Skill

/skill-events

AL event-driven architecture for Business Central. Use when creating EventSubscribers, IntegrationEvents, BusinessEvents, or implementing publisher/subscriber patterns in extensions.

BOOST
From plugin
aldc-al-development-collection
11237 skills28 agents11 commands4 MCP
Install
$ npx -y skills add javiarmesto/ALDC-AL-Development-Collection --skill skill-events --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/skill-events

Context preview

The summary Claude sees to decide when to auto-load this skill.

AL event-driven architecture for Business Central. Use when creating EventSubscribers, IntegrationEvents, BusinessEvents, or implementing publisher/subscriber patterns in extensions.

SKILL.md

skill-events.SKILL.md
name: skill-events
description: "AL event-driven architecture for Business Central. Use when creating EventSubscribers, IntegrationEvents, BusinessEvents, or implementing publisher/subscriber patterns in extensions."

Skill: AL Event-Driven Architecture

Purpose

Discover, design, and implement event-driven patterns in AL Business Central extensions: event discovery via Event Recorder, subscriber/publisher creation, IsHandled patterns, and extensibility design.

When to Load

This skill should be loaded when:

  • Extending standard BC functionality (posting, validation, master data changes)
  • Designing custom integration events for a new codeunit or extension
  • A subscriber is not firing and needs investigation
  • An architecture requires extensibility points for future consumers
  • Implementing document posting interventions, workflow triggers, or UI customizations

Core Patterns

Pattern 1: Event Discovery with Event Recorder

Before writing any subscriber, discover which events are raised during the business process:

1. Open the Event Recorder in VS Code  ← VS Code command (not an agent tool)
2. Start recording
3. Execute the business process in BC (e.g., post a sales order)
4. Stop recording
5. Analyze the event list — filter by object or keyword
6. Identify the OnBefore/OnAfter event closest to your extension point

Use `al_search_objects` and `al_get_object_definition` to inspect publisher signatures. Use `al_find_references` to see who else subscribes to the same event.

Pattern 2: Event Subscriber

// Subscriber codeunit — name with "Handler" suffix
codeunit 50100 "Sales Document Events Handler"
{
    // Attribute breakdown:
    //   ObjectType  — Table, Codeunit, Page, Report, etc.
    //   ObjectId    — Database::"Sales Header" or Codeunit::"Customer Management"
    //   EventName   — exact name of the publisher procedure (e.g., OnBeforeInsert)
    //   ElementName — '' for table/codeunit events; field name for page field triggers
    //   SkipOnMissingLicense  — false (recommended: always run)
    //   SkipOnMissingPermission — false (recommended: always run)

    [EventSubscriber(ObjectType::Table, Database::"Sales Header",
                     OnBeforeInsert, '', false, false)]
    local procedure OnBeforeInsertSalesHeader(
        var SalesHeader: Record "Sales Header";
        RunTrigger: Boolean)
    begin
        ValidateCustomFields(SalesHeader);
    end;
}

**Subscriber rules:**

  • Procedure MUST be `local`
  • Parameter signature MUST exactly match the publisher (name, type, order)
  • One subscriber per event per codeunit (keep handler codeunits focused)
  • Never use `Commit` inside a subscriber unless absolutely necessary

Pattern 3: Integration Event Publisher with IsHandled

The standard extensibility pattern: `OnBefore` allows interception, `OnAfter` allows reaction.

codeunit 50101 "Customer Management"
{
    procedure CreateCustomer(var Customer: Record Customer): Boolean
    var
        IsHandled: Boolean;
    begin
        // 1. Raise OnBefore — subscribers can validate, modify, or skip
        OnBeforeCreateCustomer(Customer, IsHandled);
        if IsHandled then
            exit(true);

        // 2. Default logic
        if not Customer.Insert(true) then
            exit(false);

        // 3. Raise OnAfter — subscribers can react (logging, integration, etc.)
        OnAfterCreateCustomer(Customer);
        exit(true);
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeCreateCustomer(
        var Customer: Record Customer;
        var IsHandled: Boolean)
    begin
        // Empty body — subscribers provide the implementation
        // IsHandled = true → skip default logic
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCreateCustomer(var Customer: Record Customer)
    begin
        // Empty body — subscribers react after creation
    end;
}

**IntegrationEvent attribute:**

  • `IntegrationEvent(IncludeSender, GlobalVarAccess)`
  • `IncludeSender = false` — recommended for clean API (no coupling to publisher internals)
  • `GlobalVarAccess = false` — recommended (prevent subscribers from accessing publisher global vars)

Pattern 4: Business Event

Business events are user-disablable — use for optional, non-critical functionality:

[BusinessEvent(IncludeSender)]
local procedure OnCustomerCreditLimitExceeded(
    Customer: Record Customer;
    RequestedAmount: Decimal)
begin
    // Subscribers may send notification, log, or block — user can disable
end;

| Attribute | Cannot be disabled | Use for | |---|---|---| | `IntegrationEvent` | Correct | Critical business logic, posting interventions | | `BusinessEvent` | Can be disabled by user | Optional features, external integrations, notifications |

Pattern 5: Well-Designed Event Parameters

// ✅ Good — rich context, var where modification expected, IsHandled for OnBefore
[IntegrationEvent(false, false)]
local procedure OnBeforePostDocument(
    var DocumentHeader: Record "Sales Header";   // var — subscriber may modify
    var DocumentLines: Record "Sales Line";      // var — subscriber may modify
    PostingDate: Date;                           // value — read-only context
    var IsHandled: Boolean)                      // var — subscriber may skip default
begin
end;

// ✅ Good — results context for OnAfter
[IntegrationEvent(false, false)]
local procedure OnAfterPostDocument(
    DocumentHeader: Record "Sales Header";       // value — read-only (already posted)
    PostedDocumentNo: Code[20];                  // result reference
    PostingResult: Boolean)                      // success/failure
begin
end;

**Parameter design rules:**

  • `var Record` — when subscribers should be able to modify the record
  • Non-var `Record` — when record is read-only context
  • Always include `var IsHandled: Boolean` in `OnBefore` events
  • Include result/outcome parameters in `OnAfter` events
  • Use meaningfu
Read more
Ships withaldc-al-development-collection

Skills-based, spec-driven, TDD-orchestrated development framework for Microsoft Dynamics 365 Business Central. Engineering systems, visibly reasoned.

Get the whole plugin