AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Debug App

skill-leonardseo-power-platform-skills-codex-debug-app · by LeonardSEO

Use when the user has finished building a mobile app, started it 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 terminal-log diagnostics — injects temporary console.log statemen…

No reviews yet
0 installs
12 views
0.0% view→install

Install

$ agentstack add skill-leonardseo-power-platform-skills-codex-debug-app

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-leonardseo-power-platform-skills-codex-debug-app)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Debug App? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

📋 Shared instructions: [shared-instructions.md](${CLAUDESKILLDIR}/../../shared/shared-instructions.md) — read first.

Debug App — Monitor & Fix

Monitor the running app by reading the Metro dev-server terminal output, 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 the Metro terminal for output, then clean them up after the root cause is fixed. Modeled on the upstream app-debugger.agent.md pattern — foreground loop, 5-second cadence, exit on 3 consecutive clean polls.

> Dev-client limitation: the standalone dev client outputs app/runtime logs, React errors, and Metro bundler output to the terminal running npm run dev. This includes host runtime diagnostics that use strings such as [AuthProvider] MSAL init failed:, [bridge] fetch THREW for, [bridge] HTTP for, [addAadAppToConnectionAcl] failed HTTP for connection, [useConnectionRefs] could not verify connection ACLs; treating existing connections as setup-required, and [PAHost][ErrorBoundary] Unhandled JS error:. There is no separate device log stream. All diagnosis happens by reading that terminal and, where needed, injecting strategic trace statements into source files.

Subcommands (parsed from $ARGUMENTS)

| Form | Behavior | |---|---| | /debug-app (no args) | Default — terminal log-driven mode. Run Phase 0 (startup check), enter monitor loop. Log source is the Metro terminal (BashOutput on the $METRO_TERMINAL_ID recorded in memory-bank.md by /create-mobile-app Step 12). One read covers Metro bundler errors, app/runtime log lines (including host diagnostics), and red-box stack traces. If the terminal ID is not in memory-bank.md, ask the user which terminal is running npm run dev before starting. | | /debug-app "" | 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 | Print current state (last poll, fixes applied this session, unresolved errors). Do NOT enter loop. | | /debug-app stop | If a loop is in progress, the user can type "stop" or this command to exit. State files preserved at .claude/debug-app/. |

Dispatch rule: if $ARGUMENTS is non-empty and is not one of the reserved subcommand tokens (status, stop, help, --help, -h, version, --version), treat the entire string (everything after the command name; outer quotes optional) as the symptom and use symptom-driven mode. For help / --help / -h, print the subcommands table above and exit.

Tip — "play around then debug": in primary mode, BashOutput($METRO_TERMINAL_ID) returns Metro output accumulated since the last read. So if something weird just happened, keep using the app the way you would normally — then run /debug-app (or /debug-app "") and the very first cycle will see the entire history of your session, not just what arrives after the skill starts. No need to reproduce the bug under the agent's eye.

Core Principles

  • Foreground autonomous loop — Once started, this skill owns the conversation until 3 consecutive clean polls confirm the app is healthy, the user types stop, or the escalation rule trips. Do not run other skills concurrently — they'll queue behind the loop.
  • Run AFTER the app is loadednpm run dev must be running and the simulator/device must have the app open. Phase 0 verifies this; the skill stops cleanly if no app is detected.
  • Native-only runtime target — The app must be loaded in a native dev client on a device or simulator; Metro terminal output is the log source for that native session.
  • No web or direct Metro probes — Do not use React Native Web, browser automation, curl, fetch, WebFetch, or any direct request to a Metro/localhost endpoint for runtime diagnosis. Read only the Metro terminal and source files.
  • No screen-by-screen verification — Do not crawl routes or validate every screen. In symptom mode, focus only on the user-reported workflow and the terminal/source evidence needed to diagnose it.
  • One fix at a time — Fully resolve one issue (context → fix → type-check → reload → re-poll) before starting the next. No batching.
  • Working-dir state — All session state lives in .claude/debug-app/ (gitignored): fixes.md for audit log, unresolved.md for escalations, injected-logs.md for tracking injected console.log statements. Survives across runs.
  • Reference resolution order — For unfamiliar errors: in-repo references first ([skills/add-dataverse/references/dataverse-reference.md](${CLAUDESKILLDIR}/../../skills/add-dataverse/references/dataverse-reference.md), etc.), then mcp__microsoft-learn__microsoft_docs_search, then general web search.

Workflow — Task List First

Before entering the monitor loop, write a task list and keep it up to date:

- [ ] Verify dev server is running (BashOutput on Metro terminal — expect Metro banner)
- [ ] Capture baseline terminal state (read BashOutput, note most recent activity)
- [ ] (Symptom mode only) Phase 0.5: parse symptom → ask user to navigate → inject console.logs → read terminal → 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; stop after 3 consecutive clean cycles AND symptom resolved/flagged)
- [ ] Fix:  →   (one task per error found)

Mark each cycle complete (clean OR fixed) before starting the next.


Phase 0 — Startup Check

Before entering the loop:

0.0 Resolve the Metro terminal

The Metro terminal is the only log source. The dev-player routes all JS output there.

  1. Read memory-bank.md for the Metro terminal id: line (written by /create-mobile-app Step 12).
  2. If found, call BashOutput against that id once. If it returns any Metro output (even just the banner), set $METRO_TERMINAL_ID and continue.
  3. If memory-bank.md has no terminal id, or BashOutput returns "shell not found" / "no such background shell": ask the user:

