sleuth library

Sleuth — Runtime Performance Diagnostics for Flutter

Surfaces performance bottlenecks and actionable fixes directly inside your app using three layers of analysis:

  • Frame timing: SchedulerBinding.addTimingsCallback per frame (~zero cost)
  • VM timeline (best-effort): vm_service sub-phase breakdowns when connected
  • Widget tree scan: structural heuristics for common anti-patterns

Usage

void main() => runApp(Sleuth.track(child: MyApp()));

Features

  • 20 performance detectors (VM-powered, hybrid, structural, and runtime)
  • Actionable fix hints for every issue
  • In-app overlay with live FPS chart and issue dashboard
  • Debug mode warning (run with --profile for accurate data)
  • Completely disabled in release builds

Theming

The overlay auto-detects dark/light mode from the system brightness and uses the high-contrast presets when the platform asks for high contrast. The header toggle cycles System, Light and Dark (persisted in OverlayUiState.themeMode). To force a specific theme or customize colors:

// Light theme for light-background apps
Sleuth.track(
  child: MyApp(),
  config: SleuthConfig(theme: SleuthThemeData.light()),
);

// Custom brand colors
Sleuth.track(
  child: MyApp(),
  config: SleuthConfig(
    theme: SleuthThemeData.light().copyWith(
      severityCritical: Color(0xFFDC2626),
    ),
  ),
);

// Toggle at runtime (e.g. from app code)
Sleuth.updateTheme(const SleuthThemeData.light());
Sleuth.updateTheme(null); // revert to the config theme or auto-detect

See SleuthThemeData for all available tokens (colors, spacing, typography, and border radii).

Classes

AiChatAdapter
Provider-agnostic AI chat adapter.
AiChatMessage
A single message in an AI chat conversation.
AiChatRequest
Request sent to the AI provider via AiChatAdapter.sendMessage.
AllocationEntry
A single class's allocation contribution during heap growth.
BaseDetector
Base class for all performance detectors.
BracketSpec
One bracket axis declaration for a detector's runtimeVerified evidence.
CaptureEntry
A single captured jank frame with its verdict, stamped issues, and timing.
ComponentMetadata
Metadata describing how a non-detector component's reliability claim was validated.
CpuAttribution
A single function's CPU attribution during a jank frame.
DebugInstrumentationConfig
Advanced sub-flag configuration for debug instrumentation.
DebugSnapshot
A snapshot of debug callback data accumulated over a time window.
DetectorMetadata
Metadata describing how a detector's threshold or heuristic was validated.
DetectorThresholds
Detector-specific thresholds for fine-tuning performance detection.
FixHintBuilder
Centralised builder for context-aware fix hints.
FixVerificationResult
Result of comparing current issues against a captured baseline.
FpsPercentiles
FPS percentile values computed from a FrameStatsBuffer.
FrameBudget
Per-frame time budget resolved by resolveFrameBudget.
FrameStats
A single frame's timing data from SchedulerBinding.addTimingsCallback.
FrameStatsBuffer
Circular buffer holding the last capacity frames for live display.
FrameStatsSummary
Aggregated frame stats summary for the export.
FrameVerdict
A per-frame performance verdict combining SchedulerBinding + VM Timeline.
GcEventSummary
A serializable summary of a GC event extracted from VM timeline data.
HeapSample
A single heap memory usage sample from the VM service.
InMemorySleuthStateStore
A SleuthStateStore that keeps the JSON in memory.
IssueVerificationEntry
An individual issue's change between baseline and current state.
JankCaptureBuffer
Bounded rolling buffer of worst jank frames.
NetworkMonitorDetector
Detects slow, excessive, or oversized HTTP requests.
OverlayUiState
Overlay UI state that outlives the widgets showing it.
PaintOriginInstance
One widget instance credited as a likely repaint origin.
PaintOriginStats
The likely repaint origins of one widget type over a snapshot window.
ParsedTimelineData
Parsed timeline data from a batch of VM timeline events.
PerformanceIssue
A detected performance issue with actionable fix hint.
PhaseEvent
A single VM timeline event with its absolute timestamp and duration.
PlatformChannelCall
A completed platform channel call.
PlatformChannelSummary
A serializable summary of a platform channel event from VM timeline data.
PollTimings
Cost of one VM timeline poll, split by segment.
ProfileCaptureSchema
Schema + validator for Sleuth profile-mode captures.
RebuildDetector
Detects expensive widget rebuilding using VM BUILD scopes + element tree.
RecurrenceEntry
A single observation in a recurrence ring buffer.
RecurrenceTrend
Ring-buffered time-series tracker for a single issue's recurrence.
RequestRecord
A recorded HTTP request with timing and size metadata.
RouteSession
Per-route statistics accumulated while a route is the active scan target.
ServiceExtensionRegistry
Binds ext.sleuth.* extensions to dart:developer.
SessionMarkdownExporter
Renders a SessionSnapshot as GitHub-flavoured markdown suitable for pasting into Slack, a PR description, or a bug report.
SessionSnapshot
A point-in-time snapshot of a sleuth session for export.
SimpleStructuralDetector
Convenience base class for writing a structural custom detector without the full BaseDetector boilerplate.
Sleuth
Entry point for the Sleuth package.
SleuthConfig
Configuration for SleuthController.
SleuthStateStore
Storage for the overlay UI state (trigger position, card geometry, hidden issues, severity filter).
SleuthThemeData
All visual tokens for the Sleuth overlay UI.
StartupMetrics
Startup performance metrics captured by Sleuth.init.
StreamResourceDetector
Detects likely retained async resources (Stream subscriptions, StreamControllers, WebSocket channels, optional rxdart Subjects) via getAllocationProfile class-instance diff over a sliding window, gated on a recent MemoryPressureDetector.heap_growing emission.
StreamResourcePollResult
Diagnostic result of a single allocation-profile poll triggered by StreamResourceDetector.pollAllocationProfileNow. Capture screens log this every poll so an empty K=4 window can be diagnosed without a second 50-second on-device session.
WidgetHeatMapEntry
Aggregated performance cost for a single widget across all detectors.
WidgetHighlight
A detected widget's screen position and performance status.

