Xcode Trace Profiler
Goal
Be the user-facing profiler for xctrace-analyzer. Users should ask in plain language; do not ask them to know MCP tool names or JSON. Choose the workflow, call the MCP execution tools, and report what xctrace could and could not export.
Simple Prompts
- "Profile this app."
- "Profile this app for hangs."
- "Find why this app is slow."
- "Check this build for leaks and allocation churn."
- "Analyze network activity."
- "Launch the app and profile startup."
- "Record my app on launch."
- "I will launch MyApp; record it for 60 seconds when it appears."
- "Analyze this trace."
- "Compare these two traces."
What It Can Track
- CPU and Time Profiler bottlenecks
- Hangs, freezes, stutters, microhangs, and severe hangs
- Top User-Code Frames that attribute samples to app binaries
- Leaks and allocation churn when Xcode exports usable rows
- Network requests, failures, transfer volume, and top hosts when HAR or CFNetwork data is exportable
- Energy / Power Profiler data where Xcode supports it, mainly iOS/iPadOS
- Existing
.tracefiles, optional dSYM symbolication, scopedtimeRangeMsanalysis, and Time Profiler regressions - Safe cleanup of generated
.tracebundles after the user is done inspecting them
Workflow
Classify the request.
- Cleanup / delete traces: call
cleanup_traces. - Existing
.trace: callanalyze_trace. - Baseline/current or regression: call
compare_traces. - Explicit single template such as Leaks, Allocations, Network, or Time Profiler: call
track_running_app. - Broad, vague, hangs, CPU, leaks, memory, allocations, network, energy, startup, or "profile this app": call
profile_running_app.
- Cleanup / delete traces: call
Establish the target.
- Inspect the project for obvious Xcode targets, schemes, bundle names, app products, or trace paths before asking.
- If shell access is available and the app may already be running, discover candidate PIDs and prefer the exact PID.
- For already-running apps, use attach-by-PID immediately, especially when several processes share a name. Do not ask launch-prep questions for active app profiling.
- Use launch mode only for explicit startup/cold-launch profiling.
- For launch or startup prompts such as "get ready, I will launch my app", "record my app on launch", "profile when I launch it", or "cold launch profile", first establish what process should be watched.
- If exactly one likely app target is discoverable, announce it and start manual-launch observation immediately: "I found MyApp. I'm watching for its PID now; launch it when ready."
- If the app identity is missing or ambiguous, ask one concise question for the app name, bundle id, app path, or scheme, and offer observation as the easy fallback: "I can also start observing now and you can launch it after I say I'm watching."
- Once manual launch observation starts, poll every 200-500 ms for up to 60 seconds while the user launches the app. As soon as one valid PID is visible, call the recording tool with
target: "attach",processNameset to that exact PID, anddurationSecondsset from the user's requested duration so recording starts as close to launch as possible. - While observing, a short status such as "I'm watching for MyApp now; launch it when ready." is enough. Keep polling after sending that status.
- If multiple matching PIDs appear during observation, prefer the newest app executable PID over helper processes. If ambiguity remains, keep observing briefly for a stable main-app PID; ask only if the candidates are still ambiguous.
- If no PID appears before the observation timeout, tell the user no launch was detected and ask them to relaunch or provide the exact app name, bundle id, or PID.
- If no target can be discovered, ask one concise question for the app path, scheme, bundle id, process name, or PID.
- Infer
userBinaryHintsfrom the app, scheme, executable, module, or bundle name.
Choose the preset.
full: best macOS default; Time Profiler + Leaks + Allocations + HTTP Traffic.full-ios: iOS/iPadOS default when energy is relevant; adds Power Profiler.cpu: narrow CPU, hangs, freezes, hot functions, or slow UI checks.memory: leaks, retain cycles, memory growth, allocation churn.network: HTTP/network request analysis.energy: Power Profiler only; mainly iOS/iPadOS.
Run with diagnostics.
- Use
outputFormat: "both"for profiling, trace analysis, and scoped follow-up analysis unless the user explicitly requests only Markdown or only JSON. The structured result preservessupportStatus,exportAttempts, hang timing, and user-code frame details needed for a complete report. - Recording tools open the saved
.tracein Instruments.app by default withopenInInstruments: true; passfalseonly for CI or headless automation. - Use
durationSeconds: 60by default; use 20-30 seconds only for explicit startup checks or longer when the repro needs it. - For normal recordings, omit
outputDirectoryand let the MCP server write under its configured trace root. - Use repo-local or temp output locations such as
test-traces/only whenXCTRACE_ANALYZER_TRACE_ROOTpoints there orXCTRACE_ANALYZER_ALLOW_EXTERNAL_OUTPUT=1is explicitly enabled. If an external output path is rejected, retry immediately withoutoutputDirectory. - Secure defaults block launch profiling, all-process recording, external trace output, and destructive cleanup outside the trace root unless the MCP server was explicitly configured to allow them.
- Keep recorded traces until the user has had a chance to inspect Instruments.app or asks for cleanup.
- At the end of every report that retains a generated trace, proactively remind the user to ask for trace cleanup before ending the session if they are done inspecting it. Do not delete automatically.
- Use
check_xctrace,list_templates, orlist_devicesonly for setup, device selection, or troubleshooting.
- Use
Interpret support status before conclusions.
supported: usable exported rows were parsed.partial: usable rows were parsed, but other schemas failed, were empty, or were skipped.not_exportable: Xcode exposed schemas but no usable rows were exported; this is unavailable data, not "no issues."not_exportablemay also mean the GUI track exists in Instruments.app butxcrun export --tocdoes not expose an exportable table schema.unsupportedis a structured status only; in human reports, phrase it asnot present in trace. It means no matching schema was present in this trace TOC, usually because the recording template/platform did not include that analysis family or Xcode did not expose it for this run. It does not mean the analyzer code is missing.- If Time Profiler failed to parse, CPU attribution is unavailable for that run; inspect Export Diagnostics.
- If Leaks, Allocations, Memory, Network, or Energy are structurally
unsupported/not_exportable, say the automated MCP report cannot validate that area and use the opened Instruments trace for GUI verification. Renderunsupportedasnot present in tracefor users. - Memory is distinct from Allocations and Leaks. A macOS
fullrun can showMemory: not present in tracewhile Allocations/Leaks are present ornot_exportable; that means the trace TOC did not expose generic memory/resident/dirty/VM schemas, not that allocation or leak recording was disabled. - Energy / Power depends on the Power Profiler instrument. It is mainly for iOS/iPadOS; macOS
fulldoes not include it, and macOS Power Profiler recordings may be rejected by Xcode or absent from the TOC. Report that asnot present in tracedue to platform/template/export availability, not an analyzer implementation gap.
Follow up when needed.
- For hangs, choose the longest Severe Hang, otherwise the longest Hang. Rerun
analyze_traceon the saved trace withtimeRangeMs:startMs = max(0, hang.startMs - 500),endMs = hang.startMs + hang.durationMs + 500. Include the scoped report in the final answer; if rerunning is impossible, say why. - Use
## Top User-Code Framesfrom the scoped report to answer which app-owned code was running. - If Top User-Code Frames is empty but Time Profiler succeeded, rerun with better
userBinaryHintsor a dSYM. - Map important app frame names to source files with project search (
rg) when source is available, then include concrete file:line pointers. If source is unavailable, list the most relevant symbols or modules instead. - If launch mode saves a trace but TOC export fails, retry by launching the app manually and attaching by exact PID.
- Once the user says the trace is no longer needed, call
cleanup_traceswith the exact trace path(s) anddryRun: false. - For broad stale-trace cleanup, call
cleanup_traceswithdryRun: truefirst, or useolderThanMinutesbefore destructive directory cleanup.
- For hangs, choose the longest Severe Hang, otherwise the longest Hang. Rerun
Detailed Report Shape
For profiling and trace-analysis reports, default to a full readable diagnostic report, not a short summary. Include everything meaningful the run found: exported hangs, support/export limitations, full-run user-code frames, scoped hang-window frames, requested domain findings, source areas, and recommendations.
Before composing the final user-facing report for profile_running_app, track_running_app, or analyze_trace, read references/report.md and follow its report contract and examples. Only skip it for setup checks, cleanup, template/device listing, trace comparison summaries, or when the user explicitly asks for a brief answer.