AL Technical Specification Workflow¶
Your goal is to generate a detailed implementable technical specification for ${input:req_name} (complexity: ${input:Complexity}).
This is NOT the architecture phase. This phase produces the implementable blueprint: exact object IDs, field types, procedure signatures, event patterns, and AL code snippets.
Guardrails¶
- Never create or modify real AL objects during this phase
- Never output to
/specs/— always output to.github/plans/{req_name}/ - If
{req_name}.architecture.mdexists, read it first — the spec must implement what the architect designed - If spec already exists, confirm with user before overwriting
- Complexity drives depth: LOW = lighter spec, MEDIUM/HIGH = full spec with all sections
Step 1 — Read Context¶
1.1 Read global memory¶
Extract: project app ID range, naming conventions (prefix), existing table IDs in use, current extension patterns.
1.2 Read architecture document (if exists)¶
If it exists: the spec MUST align with the architectural decisions (data flows, chosen patterns, integration points). If it does not exist: proceed — spec will define structure from scratch (typical for LOW complexity).
1.3 Analyze codebase¶
Search for: - Existing objects with similar patterns (search) - Naming conventions in /src - Available object ID ranges in app.json - Existing event publishers relevant to this feature - Existing API pages or codeunits if integration is involved
Step 2 — Generate Specification¶
Create .github/plans/${input:req_name}/${input:req_name}.spec.md with the following structure:
# ${input:req_name} — Technical Specification
**Version:** 1.0
**Date:** {current date}
**Complexity:** ${input:Complexity}
**Status:** Draft
## 1. Overview
### Business Context
[1-3 sentences describing what this feature does and why it is needed]
### Scope
[What is included. What is explicitly excluded.]
### Architecture Reference
[If architecture.md exists: "Implements {req_name}.architecture.md — {pattern chosen}". If not: "No architecture document — spec defines structure."]
---
## 2. AL Object Inventory
| Object Type | Object ID | Name | Extends / Source | Purpose |
|-------------|-----------|------|-----------------|---------|
| TableExtension | {ID from range} | {Prefix} {BaseName} Ext | {Base Table} | {Why this extension} |
| PageExtension | {ID} | {Prefix} {BasePage} Ext | {Base Page} | {What fields/actions added} |
| Codeunit | {ID} | {Prefix} {Name} Mgt | — | {Core business logic} |
| Codeunit | {ID} | {Prefix} {Name} Subscriber | — | {Event subscriptions} |
> Object IDs MUST be within the app.json `idRanges`. Verify with codebase search before assigning.
---
## 3. Data Model
### Table Extensions / New Tables
For each table/extension:
```al
tableextension {ID} "{Prefix} {BaseName} Ext" extends "{BaseName}"
{
fields
{
field({FieldID}; "{Prefix} {FieldName}"; {DataType}[{Length}])
{
Caption = '{Caption}', Comment = '{Translation key}';
DataClassification = CustomerContent; // or ToBeClassified / SystemMetadata
{CalcFormula / TableRelation / BlankZero / etc. if applicable}
}
}
}
Specify GDPR DataClassification for every field.
Field Catalogue¶
| Field No. | Field Name | Type | Length | Required | Relation | Description |
|---|---|---|---|---|---|---|
| {ID} | {Prefix} | {Type} | {L} | Yes/No | {Table."Field"} | {Purpose} |
4. Business Logic — Codeunit Procedures¶
For each codeunit, list every public procedure with full signature:
codeunit {ID} "{Prefix} {Name} Mgt"
{
// Procedure: {What it does}
// Called by: {who calls this}
procedure {ProcedureName}({Param}: {Type}): {ReturnType}
begin
// AL code sketch for complex logic only
end;
// Internal helper
local procedure {HelperName}({Param}: {Type})
begin
end;
}
5. Event Integration¶
Publishers (new events this feature exposes)¶
// In: {Codeunit name}
[IntegrationEvent(false, false)]
local procedure OnAfter{ActionName}({Param}: {Type})
begin
end;
Subscribers (events this feature hooks into)¶
[EventSubscriber(ObjectType::Codeunit, Codeunit::{Publisher}, '{EventName}', '', false, false)]
local procedure {EventName}_Handler({Param}: {Type})
begin
// What this subscriber does
end;
6. Pages and UI¶
Page Extensions / New Pages¶
pageextension {ID} "{Prefix} {BasePage} Ext" extends "{BasePage}"
{
layout
{
addafter({ExistingGroup})
{
group("{Prefix} {GroupName}")
{
Caption = '{Caption}';
field("{Prefix} {FieldName}"; Rec."{Prefix} {FieldName}")
{
ApplicationArea = All;
ToolTip = '{Explain what this field does}';
}
}
}
}
actions
{
addafter({ExistingAction})
{
action("{Prefix} {ActionName}")
{
Caption = '{Caption}';
ApplicationArea = All;
Image = {IconName};
trigger OnAction()
begin
{Codeunit}.{Procedure}(Rec);
end;
}
}
}
}
7. Tests (Given/When/Then)¶
For each main scenario:
codeunit {ID} "{Prefix} {Feature} Tests"
{
Subtype = Test;
[Test]
procedure {ScenarioName}()
// Given: {Initial state}
// When: {Action performed}
// Then: {Expected result}
var
{Var}: Record {Table};
begin
// Arrange
// Act
// Assert
Assert.{AssertMethod}({Expected}, {Actual}, '{Message}');
end;
}
| Test Name | Given | When | Then |
|---|---|---|---|
| {Scenario1} | {State} | {Action} | {Result} |
| {Scenario2} | {State} | {Action} | {Result} |
8. Permission Sets¶
permissionset {ID} "{Prefix} - {Feature}"
{
Assignable = true;
Caption = '{Caption}';
Permissions =
tabledata "{Table}" = RIMD,
codeunit "{Codeunit}" = X;
}
9. API Endpoints (if applicable)¶
Only if this feature exposes or consumes APIs:
page {ID} "{Prefix} {Entity} API"
{
PageType = API;
APIPublisher = '{publisher}';
APIGroup = '{group}';
APIVersion = 'v2.0';
EntityName = '{entity}';
EntitySetName = '{entities}';
SourceTable = {Table};
DelayedInsert = true;
layout
{
area(Content)
{
repeater(Group)
{
field(id; Rec.SystemId) { }
field({camelCaseField}; Rec."{Field Name}") { }
}
}
}
}
10. AL-Go / CI Considerations¶
- New object IDs registered in
app.jsonidRanges - AppSourceCop rules: no hardcoded object IDs in code
- Build pipeline: no new BC version dependencies introduced
- Translations: all new Captions added to XLF
11. Acceptance Criteria¶
Functional¶
- {User action / business outcome 1}
- {User action / business outcome 2}
Technical¶
- All AL objects compile without errors
- Events are properly published and subscribed
- Permission sets cover all new objects
- No hardcoded values (use Setup table or constants)
Quality¶
- Unit tests cover all main scenarios (Given/When/Then defined above)
- Code review passed by @AL Code Review Subagent
- Translation keys defined for all new Captions
12. Open Questions¶
| # | Question | Owner | Status |
|---|---|---|---|
| 1 | {Question requiring human decision} | Human | Open |
Next Steps¶
Complexity: ${input:Complexity}
MEDIUM / HIGH:
✅ Spec complete. Next: 1. Human reviews and approves this spec 2. Start TDD orchestration:
Conductor will read this spec + architecture.md and orchestrate planning → implementation → review.LOW:
✅ Spec complete. Next: 1. Human reviews and approves this spec 2. Direct implementation:
Developer reads this spec and implements directly (no TDD orchestration needed). ```
Handoff¶
| Complexity | Handoff to | Purpose |
|---|---|---|
| MEDIUM / HIGH | @AL Development Conductor | TDD-orchestrated implementation (planning → implementation → review) |
| LOW | @AL Implementation Specialist | Direct implementation using this spec as blueprint |
Success Criteria¶
- ✅ Spec file created at
.github/plans/${input:req_name}/${input:req_name}.spec.md - ✅ Object IDs verified against
app.jsonidRanges - ✅ Architecture document consulted (if exists)
- ✅ All AL signatures are complete (no "TBD" in procedure signatures)
- ✅ Test scenarios defined in Given/When/Then format
- ✅ Handoff section points to correct next agent per complexity