Debugging and Error Recovery
addyosmani/agent-skills
Applies a stop-the-line rule and a step-by-step triage when tests fail, builds break or something stops working, aiming at the root cause instead of guesses.
A skill your agent uses when the user has finished building a mobile app, started Metro with npm run dev, and wants the running app monitored for runtime errors AND silent failures (empty lists…
$ npx skills add microsoft/power-platform-skills --skill debug-app -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install microsoft/power-platform-skills debug-app --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/mobile-apps/skills/debug-app .claude/skills/debug-app && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "debug-app" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/skills/debug-app into .claude/skills/debug-app/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "debug-app", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/skills/debug-appType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add microsoft/power-platform-skills --skill debug-app -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install microsoft/power-platform-skills debug-app --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/plugins/mobile-apps/skills/debug-app .agents/skills/debug-app && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "debug-app" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/skills/debug-app into .agents/skills/debug-app/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "debug-app", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add microsoft/power-platform-skills --skill debug-app -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install microsoft/power-platform-skills debug-app --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/plugins/mobile-apps/skills/debug-app .cursor/skills/debug-app && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "debug-app" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/skills/debug-app into .cursor/skills/debug-app/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "debug-app", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/microsoft/power-platform-skills.git --path plugins/mobile-apps/skills/debug-app--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add microsoft/power-platform-skills --skill debug-app -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install microsoft/power-platform-skills debug-app --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/plugins/mobile-apps/skills/debug-app .gemini/skills/debug-app && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "debug-app" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/skills/debug-app into .gemini/skills/debug-app/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "debug-app", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install microsoft/power-platform-skills debug-appInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add microsoft/power-platform-skills --skill debug-app -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/plugins/mobile-apps/skills/debug-app .github/skills/debug-app && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "debug-app" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/skills/debug-app into .github/skills/debug-app/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "debug-app", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add microsoft/power-platform-skills --skill debug-app -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install microsoft/power-platform-skills debug-app --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/microsoft/power-platform-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/plugins/mobile-apps/skills/debug-app .opencode/skills/debug-app && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "debug-app" agent skill from https://github.com/microsoft/power-platform-skills/tree/main/plugins/mobile-apps/skills/debug-app into .opencode/skills/debug-app/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "debug-app", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
debug-appA skill your agent uses when the user has finished building a mobile app, started Metro with npm run dev, and wants the running app monitored for runtime errors AND silent failures (empty lists…
Debug App is an agent skill from microsoft/power-platform-skills, published by the product's own GitHub organization. Use when the user has finished building a mobile app, started Metro with npm run dev, and wants the running app monitored for runtime errors AND silent failures (empty lists, blank screens, swallowed network errors) and fixed autonomously. Accepts a free-text symptom (e.g., /debug-app "todos not appearing on home screen") to drive persisted-log diagnostics — injects temporary console.log statements at data-path boundaries, reads the sanitized .powernative/metro-logs/ log, and cleans up logs after the root cause…
Its SKILL.md is about 22k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering Root cause analysis. It works with npm. The repository describes itself as: A plugin marketplace for GitHub Copilot and other AI agents that provides Power Platform development plugins, including reusable skills, agents, and commands for building and… The licence is MIT.
2 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 5ef4e4f. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
ReadEditWriteGrepGlobBashAskUserQuestionWebFetchmcp__plugin_mobile-app_microsoft-learn__microsoft_docs_searchFrom allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
npmnodenpxcursorexpogitFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
docs.expo.devFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
REDACTED_SECRETFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Debug App loads about 22k tokens when it runs. Until then it costs about 230 tokens; SKILL.md has 10,499 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
allowed-tools: Read, Edit, Write, Grep, Glob, Bash, AskUserQuestion, WebFetch, mcp__plugin_mobile-app_microsoft-leaAutomated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from microsoft/power-platform-skills at commit 5ef4e4f, republished under its MIT licence (© microsoft). 10,499 words, ~22,280 tokens.
.claude/skills/debug-app/SKILL.md (or your agent's skills folder).Plugin check: Run
node "${PLUGIN_ROOT}/scripts/check-version.js"- if it outputs a message, show it to the user before proceeding.
📋 Shared instructions: shared-instructions.md — read first.
Monitor the running app through the project-local .powernative/metro-logs/ files written by metro.config.js, detect runtime and bundle errors, and fix them autonomously by editing the affected files (or routing to the right skill when the fix belongs in a domain like Dataverse schema or auth registration). For silent failures, inject temporary console.log statements at data-path boundaries, read only newly appended log bytes, then clean the traces after the root cause is fixed. Modeled on the upstream app-debugger.agent.md pattern — foreground loop, bounded polling, configurable clean-check/timeout exits, and optional watch-only operation.
Dev-client limitation: the standalone dev client sends app/runtime logs, React errors, host diagnostics, and Metro bundler output through Metro. The template's
metro.config.jswrites Metro terminal output and HTTP bundle failures into.powernative/metro-logs/; there is no separate device log source. Host diagnostics include strings such as[AuthProvider] MSAL init failed:,[bridge] fetch THREW for,[bridge] HTTP <status> for,[addAadAppToConnectionAcl] failed HTTP <status> for connection,[useConnectionRefs] could not verify connection ACLs; treating existing connections as setup-required, and[PAHost][ErrorBoundary] Unhandled JS error:.
$ARGUMENTS)| Form | Behavior |
|---|---|
/debug-app (no args) | Default — project-log-driven mode. Run Phase 0, discover valid project-local Metro sessions, select automatically when one is live or ask when several are live, then monitor the selected log. No host terminal ID is required. |
/debug-app "<symptom text>" | Symptom-driven mode (recommended when there's a user-visible problem). Free-text symptom such as "todos not appearing on home screen", "login button does nothing", "list empty after refresh". Run Phase 0 → Phase 0.5 (parse symptom → ask the user to reproduce/navigate → walk the likely data path from terminal traces) → enter monitor loop. Catches silent failures (empty lists, blank screens, swallowed errors) that pure log polling misses. |
/debug-app status | Discover all project-local Metro logs and print each valid session's project, platform, PID, port, start time, and log path. Mark the session referenced by the saved cursor when present, then print fixes and unresolved errors. Do NOT ask for a selection or enter the loop. |
/debug-app stop | Stop only the foreground debug loop and preserve .powernative/debug-app/ state. It does not stop Metro; the user owns the npm run dev process. |
/debug-app version | Print the installed mobile-app plugin name and version from ${PLUGIN_ROOT}/.plugin/plugin.json, then exit. |
Options may follow the default command, a symptom, or status:
| Option | Meaning | Default |
|---|---|---|
--working-dir <path> | App root containing package.json and metro.config.js. Relative paths resolve from the current shell directory. | Current shell directory |
--port <1-65535> | Monitor only the valid Metro session on this port. | Any port |
--platform <ios|android> | Consider only sessions whose recent log identifies this platform. | Any platform |
--cycles <1-50> | Exit after this many consecutive clean observation intervals. | 3 |
--timeout <duration> | Maximum wall-clock monitoring time. Accept 30s–60m using s, m, or h. | 5m |
--no-fix | Watch-only mode: classify and report, but never edit project source/config, inject traces, install dependencies, regenerate files, or invoke a mutating handoff. Debug cursor/audit/health state still advances. | Fix enabled |
Examples:
/debug-app --port 8082 --platform ios
/debug-app "orders screen is empty" --cycles 10 --timeout 15m
/debug-app --no-fix --timeout 30m
/debug-app status --platform android
/debug-app status --working-dir ../my-mobile-appArgument parsing:
status, stop, help, --help, -h, version, --version) selects the subcommand. stop, help, and version do not accept monitoring options. status accepts only --working-dir, --port, and --platform; reject symptoms, --cycles, --timeout, and --no-fix because it does not enter the loop.platform to lowercase. Convert timeout to timeoutSeconds; require 30 <= timeoutSeconds <= 3600. For monitoring and status, resolve workingDir to an absolute path from --working-dir or the current shell directory. Do not search parent directories. Require package.json and metro.config.js at that root; otherwise print the invalid path and stop before reading or writing project state. After validation, cd to workingDir once and reset it from the resulting absolute $PWD; every relative project path and command below runs from that directory.workingDir=<absolute app root>
portFilter=<number|none>
platformFilter=<ios|android|none>
targetCleanCycles=<number, default 3>
timeoutSeconds=<number, default 300>
noFix=<true|false, default false>
monitorStartedAt=<current ISO timestamp>For help / --help / -h, print the subcommands and monitoring-options tables and exit.
Early-return subcommands:
stop: if received while this foreground loop owns the conversation, clean up any injected traces using Phase 0.5.5 and exit at the next safe boundary. For a standalone stop invocation, report that no loop is active. Never stop Metro or delete .powernative/debug-app/ state.version / --version: read ${PLUGIN_ROOT}/.plugin/plugin.json, print <name> <version>, and exit without resolving a project or writing state. If the manifest is missing or malformed, report that the plugin version is unavailable and exit.status: validate workingDir, then execute only Phase 0.0 discovery through the status branch below. Do not run project preflight, create state files, ask for a session, initialize a baseline, or enter the monitor loop.Tip — "play around then debug": Metro persists recent app output in .powernative/metro-logs/ even across chat/editor restarts. If something weird just happened, keep using the app normally, then run /debug-app or /debug-app "<what you saw>". The first cycle reads the latest persisted log window; subsequent cycles read only bytes appended after the saved cursor.
targetCleanCycles consecutive clean polls confirm the app is healthy, timeoutSeconds elapses, the user types stop, or the escalation rule trips. Do not run other skills concurrently — they'll queue behind the loop.--no-fix, do not edit project source/configuration, inject diagnostic logs, install packages, regenerate schemas, switch accounts, or invoke a mutating skill. Continue to advance .powernative/debug-app/ cursor/audit/health state, classify errors, and provide the fix/handoff that would have been used.npm run dev and the simulator/device must have the app open. Phase 0 verifies that a live .powernative log exists; the skill stops cleanly if no app is detected..powernative/metro-logs/ is the authoritative log source for that native session.curl, fetch, WebFetch, or any direct request to a Metro/localhost endpoint for runtime diagnosis. Read only the .powernative log and source files..powernative/debug-app/: fixes.md, unresolved.md, injected-logs.md, health.json, and metro-cursor.json. Metro logs live in the already-ignored .powernative/metro-logs/. Both survive chat/editor restarts without binding state to a specific agent host..powernative, but /debug-app must independently minimize and sanitize every value before persisting it to .powernative/debug-app/. Never copy raw response bodies, record objects, tokens, headers, trace payloads, or absolute home-directory paths into debugger state.port-taken status means the log belongs to a dead session and must not be diagnosed.node_modules/@microsoft/power-apps-native-* is evidence, not proof, of package ownership. First rule out invalid app inputs, unsupported configuration, and misuse of the package's documented API. Once the evidence confirms a defect inside an installed @microsoft/power-apps-native-* package, do not apply a customer-project workaround: do not edit node_modules/, create a patch-package patch or postinstall rewrite, vendor or fork package source, redirect the package through Metro/Babel/TypeScript aliases, or replace its dependency with a git, tarball, or local fork. Record a sanitized package-defect report and route the user to /report-issue..powernative log cursor too.memory-bank.md when present. Read power.config.json for environment, Dataverse, and connector context. Consult native-app-plan.md only when the failure concerns a planned screen, data model, connector, offline profile, or native capability; do not parse it for unrelated syntax/runtime errors.mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search when behavior remains uncertain. For Expo/Expo Router/React Native errors: inspect installed versions and project code first, then use targeted WebFetch against official https://docs.expo.dev/ documentation. Use package documentation next and general web search only as a last resort.Before entering the monitor loop, write a task list and keep it up to date:
- [ ] Discover valid `.powernative` Metro sessions and select one when needed
- [ ] Capture baseline log state from the selected session and save its byte cursor
- [ ] (Symptom mode only) Phase 0.5: parse symptom → ask user to navigate → inject console.logs → read new log bytes → walk data path → clean up logs
- [ ] Monitoring cycle 1: collect → classify → fix if needed
- [ ] Monitoring cycle 2: collect → classify → fix if needed
- [ ] Monitoring cycle 3: collect → classify → fix if needed
(add cycles as needed; after <targetCleanCycles> consecutive clean cycles, use the resolved/flagged/pending symptom outcome)
- [ ] Fix: <error summary> → <inline edit | skill route> (one task per error found)Mark each cycle complete (clean OR fixed) before starting the next.
Before entering the loop:
Follow the shared instructions before diagnosing logs:
Use workingDir from argument parsing as <working_dir> throughout this workflow. It is already validated as an app root; do not derive it again from a later phase or silently switch projects.
<working_dir>/memory-bank.md exists, read its Project facts, Power Platform context, Data model, Connectors, Screens, Native capabilities, and Build history. Do not create a memory bank from /debug-app; absence is valid.<working_dir>/power.config.json when present. Capture environmentId, databaseReferences, and connectionReferences. power.config.json is the preferred environment source.<working_dir>/native-app-plan.md only when the supplied symptom or a classified error concerns a planned screen, Dataverse entity/column, connector, offline behavior, navigation contract, or native capability. Treat the plan as intended design, not proof of live schema/runtime state.src/generated/services/, src/generated/models/, and src/generated/connectorSchemas.ts only when the affected data path uses them. Never edit generated files.Append a compact context line to fixes.md after Phase 0.1 creates it:
[<HH:MM:SS>] Context — memory-bank=<present|absent> native-plan=<present|absent|not-needed> environment=<environmentId|none> dataverse-tables=<N> connectors=<N>Do not resolve the environment or call Dataverse during ordinary bundle, React, or local JavaScript failures. When a current symptom/error is Dataverse or Power Platform related, perform the read-only Dataverse diagnostic sequence in D2 before handing off.
Use the validated <working_dir> from argument parsing. Enumerate all matching logs, newest first:
LOG_DIR="<working_dir>/.powernative/metro-logs"
ls -t "$LOG_DIR"/metro-*-pid-*-port-*.log 2>/dev/nullFor every candidate, parse:
pid and port from metro-<timestamp>-pid-<pid>-port-<port>.log;startedAt from the filename timestamp;project from power.config.json.appDisplayName, falling back to the basename of <working_dir>;platform by scanning only the latest 64 KiB for the most recent iOS ... Bundled / iOS Bundling or Android ... Bundled / Android Bundling line; use unknown when neither appears.Check every recorded PID with a cross-platform Node probe: process.kill(pid, 0) means alive; treat EPERM as alive and other errors as gone. When port is numeric, verify ownership with lsof -nP -iTCP:<port> -sTCP:LISTEN -t on macOS/Linux when available, or netstat.exe -ano -p tcp on Git Bash/Windows. On Linux without lsof, use ss -ltnp when available. A candidate is valid/live only when its PID is alive and either owns the recorded port, has port=unknown, or no supported port-ownership probe exists. A probe that runs and reports a different PID is a contradiction, not an unavailable probe. Do not persist terminal IDs or depend on terminal output.
Selection rules:
portFilter and platformFilter to the valid/live candidates before selection. When no valid session matches, print the filters plus the available valid sessions and stop. If a platform-filtered candidate is unknown, do not guess; tell the user to use --port or omit --platform.<project> — <platform> — port <port> — pid <pid> — started <startedAt>AskUserQuestion; identify choices internally by the complete logPath + pid + port, not by port alone. If metro-cursor.json points to one of the valid sessions, make that session the default choice but still ask. Never silently choose the newest session when more than one is live.status branch — return before selection: After filtering and liveness checks, read .powernative/debug-app/metro-cursor.json only when it is nonempty valid JSON with string logPath, numeric pid, and numeric-or-unknown port. Treat a missing, empty, malformed, or shape-invalid cursor as absent and print a warning; never overwrite it from status. Print every valid session newest-first using the normal session display shape, marking [saved] only when logPath + pid + port match the valid cursor. Then print at most the last 20 nonempty lines from fixes.md and unresolved.md, passing the displayed text through the persistence redactor first. Print stale/contradictory candidate counts without diagnosing their log content, then exit. When no valid session exists, print that result plus the applicable no-log/stale reason and exit.
For monitoring modes only, select a session using the rules above. After selection, set LOG_PATH, pid, port, project, platform, and startedAt from the chosen candidate. This selection is sticky for the current monitor run.
When no log exists, inspect metro.config.js and resolve the logging module from <working_dir> before choosing a failure branch:
createPowerAppsMetroConfig from @microsoft/power-apps-native-host/config/metroConfig, and that exact subpath resolves from the project's installed dependencies. The factory installs project-local logging internally.@microsoft/power-apps-native-host/metro-logger, and that exact subpath resolves from the project's installed dependencies.@microsoft/power-apps-native-host is missing from package.json. A dependency version string alone does not prove that the configured export exists.Branch as follows:
| Status | Meaning | Action |
|---|---|---|
| Exactly one valid log exists, PID is alive, and either port is unknown or the port probe is unavailable | Select it. Capture project, platform, startedAt, port, pid, and logPath, then continue. | |
| Exactly one valid log exists and PID still owns the logged port | Select it. Capture project, platform, startedAt, port, pid, and logPath, then continue. | |
| Multiple valid logs exist | Show every valid session and ask which one to monitor. Do not select by recency alone. | |
| Log exists, PID is gone, and another process owns the logged port | Do NOT diagnose from this log. Tell the user which PID holds the port and ask them to restart npm run dev. | |
| Log exists but PID/port contradict each other | The device may be talking to the wrong server. Ask the user to stop stale Metro processes and rerun npm run dev. | |
| No log exists and the logging form is unavailable | This project predates project-local Metro logging or has incomplete dependencies. Stop and report the missing config form, dependency declaration, or resolvable export. Do not enter a restart loop or edit customer-owned config from /debug-app; the user must adopt the current template's Metro config and host dependency first. | |
| No log exists and the current factory or legacy direct logging form resolves | If available host output contains [powernative] Metro logging instrumentation failed, report its phase and project-relative log path; the host deliberately fails open, so Metro can remain live without a file. Otherwise tell the user Metro is not running or has not emitted .powernative logs. Ask them to run npm run dev, open the native app, then rerun /debug-app. |
The PID/port check prevents stale-log diagnosis: a log file can outlive its Metro process, so only the socket probe reveals that the log stopped belonging to the app under test. The explicit choice prevents a valid session on one port from being confused with another valid session in the same project.
If no .powernative log exists but the host exposes a live Metro terminal, that output may explain what is running, but do not ask for or store its terminal ID and do not enter the continuous monitor loop against it. Ask the user to restart with npm run dev so Metro config creates the log.
Record the stable source in fixes.md:
[<HH:MM:SS>] Log source — <project> <platform> — <logPath> (pid <pid>, port <port>, started <startedAt>)mkdir -p .powernative/debug-app
touch .powernative/debug-app/fixes.md
touch .powernative/debug-app/unresolved.md
touch .powernative/debug-app/injected-logs.md
touch .powernative/debug-app/health.json
touch .powernative/debug-app/metro-cursor.json
rm -f .powernative/debug-app/symptom-state # per-session — Phase 0.5 rewrites it if symptom mode is activeIf fixes.md is empty, write a session header:
# Debug session — <date>
Append the effective invocation settings:
[<HH:MM:SS>] Monitor config — port=<any|port> platform=<any|ios|android> clean-cycles=<targetCleanCycles> timeout=<timeoutSeconds>s no-fix=<true|false>Write .powernative/debug-app/health.json without raw log content:
{
"bundle": { "status": "unknown", "summary": "No evidence yet" },
"runtime": { "status": "unknown", "summary": "No evidence yet" },
"authentication": { "status": "unknown", "summary": "No evidence yet" },
"dataverse": { "status": "unknown", "summary": "No evidence yet" },
"connector": { "status": "unknown", "summary": "No evidence yet" },
"offline": { "status": "unknown", "summary": "No evidence yet" },
"navigation": { "status": "unknown", "summary": "No evidence yet" },
"nativeCapability": { "status": "unknown", "summary": "No evidence yet" },
"updatedAt": "<ISO timestamp>"
}Allowed statuses are healthy, degraded, failed, unknown, and not-configured. Update only the affected domain after each classified signal:
| Signal | Health update |
|---|---|
| Successful native bundle after the latest bundle error | bundle=healthy |
| Bundle/transform/import failure | bundle=failed |
| Uncaught JS/React error | runtime=failed; set healthy after the repaired workflow produces clean new output |
| Auth success/failure host diagnostics | `authentication=healthy |
| Dataverse 2xx/error for the affected operation | `dataverse=healthy |
| Connector resolution/call success or failure | `connector=healthy |
| No offline profile | offline=not-configured; offline activation/sync warning or failure → `degraded |
| Confirmed route/navigation error | navigation=failed; repaired route confirmation → healthy |
| Native wrapper success, permission denial, missing module, or native failure | `nativeCapability=healthy |
Absence of evidence remains unknown; never convert an unobserved domain to healthy.
Before appending diagnostic text to fixes.md or unresolved.md, or storing a health summary, sanitize it:
<working_dir>. Replace other absolute home-directory paths with [REDACTED_PATH].Authorization, Proxy-Authorization, Cookie, Set-Cookie, x-api-key, api-key, client-secret, and token headers) with [REDACTED_HEADER].sig, se, sp, sv, code, token, access_token, refresh_token, id_token, client_secret), passwords, and API keys with [REDACTED_SECRET].[REDACTED_EMAIL] and GUIDs/record identifiers with [REDACTED_ID] unless the identifier is a non-sensitive local PID/port.[TRACE] object values. Persist only status, source/config table or column names, counts, error codes, and a bounded error message.[REDACTION_BLOCKED: diagnostic omitted] instead.Run the bundled verifier for every candidate diagnostic before writing:
printf '%s' "$DIAGNOSTIC_SUMMARY" | node \
"${PLUGIN_ROOT}/scripts/redact-debug-diagnostic.js" \
--working-dir "<working_dir>"Persist only the verifier's stdout. Build DIAGNOSTIC_SUMMARY from minimal fields first; do not pass a full Metro window or response body and rely on redaction to make it safe.
Store logPath in metro-cursor.json relative to <working_dir> and resolve it against <working_dir> when reading. This gate is required even though .powernative logs are already sanitized.
Telemetry checkpoint: validate_metro_session
Read a bounded baseline window and return a real byte cursor:
node - "$LOG_PATH" 262144 <<'NODE'
const fs = require('node:fs');
const [file, maxText] = process.argv.slice(2);
const maxBytes = Number(maxText);
const size = fs.statSync(file).size;
const start = Math.max(0, size - maxBytes);
const fd = fs.openSync(file, 'r');
const buffer = Buffer.alloc(size - start);
const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, start);
fs.closeSync(fd);
process.stdout.write(JSON.stringify({
cursor: start,
nextCursor: start + bytesRead,
truncated: start > 0,
output: buffer.subarray(0, bytesRead).toString('utf8')
}, null, 2));
NODEThe logger initially writes port-unknown and may atomically rename that file to the numeric port. If the baseline read gets ENOENT, rediscover once before reporting failure. When the same filename timestamp and PID now exist with a numeric port, update LOG_PATH and port to that file and retry the bounded read once; do not process both names as separate sessions.
Parse output, cursor, nextCursor, and truncated; use the pid, port, and logPath resolved in Phase 0.0. Scan output:
SyntaxError, Unable to resolve module, transform failed, or error: Bundling failed → bundle is broken. Treat as a Step B "Import / Bundle" critical error and route through Step D immediately. Do NOT enter the steady-state loop until the bundle is healthy.Bundling complete / iOS Bundled / Android Bundled with no later error-class line → Metro is healthy. Proceed.Metro waiting on, Logs for your project, or › Metro:) but no native Bundled / bundling lines yet → Metro is up but no native client has connected. Tell the user:Metro is running but no app is connected yet. Open the app on a device or simulator, then re-run
/debug-app. Stop here.
/debug-app; do not guess readiness.If truncated: true, the baseline covers only the latest 256 KiB. Record that older history was omitted; do not claim the full session history was inspected.
Before initializing the cursor, pass all classifiable entries in this initial window through Step B, including JS runtime errors, React warnings, network/API failures, native errors, and host diagnostics. Do not advance past a prior error just because it is not a bundle error. This preserves the promise that users can "play around, then debug" after a symptom already occurred.
The baseline window is history, not current state. It can contain errors that were already fixed, that the user resolved themselves, or that were transient. Fixing those is worse than doing nothing: it edits working code to chase a symptom that no longer exists, and the "fix" is unverifiable because the error cannot reproduce.
So every error found in the baseline window only (not in later polls) is treated as unconfirmed until checked for supersession. Scan forward from the error line to the end of the window:
| Error class | Superseded when a later line shows |
|---|---|
| Import / Bundle | Bundling complete, iOS Bundled, or Android Bundled |
| Network / API | a 2xx for the same route/resource that previously failed |
| JS runtime / React | a later app reload or successful bundle, and the error does not reappear after it |
Host diagnostic ([AuthProvider], [bridge], …) | a later success from the same subsystem (e.g. a token acquired after acquireTokenSilent failed) |
Then:
[<HH:MM:SS>] Observed (already resolved, not fixed) — <error summary> — superseded by <evidence line>This applies to the baseline window only. Anything appearing in a later
tail --cursor poll is by definition new output and needs no supersession check.
Symptom mode overrides this. If the user supplied a symptom, that is first-hand evidence the problem is current, so a matching baseline error is treated as live even when a later line would otherwise look like supersession.
Telemetry checkpoint: capture_runtime_baseline
Use the output from Phase 0.2. Note the most recently bundled native platform (iOS / Android) and any recent runtime log lines. Append to fixes.md:
[<HH:MM:SS>] Baseline — last Metro activity: <1-line summary of most recent lines>Write .powernative/debug-app/metro-cursor.json using structured JSON:
{
"logPath": ".powernative/metro-logs/metro-<timestamp>-pid-12345-port-8081.log",
"pid": 12345,
"port": 8081,
"project": "My Mobile App",
"platform": "ios",
"startedAt": "2026-08-27T12:41:32.050Z",
"monitorStartedAt": "<ISO timestamp>",
"monitorConfig": {
"port": null,
"platform": null,
"targetCleanCycles": 3,
"timeoutSeconds": 300,
"noFix": false
},
"cursor": 12345,
"updatedAt": "<ISO timestamp>"
}Set project-relative logPath, plus pid, port, project, platform, and startedAt from Phase 0.0. Set monitorStartedAt and monitorConfig from the current invocation, and set cursor to nextCursor from Phase 0.2. Resolve logPath against <working_dir> before file access. A new invocation always replaces the prior monitoring configuration and start time. On later invocations:
Parse an existing cursor only when it is nonempty valid JSON with the expected field types. Treat a missing, empty, malformed, or shape-invalid file as no saved cursor, append a sanitized reset warning to fixes.md, and initialize from the selected session's bounded baseline. Never fail startup solely because prior debug state is partial.
Same logPath, pid, and port, with the process still owning the port → reuse the saved cursor so old errors are not processed again.
Multiple valid sessions → ask which session to monitor. Default to the saved session when it remains valid.
A different session is explicitly selected, or the saved session is no longer valid → discard the old cursor and initialize from the selected session's latest log window.
rotationLost: true from Step A → accept the returned reset cursor and record the file shrink/replacement in fixes.md.
$ARGUMENTS is a symptom string)Skip this entire phase if no symptom was provided. The standard log-polling loop alone is good at visible errors but blind to silent ones: an empty list because the connector wasn't added, a blank screen because useFocusEffect wasn't wired, blank rows because column names don't match the model. Phase 0.5 closes that gap.
--no-fix behavior: Parse the symptom and ask the user to reproduce it, but do not inject [INJECTED-TRACE] logs or edit any file. Read only new Metro output. If the symptom is silent and produces no classifiable output, write pending to symptom-state, append watch-only: traces not injected to unresolved.md, then enter the standard loop.
Extract three signals from the user's text:
| Signal | How to derive |
|---|---|
| Affected screen | Match keywords against route filenames in app/ (e.g., "todos" → app/(tabs)/todos.tsx, app/todos/index.tsx, app/(tabs)/index.tsx). Use Glob to enumerate app/**/*.tsx; pick the closest substring match. If multiple, ask once. |
| Affected entity / service | Same keyword against src/generated/services/*Service.ts and src/generated/models/*Model.ts (e.g., "todos" → TodosService, Todo model). Use Glob. |
| Symptom class | Map the text to one of: empty-list, blank-screen, wrong-data, unresponsive-control, stale-data, wrong-navigation, crash, pdf-viewer, pdf-report, pen-input, geolocation, dataverse-upload. Default for "PDF won't open / preview PDF fails": pdf-viewer. Default for "report PDF not generated / print report fails": pdf-report. Default for "signature / pen / ink fails": pen-input. Default for "location not tracking / GPS not updating / background location stopped / breadcrumb gaps / route not consistent": geolocation. Default for "signature/report saved but missing", or "location rows not reaching Dataverse": dataverse-upload. Default for "not appearing / not showing / nothing here / missing": empty-list. Default for "doesn't load / freezes / spinner forever": blank-screen. |
Append to fixes.md:
[<HH:MM:SS>] Symptom — class=<class> screen=<path> entity=<service>If no screen/entity match: keep screen=unknown / entity=unknown and proceed — Phase 0.5 still injects diagnostic logs and reads the terminal from whatever data path is most likely based on the symptom text.
The dev-player has no automation API for navigation. Ask the user:
"Please open the
<screen>screen on the device/simulator, then replyready."
Wait for the user to confirm before proceeding.
Inject targeted console.log statements at the boundaries of the suspected data path so the Metro terminal reveals what's happening.
Injection sites — choose the minimum set that covers the symptom class:
| Symptom class | Inject at |
|---|---|
empty-list | (a) entry point of the data-fetching hook, logging [TRACE items] the raw response length; (b) the screen component, logging [TRACE render] the items array length before the list renders |
blank-screen | Entry point of the screen component, logging [TRACE mount] with a timestamp plus only booleans or counts that describe whether required auth/data props are present |
wrong-data / stale-data | The hook that calls the generated service (NOT inside src/generated/), logging [TRACE service-response] with an allowlisted summary: result count, error presence, bounded error code/status, and expected-field presence booleans |
unresponsive-control | The event handler (onPress, onSubmit, etc.) logging [TRACE handler-called] before any async work |
crash | Skip injection — jump to the monitor loop (Step A), crash stacks appear in the terminal |
Console.log injection pattern — all injected lines MUST use this exact format:
console.log('[TRACE <tag>]', <value>); // [INJECTED-TRACE]<tag> — short unique label for this site (e.g., items, render, service-response)// [INJECTED-TRACE] trailing comment on the SAME LINE — this is the cleanup grep keyJSON.stringify is allowed only for that constructed summary.src/generated/ — inject in the hook/screen that calls into itRecord every injection in .powernative/debug-app/injected-logs.md:
[<HH:MM:SS>] Injected [INJECTED-TRACE] at <file>:<line> — tag=<tag>Then tell the user:
"I've added diagnostic console.log statements. Fast Refresh should apply them automatically. Navigate to
<screen>and trigger the symptom (for example, scroll the list or tap the button). If the app does not refresh, reload it from the native dev-client menu. Replydonewhen finished."
Wait for the user to reply, then run the Step A tail --cursor procedure, persist nextCursor, and filter the returned output for [TRACE lines.
Use the [TRACE lines to walk the chain:
Screen TSX (app/<route>.tsx)
useListData(...) / use*Data(...) call.top: 0, an over-strict filter, a search: query bound to a never-cleared input, or orderBy on a missing column can each silently return zero rows..filter(...) after the data lands.Data hook (src/hooks/useListData.ts or sibling)
{ error } → hook substitutes mock AND may call setError. Silent if the screen ignores error.{ data: [] } (no error) → hook silently substitutes mock. Always invisible without a [TRACE] log.Grep for MOCK_ imports in the screen file. If present, mock data is wired in.useFocusEffect is used (not useEffect) — useEffect won't re-run on back-navigate.Generated service (src/generated/services/<Name>Service.ts)
/add-connector or /add-dataverse. Do NOT edit src/generated/.[TRACE service-response] summary shows an error → use its bounded status/error code; 401/403 = auth issue; 404 = wrong resource name. Use separately emitted, already-sanitized host diagnostics for message context; do not add a raw error trace.Generated model (src/generated/models/<Name>Model.ts)
item.title vs cr3e9_title produces blank rows.power.config.json
datasources array contains the suspected entity / connector. If absent, npx power-apps add-data-source was never run for it.Auth state (src/playerConfig.ts, app.config.js, auth.config.json, useAuth() hook)
{ error } — the [TRACE service-response] summary surfaces the status without persisting the error object or message.app.config.js → expo.scheme matches src/playerConfig.ts → connectorOAuthRedirectUri, AND the same redirect URI is in auth.config.json and the Entra ID registration. If the app registration is missing, route the user to the Power Apps Wrap page via /set-app-registration-native.Classify the [TRACE output:
| Output | Meaning | Next step |
|---|---|---|
[TRACE items] 0 or [] — no error field | Service returned empty — check filter/query or data not seeded | Fix the query; if no records exist, seed sample data |
[TRACE items] undefined | Hook never received a response — likely service stub or missing datasource | Route to /add-connector or /add-dataverse |
[TRACE service-response] shows an error status/code | Service threw — 401/403 = auth; 404 = wrong resource | Fix auth config or re-run add-data-source |
[TRACE render] N > 0 but list looks empty | Field name mismatch between model and screen | Fix screen field references to match the model |
[TRACE handler-called] never appears | onPress not wired or component not mounted | Read TSX, fix the event binding |
No [TRACE lines at all | Metro may have cached the old bundle | Ask the user to stop Metro, rerun npm run dev -- --clear, then reload the native app |
Record the outcome in .powernative/debug-app/symptom-state (single line: resolved, flagged, or pending).
[TRACE items] line shows N > 0, write resolved.unresolved.md. Write flagged.unresolved.md. Write pending and enter the monitor loop.After the root cause is identified and a fix is applied (or Phase 0.5 concludes), remove ALL injected logs:
find app src -type f \( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \) \
! -path 'src/generated/*' -exec grep -nH 'INJECTED-TRACE' {} +For each matching file, edit out the console.log(...); // [INJECTED-TRACE] lines. Verify with:
find app src -type f \( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \) \
! -path 'src/generated/*' -exec grep -nH 'INJECTED-TRACE' {} + # must print zero matchesClear the tracking file:
echo '' > .powernative/debug-app/injected-logs.mdRun npm run type-check once after cleanup.
Hard rule: Never leave
[INJECTED-TRACE]lines in code. Clean up before marking the session done, even if the symptom ispendingorflagged.
After Phase 0.5 completes, fall through to the monitor loop (Step A). Count clean cycles normally, but let Step C choose the exit from the single-line symptom-state: resolved may exit green, while flagged and pending use their non-green exits after targetCleanCycles. Never report a green result for a flagged or pending symptom.
Repeat until targetCleanCycles consecutive clean cycles, timeoutSeconds elapses, the user types stop, OR the escalation rule trips.
Before every collection cycle and immediately after any fix verification, compare the current time with monitorStartedAt. When elapsed time is greater than or equal to timeoutSeconds:
[INJECTED-TRACE] lines before exit.fixes.md.⚠ Monitoring timeout reached after <duration>.
Session: <project> — <platform> — port <port> — pid <pid>
Clean checks: <clean>/<targetCleanCycles>
Details: .powernative/debug-app/fixes.mdTelemetry checkpoint: collect_runtime_logs
Read .powernative/debug-app/metro-cursor.json and rediscover all live .powernative sessions using Phase 0.0's validation logic.
logPath + pid + port is still valid, keep monitoring it even when a newer valid session has appeared. Do not interrupt the current run or jump ports.Otherwise collect newly appended bytes from the pinned session. When no bytes are already waiting, this foreground collector watches the log directory until that file changes or a full 5-second observation interval completes:
node - "$LOG_PATH" <saved-cursor> 262144 5000 <<'NODE'
const fs = require('node:fs');
const path = require('node:path');
const [file, cursorText, maxText, observationText] = process.argv.slice(2);
const cursor = Number(cursorText);
const maxBytes = Number(maxText);
const observationMs = Number(observationText);
const observedAt = Date.now();
let watcher;
let timer;
let finished = false;
function snapshot(observation) {
try {
const size = fs.statSync(file).size;
const start = Number.isInteger(cursor) && cursor >= 0 && cursor <= size ? cursor : 0;
const fd = fs.openSync(file, 'r');
const buffer = Buffer.alloc(Math.min(maxBytes, Math.max(0, size - start)));
let bytesRead;
try {
bytesRead = fs.readSync(fd, buffer, 0, buffer.length, start);
} finally {
fs.closeSync(fd);
}
return {
cursor: start,
nextCursor: start + bytesRead,
rotationLost: start !== cursor,
truncated: start + bytesRead < size,
fileMissing: false,
readError: null,
observation,
observedMs: Date.now() - observedAt,
output: buffer.subarray(0, bytesRead).toString('utf8'),
};
} catch (error) {
return {
cursor,
nextCursor: cursor,
rotationLost: false,
truncated: false,
fileMissing: error && error.code === 'ENOENT',
readError: error && typeof error.code === 'string' ? error.code : 'UNKNOWN',
observation,
observedMs: Date.now() - observedAt,
output: '',
};
}
}
function finish(observation) {
if (finished) return;
finished = true;
if (watcher) watcher.close();
if (timer) clearTimeout(timer);
process.stdout.write(JSON.stringify(snapshot(observation), null, 2));
}
const initial = snapshot('initial');
if (initial.readError || initial.rotationLost || initial.truncated || initial.output) {
process.stdout.write(JSON.stringify(initial, null, 2));
} else {
try {
watcher = fs.watch(path.dirname(file), (_event, changedFile) => {
if (!changedFile || String(changedFile) === path.basename(file)) finish('change');
});
watcher.on('error', () => finish('watch-error'));
timer = setTimeout(() => finish('interval'), observationMs);
} catch {
finish('watch-error');
}
}
NODEUse only the returned output for this cycle. fileMissing: true means the logger may have renamed port-unknown; rediscover sessions instead of advancing the cursor. Any other non-null readError, or observation: watch-error, is not a clean cycle: report the bounded error code and stop rather than polling rapidly. Otherwise immediately persist the current logPath, pid, port, nextCursor, and a new updatedAt to metro-cursor.json, even when output is empty or contains an error; this prevents duplicate processing after interruption and handles file replacement safely.
Count a clean cycle only when readError is null, observation: interval, observedMs >= 5000, and output is empty or contains no classifiable error. An early change observation with informational output is not yet a full clean interval; process it and start the next collection cycle. If the log file changes, the PID/port check becomes contradictory, or the cursor resets because the file shrank/rotated, never count that cycle as clean.
If truncated: true, never count the result as clean. Process any nonempty output, then issue at most three additional tail calls from the returned cursor in the same cycle. If rotationLost: true, record an explicit rotation warning in fixes.md and require a fresh full observation interval before incrementing the clean counter. If data remains truncated after four chunks, record a backlog warning and continue next cycle rather than consuming unbounded context.
In the new output, surface as classifiable signal and update the matching health.json domain:
ERROR / WARN / LOG prefixes[PAHost], [bridge], [AuthProvider], [AuthContext], [useConnectionRefs], [useConnectionSetup], [addAadAppToConnectionAcl], [PAHost][ErrorBoundary]at <fn> (<file>:<line>:<col>))Unable to resolve module, SyntaxError, transform failed) — re-classify as Step B "Import / Bundle" Critical and route through Step D"GET /index.bundle?platform=ios&dev=true ..." 500 -) — non-200 on .bundle is a bundle/transform failure; non-2xx on connector / Dataverse hosts feeds Step B "Network / API"Bundling complete / iOS Bundled / Android Bundled are informational — log to fixes.md at debug volume but do NOT classify as an issue[TRACE prefixed lines from injected trace statements — classify under the symptom walk (Phase 0.5.4), not as errorsInterpretation rule for host diagnostic lines:
[AuthProvider] MSAL init failed:[AuthProvider] Intune enrollment failed:[AuthContext] acquireTokenSilent failed for scopes:[AuthProvider] Intune unenroll failed:[bridge] unhandled plugin call[bridge] fetch THREW for[bridge] HTTP <status> for[addAadAppToConnectionAcl] failed HTTP <status> for connection[addAadAppToConnectionAcl] error:[useConnectionRefs] could not verify connection ACLs; treating existing connections as setup-required[useConnectionRefs] Failed to load connections:[useConnectionSetup] could not grant connection ACL: missing Power Apps token or user OID[PAHost] getConnectorToken: acquireToken threw for apiId="...":[PAHost] getConnectorToken: acquireToken returned null for apiId="..."[PAHost] getDataverseToken: acquireToken threw for orgUrl="...":[PAHost] getDataverseToken: acquireToken returned null for orgUrl="..."[PAHost][ErrorBoundary] Unhandled JS error:[PAHost][ErrorBoundary] Error stack:[PAHost][ErrorBoundary] Component stack:Telemetry checkpoint: classify_runtime_failures
Apply the 8-category table. Treat each unique stack trace / error message as one issue.
| Priority | Pattern | Category |
|---|---|---|
| Critical | Uncaught exception, unhandled promise rejection, app crash | JS Runtime |
| Critical | Unable to resolve module, Cannot find module | Import / Bundle |
| Critical | SyntaxError, Unexpected token, transform failed (multi-line block from Metro terminal, primary mode only) | Import / Bundle |
| Critical | Cannot read properties of undefined, is not a function | JS Runtime |
| High | NATIVE_MODULE_MISSING from pdfViewer or penInput wrapper | Native |
| High | NATIVE_MODULE_MISSING, PERMISSION_DENIED, or TRACKING_FAILED from geolocation wrapper | Native |
| High | INVALID_URL from pdfViewer, or logs mentioning content://, blob:, or http:// PDF viewer input | JS Runtime |
| High | VIEWER_FAILED or CAPTURE_FAILED from PDF/pen wrapper | Native |
| High | ERROR level runtime log | JS Runtime |
| High | HTTP 4xx / 5xx surfaced in logs | Network / API |
| High | Native module or bridge error | Native |
| Medium | React Warning: component error | React |
| Low | WARN level log that is not known noise | General |
Parsing the multi-line bundle/transform block (primary mode): Metro prints these as a banner (e.g., error: Bundling failed, iOS Bundling failed) followed by an indented block. Unlike runtime stacks, the file:line is on the first non-banner line of the block, formatted as <absolute or relative path>:<line>:<col>. There are usually no at <fn> stack frames. Example to recognize:
iOS Bundling failed 412ms
SyntaxError: /Users/.../app/(tabs)/todos.tsx: Unexpected token (47:12)
45 | return (
46 | <YStack>
> 47 | <Text>{title</Text>
| ^
48 | </YStack>
49 | );Take app/(tabs)/todos.tsx:47:12 as the fix site. The recipes in D3.1 below operate on this format.
Ignore known-noisy lines:
Require cycle: warnings from MetroVirtualizedList: You have a large list… without an associated crashStarting Metro…, Connecting to…)USER_CANCELLED from pen input when the screen leaves state unchanged and does not show an error[bridge] setupNativeHost: bridge ready, [PAHost] bridge registered, [PAHost] render: waiting for connection resolution (spinner)Telemetry checkpoint: confirm_runtime_health
Increment the consecutive-clean-cycle counter.
Before exiting at targetCleanCycles, check the symptom guard. Read .powernative/debug-app/symptom-state and pick the matching exit path below. (If no symptom-driven mode was used this session, Phase 0.1 cleared the file at startup, so the "file missing" branch fires.)
Before every clean, flagged, pending, timeout, iteration-cap, or escalation exit, print this sanitized health table from health.json:
Health
Bundle <status> <summary>
Runtime <status> <summary>
Authentication <status> <summary>
Dataverse <status> <summary>
Connector <status> <summary>
Offline <status> <summary>
Navigation <status> <summary>
Native capability <status> <summary>Keep unknown when no evidence was observed and not-configured only when configuration absence was positively detected. Apply the persistence redaction gate to every summary. A clean log interval does not make all unknown domains healthy.
resolved OR file missing (no symptom mode this session):
✓ App is running cleanly — no errors detected across <targetCleanCycles> consecutive log checks.
Symptom verification: <PASS | n/a — no symptom provided>.
Session summary written to .powernative/debug-app/fixes.md.
To resume monitoring, run /debug-app again.flagged (Phase 0.5 found a real problem that needs another skill):
⚠ Logs are clean BUT the symptom isn't fixed — it requires another skill.
Symptom: <class> on <screen>
Next step: <skill route recorded in unresolved.md by Phase 0.5> (e.g., run /add-connector)
Details: .powernative/debug-app/unresolved.md
Re-run /debug-app "<symptom>" after taking that step to verify the fix.Do NOT print the green ✓ — the app is technically log-clean but the user-visible problem persists, and the user needs to act before re-running.
pending (still active after targetCleanCycles clean log cycles):
Append to unresolved.md with the Phase 0.5 chain findings, then print:
"⚠ Symptom
<class>on<screen>still active after<targetCleanCycles>clean log cycles. The runtime is quiet but the user-visible problem persists — likely a swallowed data-path error. See.powernative/debug-app/unresolved.mdfor the chain walk. Suggested next step:<derived from the walk>."
Exit the loop. Do NOT auto-resume.
Iteration cap (applies in both modes): independent of the clean-cycle counter and timeout, the loop exits after 50 total cycles. Track cycle: <N> at the top of fixes.md and increment per cycle. On cap-hit, exit with:
"⚠ Loop reached the iteration cap (50 cycles). Symptom may be intermittent OR a fix is regressing on every reload. See
.powernative/debug-app/fixes.mdfor the per-cycle log. Suggested next step: review the last 3 fixes for circular regressions, or re-run with a more specific symptom."
If counter is below targetCleanCycles and the cap has not tripped, return to Step A. Its foreground file watcher provides the observation interval; do not add shell sleep, a host-specific wait command, or a rapid polling loop.
Telemetry checkpoint: repair_and_verify_runtime_issue
Reset the consecutive-clean counter to 0. For each issue, work through the sequence below one at a time before moving to the next.
--no-fix)When noFix=true, do not continue to D1–D4 for mutation:
[<HH:MM:SS>] Observed (no-fix) — <category> — <file:line|no user frame> — <summary>
Would do: <inline fix recipe | skill handoff | manual native action>.powernative/debug-app/ cursor, audit, and health files is allowed.Use the current Step A output block. Note whether the log shows:
[INJECTED-TRACE] console.log; see Phase 0.5.3 for the pattern)For JS Runtime / React errors, the stack trace in the terminal IS the context. Read the topmost user-code frame to locate the file.
For crashes or blank screens with no terminal output: ask the user:
"Do you see anything on screen — error boundary, blank white, or loading spinner? Please copy any visible error text."
Read the relevant source file(s). Identify:
node_modules/ and src/generated/). For bundle / transform errors (Import / Bundle category, primary mode), use the file:line on the first non-banner line of the Metro error block — see Step B's parsing note.Dataverse / Power Platform diagnostic sequence (before handoff):
memory-bank.md and the relevant native-app-plan.md sections when present.power.config.json; take environmentId from it before any other source. Inspect the relevant generated service/model and connectorSchemas.ts.node "${PLUGIN_ROOT}/scripts/resolve-environment.js" "<environmentId-or-url>"npx power-apps auth-status --json. Never switch accounts, log out, or open login from /debug-app without user confirmation.GET requests through:node "${PLUGIN_ROOT}/scripts/dataverse-request.js" <envUrl> GET <apiPath> \
--tenant-id '<resolved-tenant-id>'WhoAmI when authentication/tenant identity is in question. Use bounded metadata/entity reads to confirm table and column names. Do not create, update, delete, publish, seed, flood, or intentionally invalidate credentials from /debug-app.<Table>Service calls. Never replace them with direct fetch/axios Dataverse calls.Only after this sequence proves that a table/column/service/schema artifact is missing or incompatible should D3 route to /add-dataverse.
Expo / Expo Router / React Native diagnostic sequence:
package.json, app.json/app.config.js, and route layout only as relevant.WebFetch against official https://docs.expo.dev/ documentation (Expo Router pages for routing; SDK pages for native modules). Do not query Microsoft Learn for Expo/React Native behavior.First-party native package ownership gate:
Apply this gate before D3 whenever the failing stack, module, or export involves an installed package whose name matches @microsoft/power-apps-native-*.
node_modules/ frame as a lead only. Read the app call site, the installed package's public types/readme/exports, and the declared and lockfile-resolved package version. Check that the app uses a documented API with supported inputs and configuration./report-issue; mention an official published fix or documented workaround when one is known, but do not apply it from /debug-app.For Import / Bundle category errors, jump to D3.1 first — those have specific recipes that pre-empt the generic routing table below. For everything else (JS Runtime, Network/API, React, etc.), use the routing table:
| Error location / category | Action |
|---|---|
app/ screen file, _layout.tsx, route segment | Inline edit via Edit tool |
src/components/ | Inline edit via Edit tool |
src/hooks/, src/services/ | Inline edit via Edit tool |
src/generated/ | Do not edit. Fix the upstream query or schema and run npm run generate-schemas |
| Dataverse schema (column/table missing) | Run D2's read-only Dataverse diagnostic sequence first. If live metadata/generated artifacts confirm the schema or service is missing, hand off to /add-dataverse. Do not mutate Dataverse or edit generated files from /debug-app. |
Auth / MSAL (AADSTS65001, AADSTS50011) | Hand-off: route user to the Power Apps Wrap page via /set-app-registration-native. Do not auto-edit registrations. |
| Connection / connector reference missing | Hand-off: route user to /list-connections or /add-connector. |
Confirmed defect inside @microsoft/power-apps-native-* | Do not fix in the customer project. Emit the package-defect report below and route to /report-issue. This route takes precedence over native, import/bundle, and unrecognized-error recipes. |
Native module, app.config.js, app.plugin.js, Podfile, build.gradle | Inform the user. Do NOT auto-edit native config — print the error + suggested action and skip to next issue. |
| Unrecognized error pattern | Best-effort autonomous fix — see D3.2 below. The skill attempts a single named hypothesis instead of stopping; the existing 2-attempt escalation rule is the safety net. |
PDF/pen/geolocation-specific routing:
INVALID_URL for PDF viewer input is an inline screen/wrapper fix. Allow https:// and non-empty file:// inputs with viewer 0.2.9+. Never add support for content://, blob:, or http:// in the native viewer path.file:// URI may be opened by native PDF viewer 0.2.9+.NATIVE_MODULE_MISSING for PDF viewer or pen input means the native extension is not in the running build. Do not install packages or edit native config from debug; route to /add-native pdf-viewer or /add-native pen-input to verify wrapper/package state, then tell the user a native rebuild/template update is needed if the package is absent from the app build.geolocation, debug the actual failure dimension: can tracking start (startTracking, permissions, native module), are rows reaching Dataverse (default msdyn_locationrecords exists, native upload/auth errors, no JS upload path), and does behavior match the user expectation (background, restart persistence, breadcrumb/route continuity). Fix visible screen handling inline; if the native module/table is missing, block use and route to the relevant geolocation setup path, not /add-dataverse.USER_CANCELLED from pen input is not a bug unless the screen renders it as an error. Inline fix screens that show cancellation as failure./add-dataverse.For inline edits, keep the change minimal and surgical. Do not refactor surrounding code, rename symbols, or change component contracts.
For a confirmed first-party native package defect, do not append a successful fix entry. Pass this report through the persistence redaction gate, append it to .powernative/debug-app/unresolved.md, clean up injected traces, and stop the loop so /report-issue can run:
Confirmed first-party native package defect — no customer-project workaround applied
Package: <@microsoft/power-apps-native-*>
Declared/resolved version: <declared> / <resolved>
Platform: <ios|android>
Reproduction: <minimal sanitized steps>
Expected: <bounded behavior>
Actual: <bounded error/status>
Ownership evidence: <why the documented caller contract is satisfied and the failure is package-internal>
Next step: /report-issue "<package>: <sanitized summary>"Append to .powernative/debug-app/fixes.md:
[<HH:MM:SS>] <category> — <file>:<line> — <one-line description of fix>These recipes apply to errors classified as "Import / Bundle" in Step B. They are read from the persisted .powernative Metro log. Each recipe is opinionated: take the action listed if its precondition matches, otherwise fall through to the next.
Before applying any recipe, run the first-party native package ownership gate when the cited source/importer or failed internal import is under node_modules/@microsoft/power-apps-native-*. A confirmed package-owned defect routes to /report-issue; never repair it with a resolver alias, copied source, patch, postinstall rewrite, or replacement dependency.
| Error pattern | Precondition | Action |
|---|---|---|
SyntaxError: <file>:<line>:<col> in app/, src/components/, src/hooks/, src/services/ | The cited line is in editable user code (NOT src/generated/, NOT node_modules/) | Read the file around the cited line (±10 lines), identify the syntactic issue (unclosed JSX tag, missing closing brace/paren, stray comma, missing from in import, unterminated string, missing semicolon between statements), apply a single minimal Edit. Do NOT reformat surrounding code. |
SyntaxError in src/generated/ | Cited file is under src/generated/ | Do not edit. Schema regen produced bad output. Hand-off: tell the user to re-run npm run generate-schemas; if the error reproduces, route to /add-connector or /add-dataverse to re-add the affected datasource. |
Unable to resolve module <name> from <importer> | <name> starts with . or .. (relative import) | Glob the importer's directory for files matching <name> with any extension (.ts, .tsx, .js, .jsx, .json). If found with a different extension → fix the import to drop the extension OR match the actual one. If found with a typo (Levenshtein ≤ 2) → fix the typo. If not found at all → the file genuinely doesn't exist; surface to user and ask whether to create it or remove the import. |
Unable to resolve module <name> | <name> is a bare package AND not present in package.json dependencies / devDependencies | Follow shared/references/javascript-dependency-planning.md to classify the published package by contents, not its name. If native-bound and absent from the template, report that a template/runtime update is required. If verified pure JavaScript, ask consent for the exact version, install with npm install --save-exact, validate, and retry. Do NOT install without consent. |
Unable to resolve module <name> | <name> IS in package.json but the bundle still fails | Likely cache: ask the user to stop Metro, rerun npm run dev -- --clear, then reload. Never kill an unowned process. |
transform failed referencing a babel plugin (e.g., [BABEL] ... unknown plugin "react-native-reanimated/plugin") | Error references babel.config.js | Hand-off. babel.config.js is project config (same constraint that protects app.config.js). Print the cited plugin and suggested fix order (e.g., "react-native-reanimated/plugin MUST be the LAST plugin in babel.config.js plugins array"); skip to next issue. |
transform failed without a babel reference | Generic transform failure (often a TS feature Metro's transformer can't handle) | Read the cited file, look for syntax that requires a specific TS lib (e.g., decorators, top-level await). If the issue is a known-bad pattern, surface and ask before fixing. Otherwise hand-off. |
predev script failure (e.g., npm run generate-schemas errored before expo start ran) | Bundle output shows the failure happened during the predev lifecycle hook | This is not a code edit — power.config.json or the connector setup is broken. Hand-off: route user to /add-connector (for Power Platform connectors) or /add-dataverse (for Dataverse). Do NOT edit power.config.json directly. |
[BABEL] ... You're trying to use the @babel/plugin-X plugin twice | Duplicate babel plugin entries | Hand-off for the same reason as above — babel.config.js is project config. Surface the duplicate; let the user dedupe. |
After applying any inline edit (rows 1, 3, 4 above), Metro auto-detects the file save and re-bundles. Skip directly to D4 — do NOT manually trigger a reload. The verify step picks up Metro's Bundling complete (or the next error block) automatically.
Append to .powernative/debug-app/fixes.md:
[<HH:MM:SS>] Import/Bundle — <file>:<line> — <recipe applied>When an error falls through every row of Step B's classification table AND every row of D3.1's bundle recipes, the skill still attempts a fix instead of stopping. The discipline below keeps best-effort from degrading into wild guessing.
Step 1 — Locate the cite. Try in order; stop at the first that yields a file:line in editable user code:
node_modules/, src/generated/, and React/Hermes internals (react-native/, hermes-engine/, metro/). First remaining frame is the cite.Grep for the exact error message text (or its most distinctive 4–6 word phrase, with regex special chars escaped) across app/, src/components/, src/hooks/, src/services/. A match at a throw new Error('...') site IS the cite.useFoo is not a function), Grep for the symbol; the unique declaration site is the cite.If no cite can be located by step 4: log a structured note to .powernative/debug-app/unresolved.md (minimal sanitized error summary + which lookup attempts ran), surface to the user, advance to next issue. Do not guess at a file. Best-effort still requires a target.
Step 2 — Enrich understanding (do not skip).
AADSTS\d+, Dataverse, Power Platform, MSAL, Entra, Graph API): first run D2's project/reference/read-only diagnostic sequence, then query mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search with the exact code or token when behavior remains uncertain.WebFetch against https://docs.expo.dev/. Do not use Microsoft Learn for these errors.@microsoft/power-apps-native-*, run D2's first-party native package ownership gate. A confirmed package-owned defect is not eligible for best-effort editing.try/catch or useEffect deps.node_modules/ from the stack), one targeted WebFetch against the module's npm page or GitHub README is acceptable; do NOT do open-ended web searches in the loop.Step 3 — Form ONE named hypothesis. Write it to .powernative/debug-app/fixes.md BEFORE editing, in this format:
[<HH:MM:SS>] Hypothesis (best-effort) — <file>:<line> — <one-sentence theory>
Evidence: <sanitized error code/summary + what in the cited code led you here>
Planned change: <what you'll edit, in 1 line>Examples of acceptable hypotheses:
<UserAvatar> reads user.profile.image but user can be undefined during the first render — add a null guard"useEffect at line 42 captures a stale userId because userId isn't in its deps array"AsyncStorage.getItem returns null for missing keys, but the caller assumes JSON-parseable string"NOT acceptable (refuse to apply, escalate instead):
Step 4 — Apply a single minimal edit. One Edit call, smallest possible diff that implements the planned change. Do NOT change unrelated code, rename symbols, or refactor surrounding structure. Re-confirm the file path is in editable user code (NOT under src/generated/, node_modules/, or any path in the Constraints section's protected list).
Step 5 — Defer to D4 verify. The existing verify cycle (type-check + reload + re-poll) decides whether the hypothesis was right. Do NOT preemptively try a second hypothesis "just in case."
Step 6 — On verify failure, ONE alternative is allowed. If D4 shows the same error reappearing, you may form ONE alternative hypothesis (this counts as fix attempt #2 against the original error). If THAT also fails, the existing Escalation rule trips and the skill stops on this error — surface to the user, append to unresolved.md, advance to the next issue. Do NOT chain a third hypothesis.
Constraint reminder for best-effort mode (no exceptions):
src/generated/, node_modules/, app.config.js, app.plugin.js, babel.config.js, metro.config.js, Podfile, build.gradle, gradle.properties, power.config.json, auth.config.json.npm install <pkg>, npm uninstall <pkg>, npx expo install <pkg>, or any command that mutates package.json / package-lock.json without explicit user consent (same gate as D3.1's bare-package recipe).expo prebuild, or otherwise touch the dev-server lifecycle.After the fix is applied:
Type-check:
npm run type-checkIf TS errors exist, fix them before continuing. Do not advance until type-check exits 0.
Wait for Metro to re-bundle (Import/Bundle fix only): For inline edits applied via D3.1, Metro auto-watches the file and triggers a re-bundle on save. Re-run the Step A cursored tail procedure for a bounded set of checks, watching for one of:
Bundling complete / iOS Bundled / Android Bundled → success, proceed to step 4.Reload the app (all other fixes — JS Runtime, Network/API, React, etc.): Fast Refresh should apply most inline edits. If no new bundle/runtime activity appears, instruct the user:
"Please reload the app from the native dev-client menu, then trigger the workflow again."
After the user confirms, run the Step A cursored tail procedure to check only new output.
Confirm the fix via persisted output. If the previous error pattern is absent from newly appended log bytes and no new errors appear, the fix held. If any [INJECTED-TRACE] lines are relevant, use them to confirm the data path is healthy. After confirming, clean up injected logs (Phase 0.5.5).
Reset clean-cycle counter to 0 and return to Step A.
If the same error persists after 2 fix attempts, stop and report:
⚠ Unresolved after 2 attempts: <error summary>
File: <path>
Log: <sanitized bounded error summary>
Last fix tried: <one-line description>
Suggested next step: <manual action>Pass the block through the persistence redaction gate, append only the verifier's output to .powernative/debug-app/unresolved.md, and clean up any [INJECTED-TRACE] logs before exiting (Phase 0.5.5 procedure).
Do NOT attempt a third automated fix for the same error. Wait for user guidance.
app.config.js, app.plugin.js, Podfile, build.gradle, gradle.properties) — report the error to the user with the exact line and a suggested manual action.src/generated/ — these files are auto-generated. Fix the upstream query / service / schema instead, then run npm run generate-schemas.@microsoft/power-apps-native-*, do not edit node_modules/, generate patch-package artifacts or postinstall rewrites, vendor/copy package source, generate or install a fork, replace the dependency with a git/tarball/local path, or add resolver aliases/shims that shadow the package. Route the sanitized evidence to /report-issue./debug-app may resolve the configured environment and issue bounded Dataverse GET requests through the bundled scripts. It must never perform metadata/data writes, publish, seed records, intentionally trigger throttling, invalidate tokens, switch CLI accounts, or replace generated services with direct HTTP./add-dataverse, /set-app-registration-native, /list-connections).// [INJECTED-TRACE] line added during a session MUST be removed before the session ends, even if the symptom is pending or flagged. Use the Phase 0.5.5 find scan across editable app/ and src/ files, excluding src/generated/, to find them.| Symptom | Likely cause | Fix |
|---|---|---|
Phase 0 reports not-started or stopped | No live .powernative Metro log exists | Run npm run dev, open the native app, then rerun /debug-app |
| Phase 0 sees recent failure lines | Expo/Metro exited during startup or runtime | Read the latest log tail, fix the sanitized error, then ask the user to restart npm run dev |
| Phase 0 reports "Metro running but no app connected" | Simulator/device hasn't loaded the app yet | Open the app on the simulator/device, then re-run /debug-app |
| Loop appears stuck | Fix taking longer than expected (e.g., type-check on large project) | Wait — log lines should still print as the fix runs. Type stop to exit. |
| Loop exits with "iteration cap reached" | Symptom is intermittent OR a fix is regressing on every reload | Inspect the last 3 entries in fixes.md for circularity; re-run with a more specific symptom or fix manually |
| Same error keeps recurring after fix | Fast Refresh didn't apply the change, or the fix targeted the wrong file | Verify with git status; reload from the native dev-client menu; re-run |
Same error persists after fix AND git status shows the change saved AND type-check is clean | Stale Metro transform cache | Ask the user to stop Metro, rerun npm run dev -- --clear, reload, then rerun /debug-app |
| Escalation triggered immediately | Error pattern is in a category we hand-off (auth, schema, native) | Take the suggested manual action, then re-run /debug-app |
.powernative/debug-app/fixes.md not appearing | Phase 0 didn't run / state directory not created | Run mkdir -p .powernative/debug-app manually, re-run skill |
| "App is running cleanly" but the user still sees the problem | Symptom-driven mode was not used — log polling alone is blind to silent failures | Re-run as /debug-app "<describe what you see>" to trigger Phase 0.5 (console.log injection) |
Phase 0.5 reports screen=unknown | Symptom text didn't match any route filename | Re-run with a more specific symptom (/debug-app "todos screen empty" not "data is broken"), OR navigate to the broken screen first then re-run |
No [TRACE lines after reload | Metro cached the old bundle | Ask the user to stop Metro, rerun npm run dev -- --clear, then reload the app |
[INJECTED-TRACE] lines left in code after session | Cleanup step was skipped | Run the Phase 0.5.5 find scan and remove each matching line |
Designed to be re-run — every invocation is idempotent. .powernative/debug-app/metro-cursor.json advances past previously seen bytes and resets safely when a new Metro session or rotated log is detected.
Honest about limits — this is a foreground loop. While it's running, you can't run other skills. By design — the model is "build first, debug second." If you need to pause, type stop and resume later.
No specialist agents — upstream's app-debugger.agent.md delegates to screen-builder, component-author, api-integration, dataverse-data-modeler agents. We don't have all those agents in this plugin, so this skill fixes inline OR routes to skills (/add-dataverse, /set-app-registration-native, /list-connections, /add-connector). Behavior is equivalent for the categories we cover.
Host diagnostics caveat — host-prefixed diagnostics ([PAHost], [bridge], [AuthProvider], etc.) are expected in dev-player sessions and should be treated as first-class telemetry. If these lines are absent in non-dev-player builds, that is expected and not itself a bug.
Upstream parity table:
| Behavior | Upstream | This skill |
|---|---|---|
| Log-driven monitor loop | yes | yes — project-local sanitized Metro log is authoritative; host terminal APIs are optional only |
| 8-category classification | yes | yes |
| Verification cycle (type-check + reload + re-poll) | yes | yes |
| Escalation after 2 attempts | yes | yes |
| Bounded polling | yes | yes — durable byte cursor, bounded chunks |
| Configurable consecutive-clean exit | fixed at 3 | yes — default 3, configurable with --cycles, and gated on symptom resolution |
| Specialist agent delegation | yes | replaced with skill routing |
| Working-dir audit log | no | yes (additional — .powernative/debug-app/fixes.md, injected-logs.md) |
| MS Learn fallback for unknown errors | no | yes (additional) |
| Persisted Metro/app log source (bundler errors + Hermes console + HTTP request log) | no | yes — survives host restarts; no MCP fallback |
| Bundle / transform error fix recipes (D3.1) | no | yes (additional) |
Bundle-aware verify (poll Metro for Bundling complete) | no | yes (additional) |
| Best-effort autonomous fix for uncategorized errors (D3.2) | no | yes (additional) |
| Symptom-driven mode — console.log injection + terminal read + data-path walk | no | yes (additional — catches silent failures invisible to log polling; injects [INJECTED-TRACE] logs, reads terminal, cleans up logs after root cause found) |
© microsoft, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in plugins/mobile-apps/skills/debug-app of microsoft/power-platform-skills.
Open the folder on GitHubat commit 5ef4e4f
Debug App next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Debug App this skillmicrosoft/power-platform-skills | 967 | — | ~22k | Automated safety check: Notes | MIT | |
| Debugging and Error Recoveryaddyosmani/agent-skills | 102k | 1 repos | ~2.6k | Automated safety check: Pass | MIT | |
| Octocode Code Researchbgauryy/octocode | 946 | — | ~1.5k | Automated safety check: Pass | MIT | |
| Binlog Generationmicrosoft/testfx | 1k | 2 repos | ~824 | Automated safety check: Pass | MIT | |
| Nextclaw Iteration Log GovernancePeiiii/nextclaw | 260 | — | ~1.4k | Automated safety check: Pass | MIT | |
| Orca Run Replayiflytek/skillhub | 5.2k | 4 repos | ~3k | Automated safety check: Pass | Apache-2.0 |
addyosmani/agent-skills
Applies a stop-the-line rule and a step-by-step triage when tests fail, builds break or something stops working, aiming at the root cause instead of guesses.
bgauryy/octocode
Researches code with evidence: traces callers, imports and cross-repo links, diagnoses failures and reports findings with exact file and line references and a confidence label.
microsoft/testfx
Generate MSBuild binary logs (binlogs) for build diagnostics and analysis.
Peiiii/nextclaw
A skill your agent uses when a commit/release, cross-module delivery, important root-cause fix, red-zone change, large governance rewrite, NPM release, work note, or goal anchor may require…
iflytek/skillhub
Answers questions about a past agent run from its recording, using causal graphs and replay, instead of reconstructing events from memory.
cursor/plugins
Digs into why code is shaped the way it is by checking git history, pull requests and connected tools in parallel, then reporting a cited read on the tradeoffs.
microsoft/power-platform-skills
Inspects and configures the web application firewall (WAF) in front of a Power Pages production site.
microsoft/power-platform-skills
Inspects and configures the security headers a Power Pages site sends to browsers — Content Security Policy, frame and clickjacking protection, cross-origin sharing, cookie behavior, and related…
microsoft/power-platform-skills
Scans a Power Pages site project for security issues in source code and dependencies.
microsoft/power-platform-skills
Runs a security scan on a deployed Power Pages site, fetches the latest scan report, and produces a plain-language summary.
microsoft/power-platform-skills
Creates Dataverse tables, columns, and relationships for a Power Pages site based on a data model proposal.
microsoft/power-platform-skills
Creates, edits, and manages Power Pages Server Logic files — server-side JavaScript that runs securely on the Power Pages runtime.
Works with
Categories
A skill your agent uses when the user has finished building a mobile app, started Metro with npm run dev, and wants the running app monitored for runtime errors AND silent failures (empty lists…. Debug App is an agent skill from microsoft/power-platform-skills, published by the product's own GitHub organization. Use when the user has finished building a mobile app, started Metro with npm run dev, and wants the running app monitored for runtime errors AND silent failures (empty lists, blank screens, swallowed network errors) and fixed autonomously.
Debug App fits situations like: the user has finished building a mobile app; started Metro with npm run dev; wants the running app monitored for runtime errors AND silent failures (empty lists; swallowed network errors) and fixed autonomously.
Run `npx skills add microsoft/power-platform-skills --skill debug-app -a claude-code`. Or copy the skill folder (plugins/mobile-apps/skills/debug-app in microsoft/power-platform-skills) into .claude/skills/debug-app in your project. Claude Code loads it when a task matches its description.
Run `npx skills add microsoft/power-platform-skills --skill debug-app -a codex`. Or copy the skill folder (plugins/mobile-apps/skills/debug-app in microsoft/power-platform-skills) into .agents/skills/debug-app in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add microsoft/power-platform-skills --skill debug-app -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/debug-app, .gemini/skills/debug-app, .github/skills/debug-app and .opencode/skills/debug-app in your project.
Going by SKILL.md and its folder, Debug App needs the command-line tools its instructions call (npm, node, npx, cursor, expo and git) and credentials named REDACTED_SECRET. Its frontmatter pre-approves these tools: Read, Edit, Write, Grep, Glob, Bash, AskUserQuestion, WebFetch, mcp__plugin_mobile-app_microsoft-learn__microsoft_docs_search.
SKILL.md names 1 domain. In commands or code: docs.expo.dev; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Debug App is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 22k tokens (SKILL.md is roughly 89k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Debug App: Debugging and Error Recovery (addyosmani/agent-skills, 102k stars), Octocode Code Research (bgauryy/octocode, 946 stars), Binlog Generation (microsoft/testfx, 1k stars) and Nextclaw Iteration Log Governance (Peiiii/nextclaw, 260 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
microsoft (a GitHub organization, an official publisher) maintains it in microsoft/power-platform-skills, which has 967 GitHub stars. The repository holds 87 skills in this directory. The repository was last updated on October 6, 2026.
Source: microsoft/power-platform-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.