agentleFS
MicrosoftKnown publishermicrosoft/powerplatform-build-tools/.claude/skills/architecture/SKILL.md

architecture

Skill314 starsChanged 7 months agoMITView on GitHub

Architecture map, layer responsibilities, key files, auth types, and debug runbook by symptom.

  • Installs packages

136 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use intelligent-routing, bash-linux and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • SKB3002Skill

    intelligent-routing

    Automatic agent selection and intelligent task routing. Analyzes user requests and automatically selects the best specialist agent(s) without requiring explicit user mentions.

    Also in 6 projects that use this

  • xenitV1Skill

    bash-linux

    Bash/Linux terminal patterns. Critical commands, piping, error handling, scripting. Use when working on macOS or Linux systems.

    Also in 8 projects that use this

  • xenitV1Skill

    red-team-tactics

    Red team tactics principles based on MITRE ATT&CK. Attack phases, detection evasion, reporting.

    Also in 8 projects that use this

  • SKB3002Skill

    nextjs-react-expert

    React and Next.js performance optimization from Vercel Engineering. Use when building React components, optimizing performance, eliminating waterfalls, reducing bundle size, reviewing code for performance issues, or implementing server/client-side optimizations.

    Also in 3 projects that use this

  • +8 more from xenitV1

The file

Show its rules and text

We split this skill into the rules it gives an agent