Enums

AiChatRole
Role in an AI chat conversation.
CardWindowState
Window state of the floating issues card.
ConnectionMode
Five-state mode stamped on every ext.sleuth.* response. Lets a consumer distinguish "no issues observed" from "warmup not elapsed" or "no VM-tier frame verdict yet".
DetectorLifecycle
Lifecycle classification for detectors.
DetectorType
Available detector types for configuration via SleuthConfig.enabledDetectors.
EvidenceTier
Evidence tier for a detector's threshold or heuristic.
FixEffort
Estimated developer effort to apply the suggested fix.
FixVerificationStatus
Categorization of an issue's change between baseline and current state.
FrameRateSource
Where the effective frame rate behind a FrameBudget came from.
InteractionContext
The user interaction state when an issue was observed.
IssueCategory
Categories mapping to Flutter rendering pipeline phases.
IssueConfidence
Confidence levels reflecting the strength of evidence behind a detection.
IssueSeverity
Severity levels for detected performance issues.
ObservationSource
Identifies the data source that produced a detection, so the UI can show provenance and users can understand the strength of the evidence.
PipelinePhase
Rendering pipeline phase suspected as bottleneck.
RebuildCountSource
Origin of the DebugSnapshot.rebuildCounts data.
SleuthThemeMode
Theme mode picked with the overlay header's theme toggle.
SnapshotSection
Payload-bearing sections of a SessionSnapshot JSON envelope that a consumer can opt out of via projection. Metadata keys (schemaVersion, exportedAt, packageVersion, isVmConnected, isDebugMode, suppressedCount) are never projectable — they are small and required for parsing, so they always serialize.
TimelinePhase
Classifies a raw VM timeline event by rendering pipeline phase.
TrendDirection
Trend direction for an issue's recurrence over time.
TriggerEdge
Horizontal screen edge the trigger button rests against.

Mixins

ComponentMetadataProvider
Mixin that lets a non-detector component declare its validation metadata in a parallel shape to DetectorMetadataProvider.
DetectorMetadataProvider
Mixin that lets a detector declare its validation metadata.

Constants

kMcpEnvelopeSchemaVersion → const int
MCP envelope shape version. Distinct from SessionSnapshot.schemaVersion.
kSleuthPackageVersion → const String
Stamped on ext.sleuth.diagnose. Keep in sync with pubspec.yaml.

Functions

buildWidgetHeatMap(List<PerformanceIssue> issues, {int maxEntries = 10}) → List<WidgetHeatMapEntry>
Build a heat map from a list of issues, filtering out framework widgets and returning the top maxEntries by total ranking score.
resolveFrameBudget({required int fpsTarget, required double displayRefreshRateHz, double? measuredCadenceHz, required bool auto}) → FrameBudget
Resolves the per-frame budget from fpsTarget, the display's reported refresh rate, and the measured vsync cadence.

Exceptions / Errors

AiProviderException
A failure reported by an AI provider: a non-200 response or an error frame inside the event stream.