BC AL Code Reviewer
Audits Business Central AL extension code against a prioritized convention stack and produces a structured review report. The compiler catches syntax errors — this skill catches the mistakes that compile fine but cause problems in production, AppSource rejection, or SaaS environments.
Read references/convention-stack.md while running Categories 1–4 — it contains the complete rule set with AL code examples and source references for every check.
Read references/appsource-blockers.md when running Category 5 or when the user asks about AppSource readiness — it contains the 14 blockers with Microsoft documentation links and a pre-submission checklist.
Convention priority stack
Rules are applied in this priority order. When sources conflict, the higher priority wins:
| Priority |
Source |
Scope |
| 1 |
AppSource validation requirements |
Blocks publication — non-negotiable |
| 2 |
CodeCop / PerTenantExtensionCop analyzers |
Compiler warnings treated as errors in CI |
| 3 |
alguidelines.dev |
Community standard, widely adopted |
| 4 |
al-copilot-skills catalogue patterns |
Ecosystem-specific, this skill collection |
When a finding comes from Priority 1 or 2, it is always 🔴 Blocker regardless of how minor it looks.
Input
The user provides one or more of:
- AL code — one or more
.al files (table, page, codeunit, report, etc.)
- Scope — what to focus on: full review, AppSource readiness only, performance only, SaaS readiness only
- Context — is this for AppSource, a per-tenant extension, or an internal tool?
- Extension type — new extension or modification of an existing one
If no scope is specified, run a full review across all five categories.
If the user provides only a snippet (not a full object), note which checks cannot be run without the full object.
Review categories
Category 1 — Naming & Structure
Checks that objects, files, fields, and variables follow AL naming conventions.
Key rules — see references/convention-stack.md#naming for the complete list:
- All custom objects have a prefix or suffix (mandatory for AppSource)
- File naming matches object type (
MyCodeunit.Codeunit.al, not Codeunit50100.al)
- Object IDs within the declared
app.json idRanges
- No
WITH statements (NoImplicitWith feature required from runtime 11.0+)
- Labels use
Locked = true when translation is not intended
ObsoleteState always paired with ObsoleteReason and ObsoleteTag
- Procedures use PascalCase, local variables use camelCase
- No hardcoded company names, environment names, or user IDs in code
Category 2 — Performance Anti-Patterns
Checks for patterns that compile correctly but cause slow pages, timeouts, or database overload.
Key rules — see references/convention-stack.md#performance:
SetLoadFields present before every FindSet / FindFirst / Get that reads specific fields
- No
CalcFields inside repeat...until loops
- No database calls (
Get, FindSet, FindFirst) inside repeat...until loops over large tables
- No
CalcSums replaceable loops (manual sum accumulation)
- Maximum 4 FlowFields on List pages
- No
Commit inside loops
SetRange / SetFilter applied before Find* (never after)
Category 3 — Extensibility Contract
Checks that the code respects the BC event-driven extensibility model so other extensions can integrate safely.
Key rules — see references/convention-stack.md#extensibility:
- Every business procedure has an
OnBefore + OnAfter [IntegrationEvent] pair
OnBefore events always include var IsHandled: Boolean parameter
IsHandled is checked after raising the event (if IsHandled then exit)
- No
Commit inside event subscribers
- Event subscriber parameters match publisher signature exactly (verified, not assumed)
[IntegrationEvent(false, false)] used (not GlobalVarAccess = true unless justified)
- Publishers do not expose internal implementation details through event parameters
[BusinessEvent] used for optional integrations, [IntegrationEvent] for critical ones
Category 4 — SaaS Readiness
Checks for patterns that work on-prem but fail or are rejected in SaaS / Business Central online.
Key rules — see references/convention-stack.md#saas:
InherentPermissions declared on all codeunits (InherentPermissions = X minimum)
InherentEntitlements declared on all objects
- No
DataPerCompany = false without explicit justification in a comment
- No direct file system access (
File, Blob local paths)
- No
Shell or OS-level calls
- No hardcoded absolute paths
[NonDebuggable] on procedures handling secrets or credentials
- Secrets stored in
IsolatedStorage, never in table fields as plain text
- No
sleep or artificial delays
ExecutionContext guard on event subscribers that call external services
- No
SMTP direct — use Email module instead
Category 5 — AppSource Blockers
Checks specifically for the conditions that cause AppSource validation to reject a submission.
See references/appsource-blockers.md for the complete list with references.
Key checks:
- Prefix/suffix registered and applied consistently to all objects and fields
- No access to base app internal procedures (those not marked
[Obsolete] but not public)
application dependency version compatible with target BC release
logo and brief present in app.json
- No
suppressWarnings pragma hiding CodeCop errors
- No
#pragma warning disable without a specific rule number and justification comment
TranslationFile feature enabled if the extension supports multiple languages
- No
ObsoleteState = Removed objects still referenced in code
- Test coverage present (test app as separate project)
Execution workflow
Step 1 — Identify object types and scope
List every object type present in the provided code. Note which categories apply:
| Object type |
Categories that apply |
| Table / TableExtension |
1, 2, 3, 4, 5 |
| Page / PageExtension |
1, 2, 4, 5 |
| Codeunit |
1, 2, 3, 4, 5 |
| Report |
1, 2, 4, 5 |
| Query |
1, 2, 4, 5 |
| Enum / EnumExtension |
1, 5 |
| PermissionSet |
1, 5 |
| Interface |
1 |
Step 2 — Run each applicable category
For each category, list every rule violation found. Do not skip a rule because it seems minor — the severity classification handles prioritization.
Step 3 — Classify findings
| Severity |
Symbol |
Criteria |
| Blocker |
🔴 |
Priority 1 or 2 source, OR causes runtime failure in SaaS/AppSource |
| Warning |
🟡 |
Priority 3 source, OR degrades performance/extensibility but does not block |
| Suggestion |
🔵 |
Priority 4 source, OR style/readability improvement |
Step 4 — Generate review report
Use the exact template below.
Step 5 — Generate prioritized fix list
After the report, produce a numbered fix list ordered by: 🔴 first (by AppSource impact), then 🟡, then 🔵. Each item has the exact line or object to fix and the corrected version.
Report template
# AL Code Review Report
**Extension:** {extension name from app.json or "unnamed"}
**Date:** {today}
**Scope:** Full review / AppSource readiness / Performance / SaaS readiness
**Objects reviewed:** {list of object types and counts}
---
## Summary
| Category | 🔴 Blockers | 🟡 Warnings | 🔵 Suggestions |
|---|---|---|---|
| 1 — Naming & Structure | n | n | n |
| 2 — Performance | n | n | n |
| 3 — Extensibility | n | n | n |
| 4 — SaaS Readiness | n | n | n |
| 5 — AppSource Blockers | n | n | n |
| **Total** | **n** | **n** | **n** |
**AppSource ready:** Yes / No / Conditional (fix blockers first)
---
## Findings
### 🔴 Blockers — {count}
#### [B-01] {Short title}
- **Category:** {1–5}
- **Source:** AppSource / CodeCop / alguidelines.dev / al-copilot-skills
- **Location:** {Object name, line or section}
- **Rule:** {Rule reference or description}
- **Issue:** {What is wrong and why it matters}
- **Fix:** {Exact corrected code or instruction}
{Repeat for each blocker}
---
### 🟡 Warnings — {count}
#### [W-01] {Short title}
- **Category:** {1–5}
- **Source:** {source}
- **Location:** {location}
- **Issue:** {issue}
- **Fix:** {fix}
---
### 🔵 Suggestions — {count}
| ID | Category | Location | Issue | Suggestion |
|---|---|---|---|---|
| S-01 | {cat} | {loc} | {issue} | {suggestion} |
---
## Prioritized fix list
1. 🔴 [B-01] {one-line fix description} → {object/line}
2. 🔴 [B-02] ...
3. 🟡 [W-01] ...
4. 🔵 [S-01] ...
---
## Convention sources
- AppSource requirements: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-checklist-submission
- CodeCop rules: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/analyzers/codecop
- alguidelines.dev: https://alguidelines.dev
- al-copilot-skills catalogue: https://github.com/microsoft/al-copilot-skills
---
## Skills Evidencing
| Field | Value |
|---|---|
| Skill loaded | bc-al-code-reviewer |
| Objects reviewed | {list} |
| Convention stack applied | AppSource → CodeCop → alguidelines.dev → al-copilot-skills |
| Findings | 🔴 {n} / 🟡 {n} / 🔵 {n} |
| AppSource ready | Yes / No / Conditional |
Behaviour rules
Never invent rules. Every finding must reference a specific rule from the convention stack. If you are unsure, mark the finding as 🔵 Suggestion and cite the closest applicable source.
If the user provides a snippet without full object context, note explicitly which checks could not be run (e.g., cannot verify InherentPermissions without the full codeunit declaration).
Do not rewrite the entire code. The fix for each finding is targeted and minimal.
If the extension context is "internal tool" (not AppSource, not SaaS), downgrade Category 4 and 5 findings from Blocker to Warning where appropriate — and state this explicitly in the report header.
If no issues are found in a category, say so explicitly — do not omit the category from the report.
Reference files
references/convention-stack.md — Complete rule set for all five categories with source references
references/appsource-blockers.md — AppSource validation requirements with Microsoft documentation links
1---2name: bc-al-code-reviewer3description: Reviews Business Central AL extension code against a prioritized convention stack: AppSource validation requirements, CodeCop/PerTenantExtensionCop analyzer rules, alguidelines.dev community standards, and al-copilot-skills catalogue patterns. Audits five categories that the AL compiler does not catch: naming and structure, performance anti-patterns, extensibility contract, SaaS readiness, and AppSource blockers. Produces a structured review report with severity-classified findings and a prioritized fix list. Use this skill whenever you want to review AL code before a PR, before AppSource submission, before deploying to a customer, when onboarding a new developer, when inheriting legacy AL code, or when a senior developer needs to audit an extension. Also trigger when the user says 'review my code', 'check this extension', 'is this AppSource ready', 'code quality', 'AL best practices', or 'what is wrong with this'.4---56# BC AL Code Reviewer78Audits Business Central AL extension code against a prioritized convention stack and produces a structured review report. The compiler catches syntax errors — this skill catches the mistakes that compile fine but cause problems in production, AppSource rejection, or SaaS environments.910Read `references/convention-stack.md` **while running Categories 1–4** — it contains the complete rule set with AL code examples and source references for every check.11Read `references/appsource-blockers.md` **when running Category 5 or when the user asks about AppSource readiness** — it contains the 14 blockers with Microsoft documentation links and a pre-submission checklist.1213---1415## Convention priority stack1617Rules are applied in this priority order. When sources conflict, the higher priority wins:1819| Priority | Source | Scope |20|---|---|---|21| 1 | AppSource validation requirements | Blocks publication — non-negotiable |22| 2 | CodeCop / PerTenantExtensionCop analyzers | Compiler warnings treated as errors in CI |23| 3 | [alguidelines.dev](https://alguidelines.dev) | Community standard, widely adopted |24| 4 | al-copilot-skills catalogue patterns | Ecosystem-specific, this skill collection |2526When a finding comes from Priority 1 or 2, it is always 🔴 Blocker regardless of how minor it looks.2728---2930## Input3132The user provides one or more of:3334- **AL code** — one or more `.al` files (table, page, codeunit, report, etc.)35- **Scope** — what to focus on: full review, AppSource readiness only, performance only, SaaS readiness only36- **Context** — is this for AppSource, a per-tenant extension, or an internal tool?37- **Extension type** — new extension or modification of an existing one3839If no scope is specified, run a full review across all five categories.40If the user provides only a snippet (not a full object), note which checks cannot be run without the full object.4142---4344## Review categories4546### Category 1 — Naming & Structure4748Checks that objects, files, fields, and variables follow AL naming conventions.4950Key rules — see `references/convention-stack.md#naming` for the complete list:51- All custom objects have a prefix or suffix (mandatory for AppSource)52- File naming matches object type (`MyCodeunit.Codeunit.al`, not `Codeunit50100.al`)53- Object IDs within the declared `app.json` `idRanges`54- No `WITH` statements (`NoImplicitWith` feature required from runtime 11.0+)55- Labels use `Locked = true` when translation is not intended56- `ObsoleteState` always paired with `ObsoleteReason` and `ObsoleteTag`57- Procedures use PascalCase, local variables use camelCase58- No hardcoded company names, environment names, or user IDs in code5960---6162### Category 2 — Performance Anti-Patterns6364Checks for patterns that compile correctly but cause slow pages, timeouts, or database overload.6566Key rules — see `references/convention-stack.md#performance`:67- `SetLoadFields` present before every `FindSet` / `FindFirst` / `Get` that reads specific fields68- No `CalcFields` inside `repeat...until` loops69- No database calls (`Get`, `FindSet`, `FindFirst`) inside `repeat...until` loops over large tables70- No `CalcSums` replaceable loops (manual sum accumulation)71- Maximum 4 FlowFields on List pages72- No `Commit` inside loops73- `SetRange` / `SetFilter` applied before `Find*` (never after)7475---7677### Category 3 — Extensibility Contract7879Checks that the code respects the BC event-driven extensibility model so other extensions can integrate safely.8081Key rules — see `references/convention-stack.md#extensibility`:82- Every business procedure has an `OnBefore` + `OnAfter` `[IntegrationEvent]` pair83- `OnBefore` events always include `var IsHandled: Boolean` parameter84- `IsHandled` is checked after raising the event (`if IsHandled then exit`)85- No `Commit` inside event subscribers86- Event subscriber parameters match publisher signature exactly (verified, not assumed)87- `[IntegrationEvent(false, false)]` used (not `GlobalVarAccess = true` unless justified)88- Publishers do not expose internal implementation details through event parameters89- `[BusinessEvent]` used for optional integrations, `[IntegrationEvent]` for critical ones9091---9293### Category 4 — SaaS Readiness9495Checks for patterns that work on-prem but fail or are rejected in SaaS / Business Central online.9697Key rules — see `references/convention-stack.md#saas`:98- `InherentPermissions` declared on all codeunits (`InherentPermissions = X` minimum)99- `InherentEntitlements` declared on all objects100- No `DataPerCompany = false` without explicit justification in a comment101- No direct file system access (`File`, `Blob` local paths)102- No `Shell` or OS-level calls103- No hardcoded absolute paths104- `[NonDebuggable]` on procedures handling secrets or credentials105- Secrets stored in `IsolatedStorage`, never in table fields as plain text106- No `sleep` or artificial delays107- `ExecutionContext` guard on event subscribers that call external services108- No `SMTP` direct — use `Email` module instead109110---111112### Category 5 — AppSource Blockers113114Checks specifically for the conditions that cause AppSource validation to reject a submission.115See `references/appsource-blockers.md` for the complete list with references.116117Key checks:118- Prefix/suffix registered and applied consistently to all objects and fields119- No access to base app internal procedures (those not marked `[Obsolete]` but not `public`)120- `application` dependency version compatible with target BC release121- `logo` and `brief` present in `app.json`122- No `suppressWarnings` pragma hiding CodeCop errors123- No `#pragma warning disable` without a specific rule number and justification comment124- `TranslationFile` feature enabled if the extension supports multiple languages125- No `ObsoleteState = Removed` objects still referenced in code126- Test coverage present (test app as separate project)127128---129130## Execution workflow131132### Step 1 — Identify object types and scope133134List every object type present in the provided code. Note which categories apply:135136| Object type | Categories that apply |137|---|---|138| Table / TableExtension | 1, 2, 3, 4, 5 |139| Page / PageExtension | 1, 2, 4, 5 |140| Codeunit | 1, 2, 3, 4, 5 |141| Report | 1, 2, 4, 5 |142| Query | 1, 2, 4, 5 |143| Enum / EnumExtension | 1, 5 |144| PermissionSet | 1, 5 |145| Interface | 1 |146147### Step 2 — Run each applicable category148149For each category, list every rule violation found. Do not skip a rule because it seems minor — the severity classification handles prioritization.150151### Step 3 — Classify findings152153| Severity | Symbol | Criteria |154|---|---|---|155| Blocker | 🔴 | Priority 1 or 2 source, OR causes runtime failure in SaaS/AppSource |156| Warning | 🟡 | Priority 3 source, OR degrades performance/extensibility but does not block |157| Suggestion | 🔵 | Priority 4 source, OR style/readability improvement |158159### Step 4 — Generate review report160161Use the exact template below.162163### Step 5 — Generate prioritized fix list164165After the report, produce a numbered fix list ordered by: 🔴 first (by AppSource impact), then 🟡, then 🔵. Each item has the exact line or object to fix and the corrected version.166167---168169## Report template170171```markdown172# AL Code Review Report173174**Extension:** {extension name from app.json or "unnamed"}175**Date:** {today}176**Scope:** Full review / AppSource readiness / Performance / SaaS readiness177**Objects reviewed:** {list of object types and counts}178179---180181## Summary182183| Category | 🔴 Blockers | 🟡 Warnings | 🔵 Suggestions |184|---|---|---|---|185| 1 — Naming & Structure | n | n | n |186| 2 — Performance | n | n | n |187| 3 — Extensibility | n | n | n |188| 4 — SaaS Readiness | n | n | n |189| 5 — AppSource Blockers | n | n | n |190| **Total** | **n** | **n** | **n** |191192**AppSource ready:** Yes / No / Conditional (fix blockers first)193194---195196## Findings197198### 🔴 Blockers — {count}199200#### [B-01] {Short title}201- **Category:** {1–5}202- **Source:** AppSource / CodeCop / alguidelines.dev / al-copilot-skills203- **Location:** {Object name, line or section}204- **Rule:** {Rule reference or description}205- **Issue:** {What is wrong and why it matters}206- **Fix:** {Exact corrected code or instruction}207208{Repeat for each blocker}209210---211212### 🟡 Warnings — {count}213214#### [W-01] {Short title}215- **Category:** {1–5}216- **Source:** {source}217- **Location:** {location}218- **Issue:** {issue}219- **Fix:** {fix}220221---222223### 🔵 Suggestions — {count}224225| ID | Category | Location | Issue | Suggestion |226|---|---|---|---|---|227| S-01 | {cat} | {loc} | {issue} | {suggestion} |228229---230231## Prioritized fix list2322331. 🔴 [B-01] {one-line fix description} → {object/line}2342. 🔴 [B-02] ...2353. 🟡 [W-01] ...2364. 🔵 [S-01] ...237238---239240## Convention sources241242- AppSource requirements: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-checklist-submission243- CodeCop rules: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/analyzers/codecop244- alguidelines.dev: https://alguidelines.dev245- al-copilot-skills catalogue: https://github.com/microsoft/al-copilot-skills246247---248249## Skills Evidencing250251| Field | Value |252|---|---|253| Skill loaded | bc-al-code-reviewer |254| Objects reviewed | {list} |255| Convention stack applied | AppSource → CodeCop → alguidelines.dev → al-copilot-skills |256| Findings | 🔴 {n} / 🟡 {n} / 🔵 {n} |257| AppSource ready | Yes / No / Conditional |258```259260---261262## Behaviour rules2632641. Never invent rules. Every finding must reference a specific rule from the convention stack. If you are unsure, mark the finding as 🔵 Suggestion and cite the closest applicable source.2652662. If the user provides a snippet without full object context, note explicitly which checks could not be run (e.g., cannot verify `InherentPermissions` without the full codeunit declaration).2672683. Do not rewrite the entire code. The fix for each finding is targeted and minimal.2692704. If the extension context is "internal tool" (not AppSource, not SaaS), downgrade Category 4 and 5 findings from Blocker to Warning where appropriate — and state this explicitly in the report header.2712725. If no issues are found in a category, say so explicitly — do not omit the category from the report.273274---275276## Reference files277278- `references/convention-stack.md` — Complete rule set for all five categories with source references279- `references/appsource-blockers.md` — AppSource validation requirements with Microsoft documentation links