20 rules. 0 are common, 7 are distinctive, and 13 are very specific to this project.

  • 0

    Common

    Most of the 118 edited versions we read keep these.

  • 7

    Distinctive

    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
  1. Distinctive:

    Use this skill to understand the codebase architecture, trace issues across repos, or debug failures.

    line 9
  2. Distinctive:

    If given a specific error or symptom, use the architecture map below to identify which layer is failing and follow the targeted debug steps …

    line 10
  3. Very specific:

    Check ~/.npmrc has a valid GitHub token: //npm.pkg.github.com/:_authToken=<token>

    line 166
  4. Very specific:

    Test auth: curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token <token>" …

    line 167
  5. Very specific:

    Run with verbose to find where it hangs: npm install --verbose 2>&1

    line 168
  6. Very specific:

    Check npm debug log: cat C:/.tools/.npm/_logs/<latest>-debug-0.log | tail -100

    line 169
  7. Very specific:

    All tasks require tool-installer to run first — it sets POWERPLATFORMTOOLS_PACCLIPATH

    line 180
  8. Very specific:

    Check CliLocator.ts for the exact path resolution logic

    line 181
  9. Distinctive:

    Check service connection credentials in Azure DevOps (Pipelines → Service Connections)

    line 186
  10. Distinctive:

    Verify the auth type: SPN vs Username/Password vs Workload Identity

    line 187
  11. Very specific:

    Check cloudInstance — wrong cloud (e.g.

    line 188
  12. Very specific:

    Check getCredentials.ts — resolveCloudInstance() maps the endpoint URL hostname to cloud name

    line 189
  13. Distinctive:

    Check the exact pac command being run in the build log (each arg is logged)

    line 195
  14. Very specific:

    Verify environment URL: getEnvironmentUrl.ts has a 4-level fallback — add explicit Environment input to the task to override

    line 197
  15. Distinctive:

    Verify the service connection URL matches the actual cloud (Public vs USGov vs China)

    line 218
  16. Distinctive:

    Check if the tenant's AAD authority endpoint is reachable from the build agent (network/proxy issues)

    line 219
  17. Very specific:

    Workaround: Ensure build agent uses English locale (en-US).

    line 226
  18. Very specific:

    Workaround: Check pac CLI version — update nuget.json to latest pac CLI.

    line 234
  19. Very specific:

    Update version in nuget.json

    line 243
  20. Very specific:

    Run gulp restore (or npm run prepare-pack) to download the new binary to bin/

    line 245

“Common” is measured: kept by at least 6 in 10 of the 118 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Architecture & Debug Guide

Use this skill to understand the codebase architecture, trace issues across repos, or debug failures. If given a specific error or symptom, use the architecture map below to identify which layer is failing and follow the targeted debug steps for that layer.


Repo Dependency Map

powerplatform-build-tools  (THIS REPO — Azure DevOps Extension)
        │
        │  npm import (bundled)
        ▼
@microsoft/powerplatform-cli-wrapper  (TypeScript action library)
        │
        │  child_process.spawn()
        ▼
pac CLI binary  (pac.exe / pac — .NET, downloaded from NuGet at build time)
        │
        │  HTTPS REST
        ▼
Power Platform API  (Dataverse / crm.dynamics.com)

Layer Responsibilities

LayerOwnsDoes NOT own
build-toolsAzure DevOps task inputs, service connections, pipeline variables, artifact upload, task.jsonPower Platform logic, pac CLI args
cli-wrapperpac CLI argument assembly, auth flow, subprocess spawn/captureAzure DevOps APIs, pipeline variables
pac CLIPower Platform REST APIs, auth token management, all pac command semanticsNode.js, npm, Azure DevOps
Power Platform APIDataverse operations, solution lifecycleEverything above

Full Call Chain (export-solution as example)

Azure DevOps Pipeline
  │  task inputs: SolutionName, SolutionOutputFile, authenticationType, Environment
  ▼
src/tasks/export-solution/export-solution-v2/index.ts
  ├── TaskParser.getHostParameterEntries(taskDefinitionData)
  │     └── reads task.json → Record<string, HostParameterEntry>
  ├── getCredentials()
  │     ├── tl.getInput("authenticationType")  → "PowerPlatformSPN" | "PowerPlatformEnvironment"
  │     ├── tl.getEndpointAuthorization(endpointName)
  │     └── returns AuthCredentials { appId, clientSecret, tenantId, cloudInstance }
  ├── getEnvironmentUrl()
  │     └── checks (in order): task input → pipeline variable → env var → service connection URL
  │
  └── exportSolution(params, new BuildToolsRunnerParams(), new BuildToolsHost())
        │           ↑                    ↑
        │    runnersDir from          getInput() wraps
        │    POWERPLATFORMTOOLS_      tl.getInput()
        │    PACCLIPATH env var
        ▼
cli-wrapper: src/actions/exportSolution.ts
  ├── createPacRunner(runnerParams)   → CommandRunner (spawn wrapper)
  ├── authenticateEnvironment(pac, credentials, environmentUrl)
  │     └── pac("auth", "create", "--environment", url, "--applicationId", id,
  │               "--clientSecret", base64secret, "--tenant", tenantId, "--cloud", "Public")
  ├── InputValidator.pushInput(args, "--name", params.name)       → host.getInput(entry)
  ├── InputValidator.pushInput(args, "--path", params.path, resolveFolder)
  ├── InputValidator.pushInput(args, "--managed", params.managed)
  │   ... (assembles full arg list)
  │
  ├── pac("solution", "export", "--name", "MySolution", "--path", "/out/sol.zip", ...)
  │     ▼
  │   CommandRunner.ts: child_process.spawn("pac.exe", args, { env: { PP_TOOLS_AUTOMATION_AGENT: ... } })
  │     ├── stdout lines → logger.log()   → Azure DevOps build log
  │     ├── stderr lines → logger.error() → Azure DevOps build log
  │     └── exit 0 → resolve() | exit ≠ 0 → reject(RunnerError) → task fails
  │
  └── clearAuthentication(pac)
        └── pac("auth", "clear")

Key Files by Layer

build-tools (this repo)

FilePurpose
src/tasks/<name>/<name>-v2/index.tsTask entry point — reads inputs, calls cli-wrapper action
src/tasks/<name>/<name>-v2/task.jsonDeclares all task inputs, metadata, and execution config — execution handler is Node20_1 (primary) + Node16 (fallback)
src/host/BuildToolsHost.tsImplements IHostAbstractions — wraps tl.getInput(), artifact store
src/host/BuildToolsRunnerParams.tsImplements RunnerParameters — pac path, logger, agent string
src/host/CliLocator.tsFinds pac.exe/pac binary path by platform (win32 vs linux)
src/host/logger.tsImplements cli-wrapper's Logger interface — routes to tl.warning/error/debug and console.log
src/host/PipelineVariables.tsDefines output pipeline variable names (BuildTools.EnvironmentUrl, BuildTools.EnvironmentId, etc.) — used by create-environment and others
src/params/auth/getCredentials.tsExtracts auth from service connection — handles PowerPlatformEnvironment (UsernamePassword), PowerPlatformSPN (SPN or WIF, detected by authorization.scheme)
src/params/auth/getEnvironmentUrl.tsResolves target environment URL (4-level fallback chain)
src/parser/TaskParser.tsConverts task.json inputs array → Record<string, HostParameterEntry>
extension/extension-manifest.jsonAzure DevOps extension metadata
extension/task-metadata.jsonTask GUIDs per stage (LIVE / BETA / DEV / EXPERIMENTAL)
extension/service-connections.jsonPower Platform SPN endpoint definition
nuget.jsonpac CLI version pinned here — update to upgrade pac
webpack.config.jsFinds all task index.ts files, compiles each to dist/tasks/*/index.js
gulp/pack.mjsStages artifacts, injects task IDs per stage, runs tfx-cli to create VSIX

cli-wrapper (inside node_modules/@microsoft/powerplatform-cli-wrapper)

FilePurpose
dist/actions/exportSolution.tsAssembles pac args, calls pac, handles auth
dist/actions/importSolution.tsSame pattern for import
dist/actions/*.tsOne file per pac command
dist/pac/createPacRunner.tsResolves pac.exe path, returns CommandRunner
dist/pac/auth/authenticate.tsBuilds pac auth create / pac auth clear calls
dist/CommandRunner.tschild_process.spawn() wrapper — stdout/stderr capture, exit code handling
dist/host/InputValidator.tsPulls values through IHostAbstractions, normalizes, pushes to arg array

Authentication Types & Environment Variable Map

Auth TypeService Connection SchemeCredentials Passed to pac
Username/PasswordPowerPlatformEnvironment--username --password (base64)
Service PrincipalPowerPlatformSPN--applicationId --clientSecret (base64) --tenant
Workload Identity FederationPowerPlatformSPN + WIF scheme--applicationId --tenant --azureDevOpsFederated (via OIDC token env vars)

Note: Managed Identity is NOT supported through PPBT. getCredentials.ts only handles the three types above. WIF is detected when authorization.scheme === "WorkloadIdentityFederation" inside the PowerPlatformSPN branch — PPBT sets PAC_ADO_ID_TOKEN_REQUEST_URL / PAC_ADO_ID_TOKEN_REQUEST_TOKEN env vars and pac CLI handles the OIDC exchange.

Environment variables used by tasks:

VariableSet byUsed by
POWERPLATFORMTOOLS_PACCLIPATHtool-installer taskAll other tasks (to find pac.exe)
BuildTools.EnvironmentUrlcreate-environment taskAll other tasks (fallback env URL)
agent.diagnosticAzure DevOps agentAll tasks (enables --log-to-console on pac)
PP_TOOLS_AUTOMATION_AGENTCommandRunner.tspac CLI (user-agent telemetry)

Bundled Dependency Notes (affects vulnerability fixes)

These packages are in bundleDependencies — they ship inside the VSIX and their nested transitive deps are marked inBundle: true in package-lock.json. npm overrides cannot reach them. Lock file must be patched directly.

Bundled PackageKey nested depKnown issue
azure-pipelines-task-lib@5.2.8—No known issues (upgraded from 4.x which had minimatch@3.0.5 ReDoS)
@microsoft/powerplatform-cli-wrapper@0.1.135minimatch@10.x via glob@11Patched to 10.2.4 in lock file
fs-extra—No known issues
semver—No known issues

Debug Runbook by Symptom

npm install hangs indefinitely

Cause: npm re-resolves the full dependency tree when a new uncached package version is introduced. During re-resolution it hits npm.pkg.github.com for @microsoft/* packages.

  1. Check ~/.npmrc has a valid GitHub token: //npm.pkg.github.com/:_authToken=<token>
  2. Test auth: curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token <token>" https://npm.pkg.github.com/@microsoft%2fpowerplatform-cli-wrapper → should return 200
  3. Run with verbose to find where it hangs: npm install --verbose 2>&1
  4. Check npm debug log: cat C:/.tools/.npm/_logs/<latest>-debug-0.log | tail -100
  5. If log shows 50,000+ placeDep ROOT minimatch lines → infinite loop from a conflicting flat minimatch override. Remove it.

npm install errors with registry auth

Cause: GitHub PAT expired or missing scopes.

  1. Token needs read:packages scope on github.com
  2. Token goes in ~/.npmrc as //npm.pkg.github.com/:_authToken=<token>
  3. The project .npmrc sets @microsoft:registry=https://npm.pkg.github.com/ and always-auth=true

Task fails: "pac.exe not found" or "POWERPLATFORMTOOLS_PACCLIPATH not set"

Cause: tool-installer task did not run before this task, or failed silently.

  • All tasks require tool-installer to run first — it sets POWERPLATFORMTOOLS_PACCLIPATH
  • Check CliLocator.ts for the exact path resolution logic
  • On Linux: pac binary needs execute permissions — CliLocator.ts sets them via chmod

Task fails: "auth create failed" or authentication errors

Layer: cli-wrapper authenticate.ts or pac CLI auth

  1. Check service connection credentials in Azure DevOps (Pipelines → Service Connections)
  2. Verify the auth type: SPN vs Username/Password vs Workload Identity
  3. Check cloudInstance — wrong cloud (e.g. sending to Public when env is UsGov) causes auth failure
  4. Check getCredentials.ts — resolveCloudInstance() maps the endpoint URL hostname to cloud name
  5. Enable diagnostics: set agent.diagnostic=true variable in pipeline → adds --log-to-console to pac

Task fails: "Solution not found" or pac CLI errors

Layer: pac CLI → Power Platform API

  1. Enable --log-to-console: set system.debug=true in pipeline variables
  2. Check the exact pac command being run in the build log (each arg is logged)
  3. The error is from pac.exe — check Power Platform documentation for that specific pac command
  4. Verify environment URL: getEnvironmentUrl.ts has a 4-level fallback — add explicit Environment input to the task to override

Build fails: TypeScript errors after upgrading packages

Layer: build-tools compile step

  1. npm run build → webpack + ts-loader
  2. TypeScript target is ES5, module is CommonJS (tsconfig.json)
  3. gulp-typescript is on ^6.0.0-alpha.1 — type errors may surface after TS version upgrades
  4. cli-wrapper interface changes break at compile time here — check IHostAbstractions and RunnerParameters

VSIX package has wrong task GUIDs / tasks conflict in marketplace

Layer: gulp/pack.mjs

  1. Task GUIDs per stage are in extension/task-metadata.json
  2. LIVE uses the canonical GUIDs; BETA/DEV/EXPERIMENTAL get unique GUIDs so they don't conflict
  3. pack.mjs substitutes GUIDs at pack time — verify the substitution logic if tasks show up under wrong IDs

Task fails: "Can't resolve AAD/OAuth authority"

Source: IcM recurring pattern (ADO #4863652) Layer: pac CLI auth → Power Platform API

  1. Usually caused by incorrect cloudInstance value — check getCredentials.ts → resolveCloudInstance()
  2. Verify the service connection URL matches the actual cloud (Public vs USGov vs China)
  3. Check if the tenant's AAD authority endpoint is reachable from the build agent (network/proxy issues)
  4. Enable diagnostics: set agent.diagnostic=true in pipeline variables for verbose pac auth logging

Task fails: WhoAmI error in non-English build agent context

Source: ADO #4846644 (long-term, no code fix yet) Cause: whoAmI.ts in cli-wrapper parses localized pac CLI output to extract the environment ID. Fails when the build agent OS locale is non-English. Workaround: Ensure build agent uses English locale (en-US). Set LANG=en_US.UTF-8 on Linux agents. Layer: cli-wrapper src/actions/whoAmI.ts ~line 40 — fix must go upstream to cli-wrapper repo.

Import solution fails with PVA (Power Virtual Agents) components

Source: IcM 604312672, ADO #4896777 Symptom: import-solution task fails when solution contains PVA components. Layer: pac CLI → Power Platform API (not a build-tools code issue) Workaround: Check pac CLI version — update nuget.json to latest pac CLI. If persists, raise with PAC CLI team.

Extension not working on Azure DevOps Server 2020 (on-prem)

Source: ADO #5130362 Official stance: Extension is not supported on Azure DevOps Server 2020 on-prem. Action: Deflect IcM tickets. Direct customers to Azure DevOps Services (cloud) or Server 2022+.

New pac CLI version needed

  1. Update version in nuget.json
  2. The pac version is also referenced in package.json for documentation — keep in sync
  3. Run gulp restore (or npm run prepare-pack) to download the new binary to bin/
  4. Test with bin/pac/pac.exe --version

Vulnerability in a bundled dependency

Cause: Packages in bundleDependencies have inBundle: true in lock file. npm audit fix and overrides cannot touch them. Fix procedure:

# 1. Get safe version metadata
npm view <package>@<safe-version> dist.tarball dist.integrity --json

# 2. Find the exact key in package-lock.json
#    (may be nested: node_modules/foo/node_modules/bar)
node -e "const l=require('./package-lock.json'); console.log(Object.keys(l.packages).filter(k=>k.includes('<package>')))"

# 3. Patch the lock file entry: update version, resolved URL, integrity hash

# 4. Apply
npm install
npm audit  # verify resolved

Task Pipeline Dependency Order

tool-installer          ← MUST run first (sets POWERPLATFORMTOOLS_PACCLIPATH)
      │
      ├── create-environment  → sets BuildTools.EnvironmentUrl pipeline variable
      │         │
      │         ├── import-solution
      │         ├── export-solution
      │         ├── pack-solution / unpack-solution
      │         ├── publish-customizations
      │         ├── set-solution-version
      │         └── deploy-package
      │
      ├── backup-environment → restore-environment
      ├── copy-environment
      └── delete-environment

Build Output Structure

npm run build
  └── webpack → dist/tasks/<task-name>/<task-name>-v2/index.js  (32 bundles)

npm run prepare-pack
  ├── webpack (above)
  └── gulp restore → bin/pac/pac.exe + bin/pac_linux/pac

npm run pack
  └── gulp pack
        ├── npm pack → out/npm-package/
        ├── stages to out/staging/ (dist/ + bin/ + extension/)
        ├── injects GUIDs from task-metadata.json (4 stages)
        └── tfx-cli → out/packages/
              ├── PowerPlatform-BuildTools-<ver>-LIVE.vsix
              ├── PowerPlatform-BuildTools-<ver>-BETA.vsix
              ├── PowerPlatform-BuildTools-<ver>-DEV.vsix
              └── PowerPlatform-BuildTools-<ver>-EXPERIMENTAL.vsix

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.