> "Which terminal is running npm run dev? I need its terminal ID to read Metro logs. If you started it in VS Code, look for the active terminal tab name." Wait for the user to provide the ID, then retry BashOutput against the provided id. Set $METRO_TERMINAL_ID and continue.

Record the resolved id in fixes.md:

[] Log source — Metro terminal $METRO_TERMINAL_ID

0.1 Ensure state directory

mkdir -p .claude/debug-app
touch .claude/debug-app/fixes.md
touch .claude/debug-app/unresolved.md
touch .claude/debug-app/injected-logs.md
rm -f .claude/debug-app/symptom-state    # per-session — Phase 0.5 rewrites it if symptom mode is active

If fixes.md is empty, write a session header:

# Debug session — 

0.2 Verify Metro bundled and the app is running

Branch on the source resolved in 0.0.

If $METRO_TERMINAL_ID is set (primary path):

Call BashOutput on it once and scan the captured Metro output:

  • Most recent error-class line is 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.
  • Output contains Bundling complete / iOS Bundled / Android Bundled with no later error-class line → Metro is healthy. Proceed.
  • Output contains a Metro banner (Metro waiting on, Logs for your project) 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.

  • Output is empty, OR contains no Metro banner at all → the recorded shell is alive but Metro isn't running in it (the user repurposed the terminal). Tell the user:

> Metro not detected in the recorded terminal. Restart with npm run dev and re-run /debug-app — the new terminal id will be picked up from memory-bank.md. Stop here.

If $METRO_TERMINAL_ID is NOT set:

Ask the user: > "Which terminal is running npm run dev? Please provide the terminal ID so I can read Metro output."

Wait for the user to reply. Set $METRO_TERMINAL_ID to the provided ID, call BashOutput($METRO_TERMINAL_ID) once, and continue with the checks above.

0.3 Capture baseline

Read the latest output from BashOutput($METRO_TERMINAL_ID). Note the most recently bundled native platform (iOS / Android) and any recent runtime log lines. Append to fixes.md:

[] Baseline — last Metro activity: 

0.4 Initialize cursor

BashOutput maintains an internal stream cursor against $METRO_TERMINAL_ID — each call returns only output produced since the previous call. No separate cursor file is needed. The .claude/debug-app/cursor file is no longer used and can be ignored if present from a previous session.


Phase 0.5 — Symptom-driven setup (only when $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.

0.5.1 Parse the symptom

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:

[] Symptom — class= screen= entity=

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.

0.5.2 Ask the user to navigate to the affected screen

The dev-player has no automation API for navigation. Ask the user: > "Please open the ` screen on the device/simulator, then reply ready`."

Wait for the user to confirm before proceeding.

0.5.3 Inject diagnostic console.log statements and read terminal

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] a timestamp and any auth/data props passed in | | wrong-data / stale-data | The hook that calls the generated service (NOT inside src/generated/), logging [TRACE service-response] the raw return value | | 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 ]', ); // [INJECTED-TRACE]
  • ` — 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 key
  • Log the smallest useful value; use JSON.stringify(value) for objects
  • Never inject inside src/generated/ — inject in the hook/screen that calls into it

Record every injection in .claude/debug-app/injected-logs.md:

[] Injected [INJECTED-TRACE] at : — tag=

Then tell the user: > "I've added diagnostic console.log statements. Please reload the app (press r in the Metro terminal), navigate to `, and trigger the symptom (e.g., scroll the list, tap the button). Reply done` when finished."

Wait for the user to reply, then call BashOutput($METRO_TERMINAL_ID) and filter for [TRACE lines.

0.5.4 Walk the data path from terminal output

Use the [TRACE lines to walk the chain:

  1. Screen TSX (app/.tsx)
  • Find the useListData(...) / use*Data(...) call.
  • Check service-call options — a stray 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.
  • Check any client-side .filter(...) after the data lands.
  1. Data hook (src/hooks/useListData.ts or sibling)
  • Critical: the template hook has TWO mock-fallback paths:
  • Error path: service returns { error } → hook substitutes mock AND may call setError. Silent if the screen ignores error.
  • Empty-result path: service returns { data: [] } (no error) → hook silently substitutes mock. Always invisible without a [TRACE] log.
  • Detect: Grep for MOCK_ imports in the screen file. If present, mock data is wired in.
  • Confirm useFocusEffect is used (not useEffect) — useEffect won't re-run on back-navigate.
  1. Generated service (src/generated/services/Service.ts)
  • If a TODO stub or file missing → route to /add-connector or /add-dataverse. Do NOT edit src/generated/.
  • If it exists and the [TRACE service-response] log shows an error field → read that error; 401/403 = auth issue; 404 = wrong resource name.
  1. Generated model (src/generated/models/Model.ts)
  • Confirm field names match what the screen references. item.title vs cr3e9_title produces blank rows.
  1. power.config.json
  • Confirm the datasources array contains the suspected entity / connector. If absent, npx power-apps add-data-source was never run for it.
  1. Auth state (src/playerConfig.ts, app.config.js, auth.config.json, useAuth() hook)
  • 401 from the service wrapped as { error } — the [TRACE service-response] log surfaces the error string.
  • OAuth deeplink handoff: verify app.config.jsexpo.scheme matches `src/playerConf

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.