skill-events
Skill115 starsChanged 10 days agoMITView on GitHub
AL event-driven architecture for Business Central. Use when creating EventSubscribers, IntegrationEvents, BusinessEvents, or implementing publisher/subscriber patterns in extensions.
In this repository55 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- claude-plugin/CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- instructions/copilot-instructions.mdCopilot instructions
- agent-builderSkill
- al-agent-build-instructionsSkill
- al-agent-createSkill
- al-agent-instructionsSkill
- al-agent-taskSkill
- al-agent-testSkill
- al-buildSkill
- al-context-createSkill
- al-initializeSkill
- al-memory-createSkill
- al-pr-prepareSkill
- al-spec-createSkill
- architectSkill
- auditSkill
- conductSkill
- developSkill
- presalesSkill
- reviewSkill
- skill-agent-instructionsSkill
- skill-agent-task-patternsSkill
- skill-agent-toolkitSkill
- skill-al-review-pipelineSkill
- skill-apiSkill
- skill-contribution-assistantSkill
- skill-copilotSkill
- skill-debugSkill
- skill-estimationSkill
- skill-eventsSkill
- skill-migrateSkill
- skill-pagesSkill
- skill-performanceSkill
- skill-permissionsSkill
- skill-testingSkill
- skill-translateSkill
- specSkill
- triageSkill
- skill-agent-instructionsSkill
- skill-agent-task-patternsSkill
- skill-agent-toolkitSkill
- skill-al-review-pipelineSkill
- skill-apiSkill
- skill-contribution-assistantSkill
- skill-copilotSkill
- skill-debugSkill
- skill-estimationSkill
- skill-migrateSkill
- skill-pagesSkill
- skill-performanceSkill
- skill-permissionsSkill
- skill-testingSkill
- skill-translateSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 4 are distinctive, and 13 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
13
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 25
Before writing any subscriber, discover which events are raised during the business process:
- Very specific: line 36
Use al_search_objects and al_get_object_definition to inspect publisher signatures.
- Very specific: line 37
Use al_find_references to see who else subscribes to the same event.
- Very specific: line 68
Never use Commit inside a subscriber unless absolutely necessary
- Very specific: line 162
Always include var IsHandled: Boolean in OnBefore events
- Distinctive: line 164
Use meaningful parameter names that describe business intent
- Very specific: line 173
Use al_get_object_definition to inspect publisher signatures
- Very specific: line 174
Use al_find_references to check existing subscribers (avoid conflicts)
- Very specific: line 181
Create a handler codeunit with naming: "{Domain} Events Handler"
- Very specific: line 185
Add OnBefore event with IsHandled pattern before key operations
- Very specific: line 186
Add OnAfter event after key operations with result context
- Very specific: line 187
Follow naming: OnBefore{Action} / OnAfter{Action}
- Distinctive: line 192
Use the AL: Insert Event Subscriber VS Code command (not an agent tool) to scaffold subscriber/publisher structures, then fill the body:
- Distinctive: line 218
If subscriber does NOT fire, check:
- Very specific: line 247
Do NOT create publishers without an OnBefore + OnAfter pair at minimum
- Very specific: line 248
Do NOT use Commit inside event subscribers unless absolutely required
- Very specific: line 249
Do NOT set IsHandled = true without clear documentation of why default logic is skipped
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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 pointUse 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
Commitinside 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: BooleaninOnBeforeevents - Include result/outcome parameters in
OnAfterevents - Use meaningful parameter names that describe business intent
Workflow
Step 1: Discover Events
- Open the Event Recorder in VS Code (a VS Code command, not an agent tool)
- Execute the target business process in BC
- Review recorded events — filter by relevant object
- Use
al_get_object_definitionto inspect publisher signatures - Use
al_find_referencesto check existing subscribers (avoid conflicts)
Step 2: Design Event Architecture
For subscribing to existing events:
- Identify the right OnBefore / OnAfter event from Step 1
- Match the parameter signature exactly
- Create a handler codeunit with naming:
"{Domain} Events Handler"
For creating new integration events in your codeunit:
- Identify logical extension points in your business logic
- Add
OnBeforeevent withIsHandledpattern before key operations - Add
OnAfterevent after key operations with result context - Follow naming:
OnBefore{Action}/OnAfter{Action} - Choose
IntegrationEvent(critical) orBusinessEvent(optional)
Step 3: Implement
Use the AL: Insert Event Subscriber VS Code command (not an agent tool) to scaffold subscriber/publisher structures, then fill the body:
// Subscriber handler codeunit
codeunit 50102 "Customer Validation Handler"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Customer Management",
OnBeforeCreateCustomer, '', false, false)]
local procedure ValidateOnBeforeCreate(
var Customer: Record Customer;
var IsHandled: Boolean)
begin
ValidateCustomerCreditLimit(Customer);
if ShouldSkipDefaultProcessing(Customer) then
IsHandled := true;
end;
}Step 4: Verify
- Build:
al_build— check for compilation errors (signature mismatches) - Set breakpoint inside subscriber
- Debug:
al_debug - Execute the business process — confirm subscriber fires
- If subscriber does NOT fire, check:
- Signature mismatch (most common cause)
- Wrong
ObjectType/ObjectId - Extension not published/active
- Another subscriber set
IsHandled = truebefore yours - SkipOnMissingLicense / SkipOnMissingPermission attributes
Common Scenarios
| Scenario | Event Source | Pattern |
| Validate before posting | OnBeforePost* on Codeunit "Sales-Post" | Subscriber + IsHandled |
| Add fields to sales order | OnAfterInsert on Table "Sales Header" | Subscriber (set defaults) |
| External integration trigger | OnAfterPostDocument (custom) | Publisher in your codeunit |
| Custom approval workflow | OnBeforeRelease* | Subscriber + IsHandled to block |
| UI field validation | Page trigger OnAfterValidate on field | Subscriber with ElementName |
| Master data change audit | OnAfterModify on Table "Customer" | Subscriber (log changes) |
References
- Event Recorder — Microsoft Docs
- Events in AL
- IntegrationEvent Attribute
- BusinessEvent Attribute
- EventSubscriber Attribute
Constraints
- This skill covers event discovery, design, and implementation patterns — it does NOT duplicate the passive rules in
al-events.instructions.md(auto-applied to all.alfiles) - Do NOT create publishers without an
OnBefore+OnAfterpair at minimum - Do NOT use
Commitinside event subscribers unless absolutely required - Do NOT set
IsHandled = truewithout clear documentation of why default logic is skipped - Subscriber debugging (breakpoints, snapshots) → load
skill-debug.md - Subscriber performance overhead analysis → load
skill-performance.md
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

