Turn a Business Central performance profile into a list of things to fix.
al-perf reads .alcpuprofile captures and finds the anti-patterns you already know
are expensive: CalcFields inside a loop, missing SetLoadFields, records modified
one at a time, FindSet with no filter, Commit in a loop, filters no table key
can serve. Point it at your AL source and it names the file, procedure, line, and
table, reads your keys and CalcFormulas (a SUM FlowField scores worse than a
lookup), and knows a temporary table never touches SQL so it stops raising false
alarms.
Findings carry the SQL behind them, keep a stable identity across runs, file themselves as GitHub or Azure DevOps issues, and close when the problem stops appearing. Or fail the build on a pull request that introduces an N+1.
Works as a CLI, web app, MCP server (ask your AI assistant why posting got slow), or library.
bunx al-perf analyze profile.alcpuprofile --source ./src- Install
- Quick Start
- CLI Reference
- Web Server
- MCP Server
- Library API
- Docker
- Pattern Reference
- Development
- License
# npm / bun
bun add al-perf
# From source
git clone https://github.com/SShadowS/al-perf.git
cd al-perf
bun installRequires Bun >= 1.0.0.
# Analyze a profile
al-profile analyze profile.alcpuprofile
# With AL source correlation
al-profile analyze profile.alcpuprofile --source ./al-src
# Quick top-5 hotspots
al-profile hotspots profile.alcpuprofile
# Compare before/after
al-profile compare before.alcpuprofile after.alcpuprofile
# CI/CD quality gate (exits 1 on critical patterns)
al-profile gate profile.alcpuprofile --max-critical 0| Command | Description |
|---|---|
analyze <profile> |
Full analysis — hotspots, patterns, app/object breakdowns |
hotspots <profile> |
Quick top-N hotspot summary |
compare <before> <after> |
Before/after diff — regressions and improvements |
explain <profile> <method> |
Deep dive into a single method — callers, callees, times |
analyze-source <path> |
Static analysis of AL source files (no profile needed) |
source-map <profile> |
Map profile methods to source file locations |
gate <profile> |
CI/CD quality gate — pass/fail against thresholds |
mcp |
Start the MCP server (stdio transport) |
Common flags:
-f, --format <type> Output format: terminal, json, markdown, auto (default: auto)
-t, --top <n> Number of hotspots to show (default: 10)
-s, --source <path> Path to AL source files for correlation
--cache Cache the source index for faster re-analysis
--explain Append AI-powered explanation (requires ANTHROPIC_API_KEY)
--model <name> AI model: sonnet (default), opus
Upload .alcpuprofile files through a browser for instant analysis.
bun run web
# → http://localhost:3010Accepts optional source .zip files for correlation. If ANTHROPIC_API_KEY is set, results include an AI-generated explanation.
Expose all analysis tools to AI agents (Claude Code, Cursor, etc.):
{
"mcpServers": {
"al-profiler": {
"command": "bun",
"args": ["run", "src/mcp/index.ts"]
}
}
}Tools: analyze_profile · get_hotspots · compare_profiles · explain_method · analyze_source · gate_check
Resources: pattern-docs · last-analysis
import { analyzeProfile, compareProfiles } from "al-perf";
const result = await analyzeProfile("profile.alcpuprofile", {
top: 10,
includePatterns: true,
sourcePath: "./al-src",
});
for (const p of result.patterns) {
console.log(`[${p.severity}] ${p.title}: ${p.suggestion}`);
}docker build -t al-perf .
docker run -p 3010:3010 al-perf
# With AI explanation
docker run -p 3010:3010 -e ANTHROPIC_API_KEY=sk-ant-... al-perf| Pattern | Severity | Description |
|---|---|---|
| High Hit Count | warning | Methods called excessively |
| Repeated Siblings | critical | Same method called repeatedly at same call site |
| Single Method Dominance | critical | One method consumes >50% of total time |
| Deep Call Stack | warning | Call chains deeper than 30 levels |
| Event Subscriber Hotspot | warning | Event subscribers consuming significant time |
| Pattern | Severity | Description |
|---|---|---|
| CalcFields in Loop | critical | CalcFields/CalcSums called inside loops |
| Modify in Loop | critical | Modify/ModifyAll called inside loops |
| Record Op in Loop | critical | FindSet/FindFirst/Get inside loops |
| Missing SetLoadFields | warning | Find operations without SetLoadFields |
| Pattern | Severity | Description |
|---|---|---|
| Nested Loops | warning | Loops nested inside other loops |
| Unfiltered FindSet | warning | FindSet without SetRange/SetFilter |
| Event Subscriber Issues | info | Event subscribers containing loops or record ops |
bun install # Install dependencies
bun test # Run all tests
bun test <file> # Run a single test file
bunx tsc --noEmit # Type check
bun run build # Generate .d.ts declarations
bun run web # Start the web server
bun run format # Format with Biome
bun run lint # Lint with Biome
bun run check # Biome check + autofix
bun run verify # Biome check + tsc + tests (pre-commit gate)POC endpoints for the auto-ship pipeline (see docs/superpowers/specs/2026-04-13-continuous-monitoring-design.md and the POC scope spec).
Run with:
AL_PERF_POC_SECRET="<shared bearer secret>" PORT=3010 bun run web/server.tsEndpoints:
POST /api/tenants/register— register a tenant (POC: shared-secret-in-body).POST /api/ingest— encrypted ingest from al-perf-bc.GET /api/profiles/{activityId}?tenant=<code>— return ciphertext bundle + manifest sidecar.
POC limitations: v0/v1 only — single tenant, plaintext bearer auth, no rotation, no idempotency record persistence. See docs/superpowers/specs/2026-04-13-poc-scope.md.