CN

SmartPerfetto Architecture Q&A: 8 In-Depth Technical Questions

Word count: 11.2kReading time: 70 min
2026/04/10
loading

SmartPerfetto Architecture Q&A

This article collects technical questions received after publishing From Trace to Insight: Harness Engineering in SmartPerfetto AI Agent and discusses them in Q&A format.

Version note (reviewed October 2026): These answers explain the April 2026 design, pinned to f3206864. Q8 lists 164 analysis definitions; the additional _base.skill.yaml template makes 165 files. Interfaces, thresholds, cache design, and timings here are historical, not current defaults or new test results. The project is now open source; consult the v1.16.1 documentation for that version and the updated companion article for historical limits.


Q1: Why build a custom YAML Skill system instead of using Claude Code’s standard Skills?

Question context: Claude Code’s Skill system supports placing deterministic scripts in a scripts/ directory to avoid LLM generalization. Since you can use scripts/ to execute fixed SQL, why build a separate YAML Skill system? Isn’t a YAML Skill essentially a tool that lets performance engineers execute SQL according to predefined rules?

Key distinction: The two Skill systems operate at different layers

Claude Code Skills and SmartPerfetto YAML Skills solve problems at different stages:

1
2
3
4
5
Development stage (when I write code):
Claude Code + Skills/Hooks → helps me develop SmartPerfetto

Runtime stage (when users analyze traces):
SmartPerfetto Backend + YAML Skills → helps users analyze performance data

This was the project’s division of responsibilities, not a limitation of standard Skills. Users or models can invoke Claude Code Skills, and the Agent SDK can load project Skills when configured (see SDK Skills documentation). Scripts can accept parameters and return JSON. SmartPerfetto chose YAML to centralize query, output-schema, and orchestration contracts in its backend engine, not because standard Skills only work during development.

Even focusing only on “deterministic execution,” YAML Skills have several targeted designs

1. Parameterized SQL, not fixed scripts

Performance analysis SQL isn’t hardcoded – the same Skill needs to accept different parameters (process names, time ranges, frame ID lists):

1
2
3
4
5
6
7
8
9
10
11
12
13
steps:
- id: thread_state_distribution
type: atomic
sql: |
WITH clipped AS (
SELECT state,
MIN(ts + dur, ${end_ts}) - MAX(ts, ${start_ts}) AS overlap_ns
FROM thread_state
WHERE utid = ${main_thread_utid} AND dur > 0
AND ts < ${end_ts} AND ts + dur > ${start_ts}
)
SELECT state, SUM(overlap_ns) AS total_dur
FROM clipped GROUP BY state

This teaching fragment omits input declarations. thread_state has direct utid, not track_id; clipping to a half-open window includes states starting earlier without counting time outside the window. Unfinished/invalid dur <= 0 intervals are excluded, and missing state is not zero. Resolve and validate the UTID and nanosecond bounds before engine substitution; YAML itself does not eliminate injection risk. Python/Node scripts can offer the same parameter and validation contract.

2. Self-describing output format (DataEnvelope)

1
2
3
4
5
display:
level: detail
columns:
- { name: state, type: string }
- { name: total_dur, type: duration, unit: ns }

Each step declares column names, types, and units for DataEnvelope formatting. A duration is not necessarily always displayed in ms. Timeline navigation also needs valid identity, time units, and the relevant clickAction. Scripts returning the same structured JSON can reuse rendering; the choice concerns where that contract is maintained.

3. Composable (composite + iterator)

A composite Skill can reference multiple atomic Skills, and iterators can traverse data rows for per-frame analysis. This composition is declarative in YAML, with the Skill Engine handling orchestration. The scripts/ approach would require writing your own orchestration logic for the same composition.

4. Designed for performance engineers, not developers

The questioner got it right: YAML Skills are essentially a tool that lets performance engineers contribute analysis logic through predefined rules. Performance engineers know which SQL to query and which metrics to examine, but they don’t necessarily know TypeScript. The YAML format lets them directly define SQL queries and output formats without touching backend code. Development changes require confirming server-side reloading. New steps, rendering, or execution semantics may still require code changes.

Comparison summary

Dimension Standard Skill + scripts/ SmartPerfetto YAML Skill
Use in this project Mainly development then; can also integrate with Agent SDK Express backend Skill Engine
Invocation User/model invokes a Skill and its script Agent through invoke_skill
Parameters Scripts can define typed arguments and validation Engine template substitution and input contract
Output JSON, tables, or text DataEnvelope
Frontend Renderable when integrated with a structured contract Reuses existing renderer
Composition Script/tool orchestration Engine support such as composite and iterator
Contribution Understand script and contract YAML + SQL when reusing supported capabilities

Engine templates support ${param|default}; the pipe separates the parameter from its default. These approaches can coexist. YAML is this project’s choice of execution contract and maintenance cost.

Q2: How exactly is “deterministic + flexible” implemented?

Question context: The article says “known scenarios use Strategy files to constrain mandatory checks, but within each phase, the specific queries and deep drill directions are autonomously decided by Claude.” Where is the boundary between constraint and autonomy? How exactly is this achieved?

Three-layer mechanism working together

This hybrid design relies on three layers working in concert: Strategy files define “what must be done,” the enabled Planning Gate requires plan submission before protected calls, and Verifier examines textual/state risk signals afterward.

Layer 1: Strategy files – hard constraints alongside soft guidance

Taking the scrolling analysis scrolling.strategy.md as an example, it defines multiple analysis phases, but the constraint strength differs across phases:

Strong prompt requirements (not execution-layer enforcement):

Phase 1.9 root cause deep drill is the most strictly constrained phase, with the strategy file using red circle markers and “prohibited” language:

1
2
3
4
5
6
7
8
9
10
**Phase 1.9 -- Root Cause Deep Drill (Red circle mandatory, cannot skip):**

For each reason_code accounting for >15% in `batch_frame_root_cause`,
you **must** select the most severe frame for deep drilling.
**Prohibited:** drawing conclusions solely from `batch_frame_root_cause` statistical classifications.

| Condition | Deep drill action |
| Any reason_code Q4>20% | invoke_skill("blocking_chain_analysis", ...) |
| binder_overlap >5ms | invoke_skill("binder_root_cause", ...) |
| ...

Soft guidance (suggested but skippable):

Phase 1.5 (architecture-aware branching) and Phase 1.7 (root cause branching) use suggestive language like “switch to” and “note,” allowing Claude to decide whether to execute based on actual data:

1
2
3
4
5
**Phase 1.5 -- Architecture-Aware Branching:**

| Architecture | Adjustment action |
| Flutter | Switch to flutter_scrolling_analysis |
| WebView | Note CrRendererMain thread |

The entire content of the Strategy file is injected verbatim into the System Prompt, with a hard constraint statement added at injection time:

1
2
Scene Strategy (must be strictly followed)
For the following common scenarios, proven analysis pipelines exist. All phases must be fully executed and cannot be skipped.

Claude sees these phase definitions, red circle markers, and “prohibited” language directly in the System Prompt.

“Must,” “prohibited,” and red markers express policy but do not themselves block tools or prove execution. Later text heuristics can miss omissions. Preconditions that must be enforced need explicit runtime checks. Phases and thresholds such as 15%/20%/5ms are historical strategy choices, not universal causal rules.

Layer 2: Planning Gate – forces planning first, but doesn’t limit plan content

When an analysisPlan reference is enabled, the execute_sql and invoke_skill MCP entry points require submit_plan to submit an analysis plan. Calling execute_sql or invoke_skill without submitting a plan is directly rejected:

1
2
3
4
5
function requirePlan(toolName: string): string | null {
if (!analysisPlanRef) return null; // Planning feature disabled
if (analysisPlanRef.current) return null; // Plan exists, allow
return `Must call submit_plan to submit an analysis plan before using ${toolName}`;
}

The key point is: the Gate only requires a plan to exist, not that it precisely matches the Strategy’s phases. Plans still need to satisfy submit_plan’s parameter schema; within it Claude can restructure phases – it can merge Phase 1 and 1.5, add extra steps not mentioned in the Strategy, or adjust deep drill directions based on preliminary data.

When submitting a plan, the system performs scene-aware keyword checking (e.g., for scrolling scenarios, checking whether the plan mentions “frames,” “jank,” etc.), but this is only at the warning level – the plan is accepted even without these keywords.

The purpose of this design is: require a plan submission before protected tool calls (planning discipline), without restricting how it thinks (planning freedom).

This is not a global lock on every internal query: preprocessing, informational tools, and nested queries are different entry points. Quick mode without the reference disables the gate. A plan’s presence proves structured submission, not that the model thought correctly or executed the steps.

Layer 3: Verifier – multi-dimensional post-hoc checking

There can be gaps between planning and execution – Claude might submit a plan but actually skip a critical step. The Verifier performs multi-dimensional post-hoc checks after analysis completes, primarily using heuristic behavioral checks while supplementing with plan/hypothesis/scene completeness validation:

a) Scene completeness check – whether the analysis output covers the scene’s core content:

1
2
3
4
5
6
7
8
9
10
11
// Scrolling scenario: check if significant jank exists but Phase 1.9 deep drill was skipped
case 'scrolling': {
const hasSignificantJank = /* detect if text mentions significant frame drops */;
const hasDeepDrill = /* match tool/knowledge names in conclusion text, not execution logs */;
if (hasSignificantJank && !hasDeepDrill) {
issues.push({
severity: 'error',
message: 'Scrolling analysis has jank but missing Phase 1.9 root cause deep drill -- reason_code is just a classification label, not the real root cause'
});
}
}

b) Hypothesis state check – whether recorded hypotheses remain formed; a status change does not establish sufficient evidence.

c) Causal chain depth check – whether CRITICAL/HIGH severity findings contain sufficient causal connectors and mechanistic terminology (heuristic text matching).

d) Optional LLM review – using an independent Haiku model for evidence support verification (can be disabled).

If the check finds ERROR-level issues, it triggers a Correction Prompt for Claude to fill in the gaps.

Note that the Verifier does not check whether Claude’s plan phases match the Strategy’s phase numbers – it checks whether “critical analysis actions are reflected in the output,” not whether “the plan format is correct.”

At this snapshot, verifySceneCompleteness reads allText built from findings and conclusion. hasDeepDrill is hasAnalysisTool || hasKnowledgeDrill; mentioning lookup_knowledge can satisfy it. Comments about real calls do not change that implementation. Causal words, model-written evidence, and resolved state do not establish actual evidence collection or causality. Model review can be skipped or time out, and at most two corrections do not guarantee coverage.

The complete constraint spectrum

Layering all three mechanisms together, different phases form a spectrum of constraint strength:

Phase Strategy tone Planning Gate Verifier check Constraint strength
Phase 1 (overview) Suggestive Plan required Not individually checked Medium
Phase 1.5 (architecture branch) Suggestive – Not checked Low
Phase 1.7 (root cause branch) Suggestive + conditional – Not checked Low
Phase 1.9 (root cause deep drill) Must/Prohibited – Matches deep-drill-related output text High
Phase 2 (supplementary deep drill) Optional – Not checked None
Phase 3 (comprehensive conclusion) Must cover distribution – Checks conclusion completeness Medium

Meanwhile, general.strategy.md (the fallback when no scene matches) is entirely soft guidance: it only provides a routing decision tree based on the user’s focus direction (CPU -> cpu_analysis, memory -> memory_analysis), with no mandatory phases. General still has tool, permission, budget, and enabled gate/verifier constraints.

One-sentence summary

Strategy expresses requirements, the enabled Planning Gate checks for a plan, and Verifier provides post-hoc risk signals. The model can choose queries, but describing an action is different from logged execution returning valid data.


Q3: What’s the biggest difference between Agent and Workflow? Where are the Agent’s capability boundaries and what determines them?

Question context: In building our Agent, we went from initially assuming the Agent could understand and make decisions about every Skill given to it, to now having essentially hardcoded a decision tree in the Skills. The stepping stones along the way were always: “we assumed the Agent had capability X, but it didn’t,” causing its output to deviate from our expectations, so we kept adding boundaries to the Skills until it became a hardcoded Workflow.

The essential difference: Who holds decision-making authority

Agent and Workflow aren’t two tools or two frameworks – they’re two ends of the same spectrum:

1
2
3
4
5
Hardcoded Workflow <------------------------------------> Fully Autonomous Agent
| |
Developer controls every branch LLM decides everything
| |
High determinism, low flexibility Low determinism, high flexibility
Dimension Workflow Agent
Control flow Developer hardcodes if/else in code LLM autonomously selects next step
Tool selection Predefined execution order LLM selects on-demand based on data
Branch conditions Conditional logic in code LLM reasoning
Failure handling try/catch + retry logic LLM self-reflection + direction change
Predictability Highly deterministic Highly uncertain
Adapting to new scenarios Developer must add branches Can explore autonomously

But in engineering practice, almost no one operates at either extreme of the spectrum. Workflows can include generic queries, dynamic routing, and abstention/escalation branches; Agent reliability varies by task and constraints. Real-world production systems sit somewhere in the middle.

The root cause of your pitfalls: Making global assumptions about Agent capabilities

“Defaulting to ‘Agent can understand everything’ -> discovering it can’t -> constantly adding constraints -> becoming a hardcoded Workflow” – the fundamental problem with this path is: making a one-size-fits-all judgment about Agent capabilities.

But Agent capabilities vary enormously across different tasks:

Capability dimension Project allocation consideration Who should handle it
Intent understanding (what the user wants) Useful with ambiguity handling Agent (though simple scenarios can use keyword matching instead)
Plan formulation (how many steps, what order) Requires task-level validation Needs a constraint framework: Strategy files provide structure, LLM fills in details
Data collection (what to query) Requires task-level validation Semi-autonomous: Skills define what to query, Agent decides order and parameters
Data reasoning (attribution after seeing data) Model self-assessment cannot prove correctness Agent proposes explanations; evidence checks constrain attribution
Precise computation (numerical statistics) Use reproducible computation Tool system (SQL / Skill Engine)
Self-evaluation (knowing if it’s right) Insufficient as acceptance evidence External Verifier; don’t trust Agent self-assessment

The correct approach isn’t “choose Agent globally or choose Workflow globally,” but assign by task:

1
2
3
4
5
Scene recognition     -> Workflow (deterministic logic, no LLM needed)
Data collection -> Semi-Workflow (Skills define what to query, Agent decides order and params)
Reasoning/attribution -> Agent (this is LLM's core value; proposes explanations that still need verification)
Output formatting -> Program-defined schema/validation; model text can still violate it
Quality verification -> Workflow (rule checking) + Agent (LLM review)

This table recommends responsibilities; it is not a measured model-reliability ranking. The question alone cannot establish the other system’s sole root cause without failure cases, tool contracts, and data coverage.

SmartPerfetto’s approach: A constraint strength spectrum

SmartPerfetto doesn’t choose between Agent and Workflow; instead, it sets different constraint strengths for different analysis phases (detailed in Q2). Here we re-examine this design from the “capability boundary” perspective:

Strong prompt requirement (Phase 1.9) – addressing observed skipped deep drills:

1
2
3
4
5
6
7
# Phase 1.9 in scrolling.strategy.md

**Phase 1.9 -- Root Cause Deep Drill (Red circle mandatory, cannot skip):**

For each reason_code accounting for >15% in batch_frame_root_cause,
you **must** select the most severe frame for deep drilling.
**Prohibited:** drawing conclusions solely from batch_frame_root_cause statistical classifications.

Why strengthen the prompt? Because we found the Agent has a systematic bias: it tends to jump straight to conclusions after getting overview data, skipping the deep drill. Overview reason_code labels can be mistaken for conclusions. Without controlled evidence, this does not establish an internal cognitive-cost or path-dependency explanation.

Less prompt constraint (Phase 1.5) – using architecture information to guide selection:

1
2
3
4
5
6
7
# Phase 1.5 in scrolling.strategy.md

**Phase 1.5 -- Architecture-Aware Branching:**

| Architecture | Adjustment action |
| Flutter | Switch to flutter_scrolling_analysis |
| WebView | Note CrRendererMain thread |

This uses suggestive language like “switch to” and “note” without enforcement. Because the architecture detection result (Flutter/WebView/Standard) has already been placed in the system prompt by deterministic code, the Agent has routing information, but detection errors, missing signals, and wrong selections still need checks.

No fixed scene steps (general) – generic exploration within runtime boundaries:

1
2
3
4
5
6
7
# general.strategy.md -- only a routing decision tree, no mandatory steps

Scene: general
priority: 99

The current query did not match a specific scene strategy. Based on the user's
focus direction, use the following decision tree to select the appropriate analysis path.

General means no specific strategy matched at entry. It does not mean the problem cannot be programmed or that all constraints vanish. Generic exploration, clarification, and an unknown outcome are available; unconditional trust in the model is not the only option.

What determines Agent capability boundaries

Model capability, task distribution, and budget affect results. The following are three engineering factors this project can directly improve, not an exhaustive capability formula:

1. Observation capability – what data can the Agent “see”

The same model, given structured L2 per-frame data from the scrolling_analysis Skill vs. writing SQL to query raw tables itself, produces significantly different analysis quality. Available data tools constrain what the Agent can analyze. SmartPerfetto uses 164 YAML Skills to encapsulate domain experts’ query logic; the Agent gets processed, structured analysis data through invoke_skill, not raw millions of trace events.

2. Constraint framework – within what bounds does the Agent make decisions

An unconstrained Agent is like an intern without a task checklist – knowledgeable enough but unsure what to do first. Strategy files, Planning Gate, and Verifier together define the Agent’s decision boundaries: Strategy tells it “at minimum, what must be done,” Planning Gate forces it to “think before acting,” and Verifier post-checks “whether the analysis is sufficient” (heuristic checks + hypothesis closure + scene completeness + optional LLM review).

3. Feedback quality – can the Agent be corrected when wrong

A significant proportion of Agent findings have issues (shallow attribution, false positives, missing critical steps). Relying solely on model self-correction has limited effectiveness. SmartPerfetto uses multi-layer verification + external correction prompts to close the loop:

1
2
3
Verifier finds ERROR -> Generates Correction Prompt -> Triggers SDK retry
^ |
Learned patterns <- Accumulated historical misjudgment patterns

Addendum: Strategy files are SOPs, and that’s fine

Some might point out that scrolling.strategy.md reads like an SOP (Standard Operating Procedure) – with numbered Phases, condition tables, mandatory items, and even explicit invoke_skill("scrolling_analysis", {...}). How is this different from “hardcoding a decision tree in Skills”?

Data collection borrows a Workflow-style organization. Strategy files express expert step requirements; model-driven calls remain distinct from program-controlled query/branch execution. This is intentional.

The key is understanding what the SOP covers and what it doesn’t:

What the SOP can cover (data collection) – what Strategy files do:

1
2
3
4
5
scrolling.strategy.md:
Phase 1: "Invoke scrolling_analysis" <- Hardcoded what data to collect
Phase 1.5: "Flutter switches to flutter_scrolling_analysis" <- Hardcoded conditional branch
Phase 1.7: Condition table -> deep drill actions <- Hardcoded if/then table
Phase 1.9: "Red circle reason_code >15% must deep drill" <- Hardcoded mandatory items

What the SOP does not fully cover (reasoning/attribution) – where the Agent’s value lies:

1
2
3
4
- Among 47 jank frames, which share the same root cause? (Data clustering)
- Among 19 workload_heavy frames, which is "most severe" and worth deep drilling? (Priority judgment)
- Deep drill reveals Binder blocking 23ms + thermal throttling simultaneously; what's the causal direction? (Causal reasoning)
- How should the final conclusion be organized? How to differentiate recommendations for App developers vs. platform engineers? (Expression decisions)

Different scenarios have different SOP levels:

Strategy file SOP level Reason
scrolling.strategy.md High – Phase numbers + condition tables + mandatory items Scrolling analysis methodology is most mature; common collection paths are relatively clear
startup.strategy.md Medium-high – Has Phase structure, but deep drill directions are more open Startup scenarios are more diverse (cold/warm/hot, different bottlenecks)
anr.strategy.md Medium – 2-skill pipeline, but combines rules and further attribution ANR root causes are highly diverse
general.strategy.md Low – Only a routing decision tree, no mandatory items Unmatched scenarios; use generic investigation rules

scrolling.strategy.md has the highest SOP level because scrolling analysis methodology is the most mature. general.strategy.md has almost no SOP because user questions are completely unpredictable.

So the correct understanding is: SmartPerfetto = “SOP-driven data collection + Agent-driven reasoning/attribution.”

The SOP addresses “what data to look at, at minimum, when analyzing scrolling issues” – this question has a deterministic answer, and using an SOP is correct. The Agent addresses “how to reason about causality and organize conclusions after getting the data” – the instance varies by trace and can combine rules, statistics, and model reasoning.

Coming back to your concern that the Skills have become a Workflow: check each rule’s scope and evidence before treating that change as a step backward. Keep reliable collection and diagnostic rules fixed, and allow exploration where coverage is incomplete.

This allocation does not prevent SOPs from supporting reasoning. Clustering, severity ranking, rule-based diagnosis, and formatting can be programmed. Validated deterministic diagnoses can be useful outputs. Distinguish observations, rule judgments, and hypotheses with provenance instead of forbidding tool conclusions merely to preserve the Agent label.

One-sentence summary

Agent and Workflow mainly differ in how decision authority is allocated. Measure reliability on the target task, use failure types to decide what to program and what to delegate to a model, and retain an exit for insufficient evidence.


Q4: Does the Agent architecture need improvement from a business perspective?

Question context: Agent architecture has gone through different designs and evolutions – from the initial ReAct architecture to LangGraph’s node-based architecture. How do different Agent architecture designs affect it? When building your own business Agent, should you consider the architecture’s impact on Agent performance? For example, SmartPerfetto has added different Skill loading modes on top of the Claude Agent SDK based on business understanding.

Essential differences of three mainstream architectures

These names describe different layers rather than mutually exclusive approaches. ReAct is a reasoning/action pattern, LangGraph is a stateful graph orchestration framework, and Claude Agent SDK is a runtime library providing agent loops and tool integration.

Name Control/composition Application decisions
ReAct Interleaves reasoning/actions and observations; implementable in different frameworks Tools, stopping conditions, evidence checks
LangGraph Supports cycles, conditional edges, state, and dynamic routing; nodes can call models or ordinary code State/execution boundaries, persistence, retries, human intervention
Claude Agent SDK Query streams, tool/permission configuration, and session support; the application retains lifecycle/business contracts Tool integration, permissions, result validation, cancellation

LangGraph is not restricted to DAGs. Its official Agent examples loop between model and tool nodes, letting the model choose tools from intermediate results. Declaring nodes does not require enumerating every possible root cause.

Why SmartPerfetto chose Native SDK + custom constraint layers

SmartPerfetto chose Claude Agent SDK to reuse its agent loop, tool dispatch, and sessions, then add Strategy, Planning Gate, ArtifactStore, and Verifier. This was an engineering tradeoff, not a limitation preventing LangGraph from expressing performance analysis.

1
2
3
4
SDK query stream -> application message/cancellation/timeout handling -> SSE -> frontend
MCP tools -> Skill Engine / SQL -> data and evidence references
Strategies/plans -> guide analysis; runtime gate -> checks preconditions
Verifier -> rule/text review, not complete factual validation

A model can choose Binder, GPU, GC, thermal, or lock investigations from data. LangGraph can implement the same model-node/tool-node loop without a new node for every combination of 21 reason codes. The original consecutive add_edge calls represented fixed edges, not a mandatory conditional-routing design, so they do not establish combinatorial path explosion.

The SDK yields iterable messages; SmartPerfetto converts them into frontend SSE. That website connection is not entirely provided automatically by the SDK. Selection should also consider persistence, recovery, tool permissions, deployment, cost, and observability.

Key business-driven architectural designs

The following are architectural improvements SmartPerfetto made based on business understanding, each directly corresponding to a business problem:

1. Conditional tool loading – reduce the Agent’s decision space

SmartPerfetto has up to 20 MCP tools total (9 always-on + 11 conditionally injected), but only a subset is injected per analysis:

1
2
3
4
5
6
7
8
9
10
11
// claudeMcpServer.ts -- switch tool sets by mode

if (options.lightweight) {
// Factual queries (e.g., "what's the frame rate"): only 3 tools
toolEntries = [executeSql, invokeSkill, lookupSqlSchema];
} else {
// Full analysis: 9 always-on (incl. recall_patterns) + conditionally inject by context
// Comparison mode -> inject compare_skill, execute_sql_on, get_comparison_context
// Hypothesis management -> inject submit_hypothesis, resolve_hypothesis, flag_uncertainty
// Planning tools -> inject submit_plan, update_plan_phase, revise_plan
}

Business reason: Removing irrelevant tools can reduce context and unnecessary calls, but tool count versus selection accuracy needs task-specific evaluation rather than a universal rule.

2. Sub-Agent scene gating – avoid unnecessary parallel overhead

1
2
3
4
5
6
7
8
9
10
11
// claudeAgentDefinitions.ts -- only enable sub-agents in complex scenarios

const ORCHESTRATOR_ONLY_TOOLS = new Set([
'submit_plan', 'update_plan_phase', 'revise_plan',
'submit_hypothesis', 'resolve_hypothesis', 'flag_uncertainty',
'recall_patterns',
'compare_skill', 'execute_sql_on', 'get_comparison_context',
]);

// Sub-agents only get data collection tools, not planning/hypothesis tools
// Design principle: sub-agents collect evidence, orchestrator makes diagnosis
Scenario Sub-Agent configuration Reason
scrolling frame-expert + system-expert Frame analysis and system analysis are suitable for splitting, coordinated by orchestrator
startup startup-expert + system-expert Startup phase analysis and resource contention analysis are suitable for splitting
anr No sub-agent ANR is a 2-skill pipeline; extra sub-agents would only add overhead

Note: The actual parallelism of sub-agents depends on the SDK’s internal scheduling strategy. We design prompts for parallel evidence collection, but actual execution may be sequential.

3. Lightweight vs Full dual mode – quick Q&A doesn’t go through the full pipeline

For queries classified quick without a forced-full condition, the runtime can skip the full Planning -> Skill -> Verification pipeline. SmartPerfetto’s ClaudeRuntime performs complexity classification at the entry point:

1
2
3
4
5
6
7
8
9
analyze(query)
|
queryComplexity === 'quick'
-> analyzeQuick(): 3 tools, no Planning Gate, no Verifier
-> Directly answers factual questions

queryComplexity === 'full'
-> Full pipeline: Planning -> Skill -> Verification -> Correction
-> Systematic analysis

Business reason: A significant proportion of user questions are factual queries (“what’s the frame rate,” “is there an ANR”), and running the full pipeline would unnecessarily increase latency.

These are configuration sketches, not executable TypeScript. classifyQueryComplexity first forces full for selection, reference traces, existing findings, prior full analysis, and scrolling/startup/anr/interaction/scroll-response scenes. Remaining queries use Haiku classification, falling back to full on failure/timeout. “What is the frame rate?” or “Is there an ANR?” may match a forced-full scene; short wording does not guarantee quick mode. Quick lacking the full verifier does not validate its answer.

Answering “whether architecture needs business-driven improvement”

Locate bottlenecks on real tasks before adding constraints or replacing orchestration:

  1. Separate strategy text from mandatory execution conditions. Keep parameter validation, identity scope, budgets, and required dependencies in code; do not move all safety/correctness branches into Markdown.
  2. A Planning Gate can require a plan. Its effect needs failure cases and comparative evaluation; short code does not establish high reliability.
  3. Use tool records and returned data to establish execution. Runtime checks should also validate numbers, sources, entities, time windows, and causal evidence. Textual hints are supplementary.
  4. Choose tool sets and depth by complexity, while keeping missing-data, failure, and uncertainty outcomes in the fast path.

One-sentence summary

Architecture selection involves both business needs and runtime constraints. ReAct can be implemented in different frameworks, and LangGraph supports cycles and dynamic routing. This records SmartPerfetto’s SDK choice and application constraints, not a claim that another framework only handles fixed workflows.


Q5: How should a performance AI agent handle scene recognition?

Question context: We want to do scene recognition and route to the correct Skill. When building this, should we rely more on “user utterance” or “logs,” or is there a better approach? Several paths for scene recognition each have issues: code matching (keyword matching leads to results that are too broad or too narrow), LLM understanding (LLM understanding isn’t necessarily accurate), log reconstruction (can filter for scrolling presence, but that may not be what the user cares about).

SmartPerfetto’s approach: Three signal layers with clear division of labor

SmartPerfetto’s scene recognition doesn’t rely on a single signal source but uses three signal layers working together, each solving a different problem:

1
2
3
Layer 1: User utterance -- keyword matching -> scene type (scrolling / startup / anr / ...)
Layer 2: Trace data -- deterministic detection -> architecture info (Flutter / WebView / Standard / Compose)
Layer 3: Data completeness -- schema + bounded row probes -> preliminary availability (GPU data available? thermal throttling data available?)

Layer 1: User utterance (keyword matching, <1ms)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// sceneClassifier.ts -- 46 lines of code, handles all scene classification

export function classifyScene(query: string): SceneType {
const scenes = getRegisteredScenes(); // Loaded from 12 .strategy.md YAML frontmatters
const lower = query.toLowerCase();

const sorted = scenes
.filter(s => s.scene !== 'general')
.sort((a, b) => a.priority - b.priority); // ANR(1) > startup(2) > scrolling(3) > ...

for (const scene of sorted) {
// Match compound patterns first (more specific, e.g., "startup.*slow")
if (scene.compoundPatterns.some(p => p.test(query))) return scene.scene;
// Then match single keywords
if (scene.keywords.some(k => lower.includes(k))) return scene.scene;
}
return 'general'; // Fallback
}

Keywords are defined in each Strategy file’s YAML frontmatter, not hardcoded in TypeScript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# scrolling.strategy.md frontmatter
keywords:
- 滑动
- 卡顿
- 掉帧
- jank
- scroll
- fps
- 帧
- frame
- 列表
- 流畅
- fling
- stuttering
- dropped frame
- 不流畅
# ... 30+ keywords total

Why was keyword matching chosen then?

  1. Cost: This step makes no model call. <1ms is a historical target/observation; LLM latency and tokens vary with model, network, and prompt, not a fixed 500ms/500 tokens.
  2. Inspectability: Fixed inputs/rules make routing reproducible, not necessarily correct.
  3. Scope: Explicit scene words are useful; negation, multiple intents, and follow-ups can still misroute and need correction paths.

What about cases where keyword matching falls short?

Keyword matching does have boundaries – when a user says “why is this app slow,” keywords can’t determine whether it’s slow startup or slow scrolling. SmartPerfetto handles this by: falling back to the general scene when no match is found, letting the Agent autonomously choose a direction within the general strategy’s routing decision tree.

1
2
3
4
5
6
# general.strategy.md -- no hard constraints, only routing suggestions

| User focus direction | Recommended path |
| CPU / scheduling / threads | invoke_skill("cpu_analysis") |
| Memory / OOM / leaks | invoke_skill("memory_analysis") |
| Unknown direction | invoke_skill("scene_reconstruction") -> route by scene |

The core idea of this design is: don’t try to achieve 100% accurate classification at the entry point; instead, let accurate cases take the fast path (keywords -> Strategy), and uncertain cases take the exploration path (general -> Agent autonomous routing).

Layer 2: Trace data – architecture detection (deterministic code)

Scene classification only resolves “what the user wants to analyze,” but the same scenario (e.g., scrolling) requires completely different analysis paths under different rendering architectures:

Architecture Rendering pipeline Analysis differences
Standard Android UI Thread -> RenderThread -> SurfaceFlinger Dual-track analysis of main thread + RenderThread
Flutter TextureView 1.ui -> 1.raster -> JNISurfaceTexture -> RenderThread updateTexImage Dual-pipeline; need to analyze Flutter engine threads + texture bridging
Flutter SurfaceView 1.ui -> 1.raster -> BufferQueue -> SurfaceFlinger Single pipeline; doesn’t go through RenderThread
WebView CrRendererMain -> Viz Compositor Chromium rendering pipeline; different thread names
Compose UI Thread (Composition) -> RenderThread Similar to Standard but with Composition phase

Architecture detection calls rendering_pipeline_detection to collect and score signals. TypeScript still contains if/else mappings from pipeline IDs to broad types plus fallback handling. architectureDetector.ts can fall back to STANDARD with 0.5 confidence on failure/missing results; that is neither successful identification nor a calibrated 50% probability. Pipeline labels are heuristic classifications, not independent architecture ground truth.

1
2
3
4
rendering_pipeline_detection skill (SQL)
-> Collect thread signals (1.ui / 1.raster / CrRendererMain / RenderThread ...)
-> Pipeline scoring (FLUTTER_TEXTUREVIEW / WEBVIEW_BLINK / ANDROID_VIEW_STANDARD ...)
-> architectureDetector.ts maps to ArchitectureInfo type

Detection results are injected into the system prompt (via templates like arch-flutter.template.md), and the Agent selects the corresponding analysis tools after seeing the architecture information.

Layer 3: Data completeness – capability register

Different trace capture configurations yield different available data dimensions. Some traces lack GPU frequency data; others lack thermal zone data. SmartPerfetto probes the availability of 18 data dimensions before analysis begins:

1
2
3
4
available:                     primary table has at least 3 rows
insufficient_or_scene_absent: only 1–2 rows observed
missing_config_suspected: table missing/empty, cause not established
not_applicable: historical architecture filter excluded it

This information is likewise injected into the system prompt, telling the Agent which dimensions can be analyzed and which lack data. These hints can reduce some blind queries, but do not prove global completeness.

The prober counts a subquery limited to three rows; rowEstimate=3 means at least three, not totals such as 456/12000. GPU probes gpu_slice; the thermal capability uses android_dvfs_counters, not a count of four thermal zones. Unloaded modules, absent scenes, query failures, and missing capture can all appear empty. The old fallback records individual probe failures as zero; interpretation must retain unknown. Probes also lack target-process/selection scope, and architecture exclusions do not prove Flutter/WebView lacks FrameTimeline.

The rendering table is a historical sketch omitting stages such as GPU/HWC. Flutter thread names vary by engine; TextureView/SurfaceView is a separate dimension from Skia/Impeller. Compose is not a separate display pipeline, and WebView rendering is not confined to CrRendererMain.

Evaluating the three paths from the question

1. Code matching (keywords): Viable, but needs well-designed fallback

The questioner said “keyword matching leads to results that are too broad or too narrow.” SmartPerfetto’s experience:

  • Priority ordering chooses among multiple matches: ANR(1) > startup(2) > scrolling(3); when multiple keywords match simultaneously, take the highest priority
  • Compound patterns improve precision: /startup.*slow/ is more precise than matching “startup” alone
  • general fallback handles no-match cases: when nothing matches, don’t guess – hand it to Agent for autonomous exploration

2. LLM understanding: Not recommended for the classification entry point; can be used in the fallback path

LLM classification in SmartPerfetto isn’t Layer 1 but rather the Agent’s autonomous routing within the general scenario – at that point, the Agent already has trace data and can make more accurate judgments combined with the data.

3. Log reconstruction: Suitable as a supplementary signal for Layer 2

Logs can tell you “what’s in the trace” (whether scrolling events exist, whether ANR exists), but can’t tell you “what the user cares about.” SmartPerfetto’s data completeness probing plays exactly this role – it doesn’t participate in scene classification but provides the Agent with data availability information.

Priority resolves which match wins, not whether it is correct. Compound patterns run first within each scene; a broad keyword in a higher-priority scene can still win. General handles no-match, not false-positive matches. Distinguish user intent from recorded events and evaluate LLM routing by accuracy, latency, and cost. A non-LLM scene classifier does not mean the adjacent quick/full classifier also avoids models.

One-sentence summary

Intent routing, architecture identification, and data availability are different problems. Keyword routing is inspectable but can misroute; architecture scores and three-row probes are only clues. Keep correction paths and confirm analysis preconditions using the target process, time window, and actual data.


Q6: How to better leverage AI autonomous exploration in “deterministic steps + AI exploration”?

Question context: We’ve found in production that when AI explores autonomously and drills into root causes, it tends to go off track and give incorrect results. For example, in the SmartPerfetto blog post example – after identifying RenderThread being blocked by Binder in the earlier steps (based on deterministic steps), are the subsequent hypothesis formations and validations pure AI, or do we give the AI some common causes as guidance for Binder blocking and let it investigate on its own?

First, answering the core question: It’s neither pure AI nor hardcoded guidance

SmartPerfetto’s approach is structured reasoning framework + on-demand knowledge injection:

1
2
3
4
5
6
7
8
9
10
11
Deterministic steps produce data
|
Agent forms hypothesis (autonomous, but constrained by reasoning framework)
|
Agent selects verification tool (autonomous, but guided by Strategy suggestions)
|
Verification result feedback
|
Hypothesis confirmed -> go deeper / Hypothesis rejected -> backtrack and change direction
|
Verifier post-hoc check

Three key mechanisms make AI autonomous exploration more reliable:

Mechanism 1: Hypothesis management tools – adding structure to the reasoning process

Hypothesis tools record inspectable analytical claims; they do not expose or force the model’s private reasoning. The f3206864 parameters differ from the original examples:

1
2
3
4
5
6
7
{
"tool": "submit_hypothesis",
"arguments": {
"statement": "Scheduling wait on the target Binder server increased this synchronous transaction latency",
"basis": "Transaction and remote thread identified; next inspect matching-window Runnable intervals"
}
}

The tool/arguments wrapper is for readability; the MCP client sends the actual protocol request. The tool returns hypothesisId. A resolution after contradictory evidence could be:

1
2
3
4
5
6
7
8
{
"tool": "resolve_hypothesis",
"arguments": {
"hypothesisId": "h1",
"status": "rejected",
"evidence": "Illustration: no matching remote scheduling wait; another wait needs separate investigation"
}
}

Replace h1 with the returned ID. Historical status permits only confirmed/rejected, not outcome: refined; submission uses statement/basis rather than description/expected_evidence. Do not force either outcome when evidence is insufficient: preserve unresolved state, explain limits, and form a new hypothesis where appropriate. Resolution stores model-supplied evidence text; it does not run SQL to prove it.

Mechanism 2: Knowledge injection – not hardcoded guidance, but on-demand domain knowledge loading

“Could we give the AI some common causes as guidance for Binder blocking?”

Yes, but not hardcoded in Skills. Instead, it’s loaded on demand through the lookup_knowledge MCP tool. After discovering Binder blocking, the Agent can call:

1
invoke lookup_knowledge("binder-ipc")

This returns a Binder IPC knowledge template (knowledge-binder-ipc.template.md) containing:

  • Classification of typical Binder transaction blocking causes (server-side busy, process frozen, CPU scheduling delay, oneway queue full)
  • Investigation paths and key metrics for each cause
  • Common misdiagnosis scenarios (e.g., remote oneway does not await server completion, but submission/serialization still has costs and failure modes)

Key design: Knowledge is actively pulled by the Agent, not force-injected by the system. There are currently 8 knowledge templates (rendering-pipeline, binder-ipc, gc-dynamics, cpu-scheduler, thermal-throttling, lock-contention, startup-root-causes, data-sources). If all templates were pre-injected into the system prompt, it would consume a large number of tokens and most would be irrelevant. Through on-demand loading via MCP tools, the Agent only retrieves the relevant domain background knowledge when needed.

SmartPerfetto also provides conditional deep drill suggestion tables in Strategy files, which is another form of guidance:

1
2
3
4
5
6
7
8
# scrolling.strategy.md Phase 1.9

| Condition | Deep drill action |
| Any reason_code Q4>20% | invoke_skill("blocking_chain_analysis", ...) |
| binder_overlap >5ms | invoke_skill("binder_root_cause", ...) |
| cpu_runnable_ratio >30% | invoke_skill("cpu_analysis", ...) |
| thermal_throttle detected | invoke_skill("thermal_throttling", ...) |
| gc_pause_total >10ms | invoke_skill("gc_analysis", ...) |

This table isn’t a hardcoded decision tree – it’s a lookup table for the Agent. The Agent decides which row to follow based on metric values in the data. If the data doesn’t match any row, the Agent can explore autonomously.

Mechanism 3: ReAct Reasoning Nudge – triggering reflection when tools return results

During the first few successful returns from data tools (execute_sql / invoke_skill), SmartPerfetto appends a reasoning prompt at the end of the result:

1
2
3
4
5
6
7
8
// claudeMcpServer.ts

const REASONING_NUDGE = '\n\n[REFLECT] Before executing the next step: ' +
'What are the key findings from this data? Does it support/refute your hypothesis? ' +
'If there are important inferences, please record them using submit_hypothesis or write_analysis_note.';

// Only appended during the first N data tool calls, then stopped (to control token cost)
const REASONING_NUDGE_MAX_CALLS = 4;

The appended prompt can remind the model to record intermediate judgments; it does not guarantee reflection or prevent drift. The original ~20 tokens/call and ~80 total lack tokenizer/usage evidence, and Chinese/English text need not have equal token counts. Four is the code’s append limit, not measured effectiveness. Use comparative evaluation.

Walking through the complete flow with the Binder example from the article

This is a teaching hypothesis, not a trace result reproduced by the article’s images. The original “47 frames, Frame #234, 23ms, frequency limited to 50%” lacks accompanying raw data and cannot establish the causal chain.

1
2
3
4
5
6
7
1. Query the target process/window, defining frame counts and missing data.
2. For a long synchronous Binder interval, associate the transaction, client, and remote thread.
3. Form a hypothesis that remote Runnable wait increased response latency.
4. Clip remote thread states to that transaction window; separate running, runnable, sleeping, and dispatch delay.
5. Refine the slow-response mechanism if supported; otherwise reject with contradictory evidence.
6. Investigate thermal impact only with matching policy, effective frequency-cap, and timing evidence.
7. Attach queryable evidence and uncertainty to each conclusion; do not verify causality by keywords alone.

Scheduling delay can be part of a slow Binder response, not evidence against that response being slow. Low frequency plus high temperature does not establish that thermal control caused the jank. Use the actual hypothesis schema above; an already rejected hypothesis cannot be changed to a nonexistent refined status.

Four practical recommendations for making AI autonomous exploration more reliable

  1. Separate observations, rule judgments, and hypotheses: Retain structured data and provenance. Validated rule diagnoses are useful but are not raw observations.
  2. Keep deterministic boundaries: Enforce budgets, identity scope, arithmetic, and required query dependencies in code; allow model routing for open questions.
  3. Use knowledge as investigative guidance: Versioned background knowledge is not evidence from the current trace; query the corresponding data.
  4. Validate conclusions at runtime too: Check numbers, entities, references, time windows, and causal chains. Tool logs establish execution; text heuristics add signals. Labeled datasets and LLM Judges can aid offline evaluation, but a Judge is not independent ground truth.

One-sentence summary

Hypothesis records, retrieval, and reminders help organize exploration without guaranteeing correctness. Reliability still requires actual tool results, traceable evidence, and appropriate stopping conditions; keep insufficiently supported claims unresolved.


Q7: How is the Prompt assembled for each turn?

Question context: LLM Agent output quality depends heavily on system prompt design. How does SmartPerfetto construct the prompt for each analysis? How does the prompt change across different scenarios and different turns? How is the token budget controlled?

Overall design: Four-tier layered assembly + cache optimization

buildSystemPrompt() organizes context at analysis start and in some correction paths; it does not rebuild the entire system prompt after every tool call. Relatively stable content goes first to increase reusable prefixes.

The old source comment “above 1024 tokens it is automatically cached” is an oversimplification, not an API contract. Official Prompt caching documentation distinguishes automatic caching configuration from explicit breakpoints. Request/SDK behavior, model-specific minimum length, matching prefixes, and expiry all matter. Current documentation provides a default five-minute and optional one-hour TTL, separate from SDK session lifetime.

The original 4000/800/400 cached-token and ~80%/18%/~8% savings figures lack usage records and mix cache proportion with price savings. Caching does not remove logical context. Inspect cache_creation_input_tokens, cache_read_input_tokens, and ordinary input/output separately, then calculate cost using the applicable model prices. Token figures in the structural diagram below are estimates.

Four-tier assembly structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
+-------------------------------------------------------+
| Tier 1: STATIC (unchanged within process lifetime) |
| +---------------------------------------------------+ |
| | prompt-role.template.md (~200 tokens) | |
| | -> Role definition: Android performance expert | |
| +---------------------------------------------------+ |
| | prompt-output-format.template.md (~850 tokens) | |
| | -> Output format: [CRITICAL]/[HIGH]/[MEDIUM]/[LOW] | |
| | -> Root cause reasoning chain format, Mermaid rules| |
| | -> Slice nesting rules, CPU frequency estimation | |
| +---------------------------------------------------+ |
+-------------------------------------------------------+
| Tier 2: PER-TRACE (stable within same trace) |
| +---------------------------------------------------+ |
| | Architecture info (~150 tokens) | |
| | -> "Flutter TextureView, confidence 92%" | |
| | -> + arch-flutter.template.md architecture guide | |
| +---------------------------------------------------+ |
| | Focus application (~100 tokens) | |
| | -> "com.example.app (primary focus), 456 frames" | |
| +---------------------------------------------------+ |
| | Data completeness (~200 tokens, droppable) | |
| | -> Only reports missing/insufficient dimensions | |
| +---------------------------------------------------+ |
| | SQL knowledge base ref (~300 tokens, droppable) | |
| | -> Tables/views/functions matched from stdlib index | |
| +---------------------------------------------------+ |
+-------------------------------------------------------+
| Tier 3: PER-QUERY (changes with scene/query) |
| +---------------------------------------------------+ |
| | Methodology + scene strategy (~1200 tokens) | |
| | -> prompt-methodology.template.md | |
| | -> {{sceneStrategy}} = scrolling.strategy.md | |
| | or one of 12 strategies (startup/anr/general...) | |
| +---------------------------------------------------+ |
| | Sub-agent collaboration (~200 tokens, droppable)| |
| | -> When to delegate vs direct call | |
| | -> Scrolling-specific parallel evidence collection | |
| +---------------------------------------------------+ |
+-------------------------------------------------------+
| Tier 4: PER-INTERACTION (may change every query) |
| +---------------------------------------------------+ |
| | User selection context (~300 tokens, not drop.) | |
| | -> Time range selection (selection-area.template.md)| |
| | -> Or Slice selection (selection-slice.template.md) | |
| +---------------------------------------------------+ |
| | Comparison mode context (conditionally injected) | |
| | -> Dual-trace comparison methodology + tool guide | |
| +---------------------------------------------------+ |
| | Conversation context (~500 tokens) | |
| | -> Analysis notes (<=10, sorted by priority) | |
| | -> Previous findings (<=10) | |
| | -> Known entities (for drill-down) | |
| | -> Conversation summary (cross-turn compressed, | |
| | <=2000 tokens) | |
| +---------------------------------------------------+ |
| | SQL pitfall records (<=5, droppable) | |
| | -> ERROR -> BAD SQL -> FIX SQL | |
| +---------------------------------------------------+ |
| | Historical analysis patterns (cross-session, drop.) | |
| | Historical pitfall records (cross-session, drop.) | |
| +---------------------------------------------------+ |
| | Historical analysis plans (<=3 turns, droppable) | |
| | -> Phase status: done/skipped/pending + summary | |
| +---------------------------------------------------+ |
+-------------------------------------------------------+

Template loading and variable substitution

Most fixed rules come from Markdown templates; TypeScript still constructs selection, findings, notes, and budget trimming. The following shows template loading:

1
2
3
4
5
6
7
8
9
10
11
// strategyLoader.ts -- template system

// 1. Load template (development cache behavior depends on server configuration)
loadPromptTemplate('prompt-methodology') // -> strategies/prompt-methodology.template.md

// 2. Load scene strategy (extract keywords from YAML frontmatter, body as strategy content)
getStrategyContent('scrolling') // -> Markdown body of strategies/scrolling.strategy.md

// 3. Variable substitution
renderTemplate(methodologyTemplate, { sceneStrategy })
// Replaces {{sceneStrategy}} with scrolling.strategy.md content

Template file inventory:

Category File Purpose
Static templates prompt-role.template.md Role definition
prompt-output-format.template.md Output format rules (91 lines)
prompt-quick.template.md Quick mode streamlined prompt
Methodology prompt-methodology.template.md Analysis methodology (contains {{sceneStrategy}} placeholder)
Architecture guides arch-standard.template.md Standard Android rendering guidance
arch-flutter.template.md Flutter engine guidance
arch-compose.template.md Jetpack Compose guidance
arch-webview.template.md WebView guidance
Selection templates selection-area.template.md Time range selection ({{startNs}}, {{endNs}}…)
selection-slice.template.md Slice selection ({{eventId}}, {{ts}}…)
Comparison mode comparison-methodology.template.md Dual-trace comparison methodology
Scene strategies 12 *.strategy.md files scrolling/startup/anr/memory/…
Knowledge templates 8 knowledge-*.template.md files On-demand domain knowledge (not injected into prompt)
Auxiliary templates prompt-complexity-classifier.template.md Quick/Full routing decision (not injected into prompt, but determines which path to take)

Token budget management

Soft budget target: 4500 tokens (MAX_PROMPT_TOKENS). During correction retries, if SDK auto-compact is detected (conversation history automatically compressed), the budget is reduced to 3000 tokens to leave room; otherwise the original prompt is reused.

Token estimation method: Mixed Chinese-English estimation – Chinese characters at 1.5 tokens/character, ASCII at 0.3 tokens/character. This project approximation is not measured tokenizer usage or billing data; estimation error can affect budgets.

Progressive dropping strategy when over budget:

When the assembled prompt’s token count exceeds the budget, entire sections are dropped in order from lowest to highest priority:

1
2
3
4
5
6
7
8
Drop order (dropped first -> dropped last):
1. Perfetto SQL knowledge base reference -> Agent can use lookup_sql_schema tool instead
2. Trace data completeness -> Helpful but Agent can discover missing data at runtime
3. Historical analysis patterns -> Cross-session pattern memory, non-critical
4. Historical pitfall records -> Cross-session negative memory, droppable
5. SQL pitfall records -> Nice to have
6. Sub-agent collaboration -> Only useful when sub-agents are enabled
7. Historical analysis plans -> Supplementary context

Content that is never dropped:

  • Role definition, output format (Tier 1 static)
  • Architecture info, focus application (Tier 2 per-trace)
  • Methodology + scene strategy (Tier 3 core)
  • User selection context (user’s explicit intent)
  • Conversation context (previous findings and analysis notes)

If optional-section removal still leaves the prompt over budget, f3206864 logs a warning and returns it. Thus 4500/3000 are not hard caps and do not represent all history, tool definitions, or output budget. Tool results must retain missing/unknown data even when completeness guidance is dropped; absent warnings do not prove completeness.

Complete context construction flow

In ClaudeRuntime.analyze(), prompt assembly is preceded by over twenty preparation phases to collect all context:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Phase 0:   Selection context logging
Phase 0.5: Focus app detection (3 methods: battery_stats / oom_adj / frame_timeline)
Phase 1: Skill executor initialization
Phase 2: Architecture detection (LRU cached, reused while a valid cache entry exists)
Phase 2.5: Vendor detection (OEM customization, LRU cached)
Phase 2.8: Comparison mode context (dual-trace mode)
Phase 2.9: Data completeness probing (18 dimensions, time depends on data/modules)
Phase 3: Session context + conversation history
Phase 4: Entity store (drill-down references)
Phase 5: Scene classification (keyword matching, <1ms)
Phase 5.5: Cross-session pattern memory matching
Phase 6: ArtifactStore + analysis notes
Phase 6.5: Analysis plan (current + historical)
Phase 6.6: Watchdog feedback references
Phase 6.7: Hypothesis state
Phase 6.8: Uncertainty flags
Phase 7: SQL error tracking
Phase 8: MCP Server creation (inject all the above state)
Phase 9: (removed)
Phase 10: SQL knowledge base context
Phase 11: Sub-agent definitions
Phase 12: SQL error-fix pairs
Phase 13: -> buildSystemPrompt(context) -> final prompt

All Phase results feed into the ClaudeAnalysisContext object, passed to buildSystemPrompt() for final assembly.

These Phase numbers identify preparation steps in this source snapshot, not an external protocol requiring serial completion. LRU eviction, restoration, and failures can trigger new probes; restored state also means the first visible turn need not start with empty context.

Quick vs Full dual mode

Not all queries need the full 4500-token prompt. When entry routing selects quick, SmartPerfetto uses a streamlined quick prompt:

1
2
3
4
// buildQuickSystemPrompt() -- ~1500 tokens
// Loads prompt-quick.template.md
// Only injects {{architectureContext}} and {{focusAppContext}}
// No methodology, no scene strategy, no conversation context
Dimension Quick Mode Full Mode
Target tokens ~1500 ~4500
Scene strategy None One of 12
Methodology None prompt-methodology.template.md
Conversation context None findings + notes + entity + summary
Planning Gate None Yes
Verifier None Yes
Use case Simple queries classified quick after forced-full checks “Analyze scrolling stuttering” “Analyze startup performance”

This compares explicitly assembled system prompts. Quick runtime may still pass SDK resume, so no injected conversation context does not mean the SDK sees no history. Q4 describes the actual routing checks; not every factual question takes the quick path.

How the prompt changes across multi-turn conversations

During context preparation, the project checks an SDK ID and timestamp in its local sessionMap. SDK_SESSION_FRESHNESS_MS = 4 * 60 * 60 * 1000 is an application freshness heuristic, not proof that Anthropic sessions universally expire after four hours.

  • Locally considered resumable: Skip manually injected previousFindings/conversationSummary while retaining available notes, entities, and plans. This decision is not confirmation that SDK resume succeeded.
  • Locally old/unavailable: Inject partial findings and summaries. Summaries and item caps can lose details.
  • Correction: Detected auto-compaction can lower the system-prompt soft budget to 3000; otherwise reuse the original prompt. Compacted history is not the original complete message set.

The SDK session documentation describes disk persistence and ID-based restoration. Availability also depends on session files, environment, and SDK configuration; prefix-cache hits do not verify successful session restoration. Follow-ups can change scene, selection, or focus, so Tiers 1–3 need not stay unchanged and have no fixed 80% hit rate.

A concrete example: Prompt assembly for scrolling analysis

User inputs "Analyze scrolling stuttering", Flutter TextureView architecture, Turn 1:

1
2
3
4
5
6
7
8
9
10
[Tier 1] prompt-role.template.md                    -> "You are an Android performance analysis expert..."
[Tier 1] prompt-output-format.template.md -> Output format rules
[Tier 2] "Architecture: Flutter TextureView, confidence 92%" -> + arch-flutter.template.md
[Tier 2] "Focus app: com.example.app (primary focus)" -> frame count + detection method
[Tier 2] "Data completeness: gpu MISSING, suspected not captured" -> only reports missing/insufficient
[Tier 2] SQL knowledge base: android_frames, slice_self_dur -> stdlib match results
[Tier 3] prompt-methodology + scrolling.strategy.md -> Phase 1->1.5->1.9->3 complete strategy
[Tier 4] (no selection, no conversation context, no historical plans)

Estimated: ~3200 tokens, within 4500 budget, no dropping needed

User follows up with "Deep dive into frame 3", Turn 2 (SDK session resume hit):

1
2
3
4
5
6
7
8
[Tier 1-3] Same as Turn 1 (unchanged content may be reusable; not measured)
[Tier 4] Conversation context (SDK holds conversation history, findings not re-injected):
- Analysis notes: "Warning [Hypothesis] Primary jank cause is RenderThread Binder blocking"
- Entity context: frame#3's ID and time range
- Historical plan: "Done Phase 1 overview, Done Phase 1.9 deep drill, Pending Phase 3 conclusion"
(previousFindings and conversationSummary managed internally by SDK session, not duplicated in prompt)

Estimated: ~3400 tokens, within budget

This is a teaching assembly example: 92% is an illustrative score, and 3200/3400 are estimates, not calibrated probabilities or billing records from a user session. Recheck tokens and output contracts when placeholders, strategy content, or model configuration change.

One-sentence summary

Stable prefixes can help reuse, but caching depends on model/API conditions and measured usage; session restoration is separate. The 4500/3000 targets are soft budgets. Trimming and summaries can lose information, so preserve user scope and missing-evidence semantics.


Q8: What Skills does SmartPerfetto have?

Question context: SmartPerfetto’s analysis capabilities are carried by YAML Skills. A complete Skill inventory helps understand the system’s analysis coverage.

Overview

This inventory checks definition names/directories at f3206864 and restores five omitted atomic entries. A definition’s existence does not mean every trace provides data or executes successfully: modules, recording, platform, and parameters still matter. Labels such as v3.0 identify Skill versions, not Android versions. Installed versions can have different inventories.

Category Count Description
Atomic 87 Single-step detection/statistics, completed with one or a few SQL statements
Composite 29 Combines multiple atomic skills, supports iterator/conditional
Deep 2 Deep profiling (callstack, CPU profiling)
Pipeline 28 Rendering pipeline detection + teaching (24+ architectures)
Module 18 Modular configuration: app/framework/hardware/kernel
Total 164

Atomic Skills (87)

Single-step data extraction and detection – the building blocks for all higher-level Skills.

Frame rendering and jank:

Skill ID One-line description
consumer_jank_detection Historical frame-interval heuristic, not independent perceptual-jank ground truth
frame_blocking_calls Identify blocking calls during each jank frame (GC, Binder, locks, IO)
frame_production_gap Detect frame production gaps: gaps between consecutive frames exceeding 1.5x VSync
frame_pipeline_variance Detect frame duration jitter and high-variance intervals
render_pipeline_latency Break down latency across all stages of the frame rendering pipeline
render_thread_slices Analyze RenderThread time slice distribution
app_frame_production Analyze application main thread frame production
sf_frame_consumption Analyze SurfaceFlinger frame consumption
sf_composition_in_range Analyze SurfaceFlinger composition latency
sf_layer_count_in_range Count active SF layers within a time range
present_fence_timing Correlate recorded present-fence timing with verified endpoint semantics
game_fps_analysis Game-specific frame rate analysis, supporting fixed frame rate modes

VSync and refresh rate:

Skill ID One-line description
vsync_period_detection Detect VSync period, return refresh rate and confidence
vsync_config Read or estimate periods; distinguish fallback defaults from measurement
vsync_alignment_in_range Analyze frame-to-VSync signal alignment
vsync_phase_alignment Analyze input event to VSync phase relationship, locating touch-to-display latency bottlenecks
vrr_detection Inspect cadence-change clues, not proof of LTPO hardware or complete VRR support

CPU and scheduling:

Skill ID One-line description
cpu_topology_detection Infer core groups from recorded frequency information; verify device topology
cpu_topology_view Create reusable SQL VIEW _cpu_topology
cpu_slice_analysis Analyze CPU time slice distribution (with dynamic topology detection)
cpu_load_in_range Analyze per-CPU core load within a specified time range
cpu_cluster_load_in_range Calculate overall CPU load percentage for big and little core clusters
cpu_freq_timeline Analyze per-CPU core frequency change timeline
cpu_idle_analysis Inspect recorded CPU-idle states/intervals; assess impact with wakeup timing
cpu_throttling_in_range Inspect frequency-limit candidates; low frequency alone does not prove thermal control
sched_latency_in_range Analyze thread scheduling wait time distribution, detecting CPU contention
scheduling_analysis Analyze thread scheduling latency (Runnability)
task_migration_in_range Analyze thread migration frequency between big and little cores
thread_affinity_violation Inspect main/RenderThread migration; migration alone is not an affinity violation
thermal_predictor Frequency-trend heuristic, not a calibrated thermal-throttling forecast
util_tracking_analysis Correlate early main-thread running/frequency windows; not proof of WALT/PELT lag
cache_miss_impact Count cache-miss counters and evaluate fluctuation

GPU:

Skill ID One-line description
gpu_render_in_range Analyze GPU rendering duration and Fence wait
gpu_freq_in_range Analyze GPU frequency changes
gpu_metrics Analyze GPU frequency, utilization, and rendering performance
gpu_power_state_analysis Analyze GPU frequency state transitions, identifying frequency reduction pressure and jitter
gpu_frequency_analysis Summarize GPU-frequency samples; verify units, weighting, and thermal inference

Main thread analysis:

Skill ID One-line description
main_thread_states_in_range Count main thread states, blocking functions, and percentages within a range
main_thread_slices_in_range Count main thread slice duration distribution within a range
main_thread_sched_latency_in_range Count main thread Runnable wait time distribution
main_thread_file_io_in_range Count main thread file IO related slice durations within a range

Binder IPC:

Skill ID One-line description
binder_in_range Analyze Binder transactions within a specified time range
binder_blocking_in_range Analyze counterpart process response delays in synchronous Binder calls
binder_root_cause Perform server/client-side blocking cause attribution for slow Binder transactions
binder_storm_detection Detect Binder transaction storms: too many IPC calls in a short period

Locks and synchronization:

Skill ID One-line description
lock_contention_in_range Analyze lock contention within a specified time range
futex_wait_distribution Inspect futex-related waits; not every futex wait is mutex contention

Startup-specific (19):

Skill ID One-line description
startup_events_in_range Query startup events and TTID/TTFD metrics
startup_slow_reasons Startup slow reasons (Google official classification + self-check) v3.0
startup_critical_tasks Query recorded active threads in the startup window, sorted by CPU time
startup_thread_blocking_graph Build waker associations; not automatic proof of lock ownership
startup_jit_analysis Analyze JIT compilation thread impact on startup speed
startup_cpu_placement_timeline Analyze main thread core type changes by time bucket, detecting stuck-on-little-core during startup
startup_freq_rampup Analyze CPU frequency ramp-up speed during cold start, detecting frequency scaling delays
startup_binder_pool_analysis Inspect observed Binder threads/transactions; saturation needs queuing/wait evidence
startup_hot_slice_states Analyze thread state distribution of Top N hot slices during startup interval
startup_main_thread_states_in_range Count main thread Running/Runnable/Blocked percentages during startup
startup_main_thread_slices_in_range Count main thread slice hotspots during startup
startup_binder_in_range Count Binder call distribution during startup
startup_main_thread_file_io_in_range Count main thread file IO during startup
startup_sched_latency_in_range Count main thread Runnable wait latency during startup
startup_main_thread_sync_binder_in_range Count main thread synchronous Binder duration during startup
startup_main_thread_binder_blocking_in_range Analyze main thread synchronous Binder blocking details during startup
startup_breakdown_in_range Count attribution reason time percentages during startup
startup_gc_in_range Count GC slices and main thread percentage during startup
startup_class_loading_in_range Count class loading slice durations during startup

Memory and GC:

Skill ID One-line description
gc_events_in_range Query GC events for a given process and optional time range
memory_pressure_in_range Analyze memory pressure metrics within a specified time range
page_fault_in_range Analyze Page Fault and memory reclaim impact on performance

Input and touch:

Skill ID One-line description
input_events_in_range Extract raw input events within a range, analyzing dispatch latency
input_to_frame_latency Estimate latency from recorded input/frame associations; verify mapping and missing events
touch_to_display_latency Estimate input-to-presentation latency from recorded endpoints, not optical touch latency
scroll_response_latency Measure response latency from scroll gesture input to first frame rendering

System and device:

Skill ID One-line description
system_load_in_range Analyze overall system CPU utilization and process activity
device_state_snapshot Capture device environment info during trace (screen, battery, temperature, etc.)
device_state_timeline Track device state changes over time
wakelock_tracking Inspect recorded Wake Lock holding; duration alone does not measure battery drain

Others:

Skill ID One-line description
blocking_chain_analysis Analyze main thread blocking chain: what blocked the main thread? What was the waker doing?
anr_main_thread_blocking Deep analysis of main thread blocking cause during ANR
anr_context_in_range Extract first ANR event data as time window anchor
app_lifecycle_in_range Track Activity/Fragment lifecycle events
compose_recomposition_hotspot Detect Jetpack Compose recomposition hotspots
webview_v8_analysis Analyze WebView V8 engine: GC, script compilation, execution time
rendering_pipeline_detection Identify application rendering pipeline type (24 fine-grained detection types)
pipeline_key_slices_overlay Query pipeline key Slice ts/dur for timeline overlay
fpsgo_analysis Summarize FPSGO/FSTB/FBT-like slice names; name matches can be false positives
logcat_analysis Filter captured Logcat for ANR/GC/Binder/StrictMode warning clues

Composite Skills (29)

Combine multiple atomic skills, supporting iterator (per-frame/per-event deep drill) and conditional (data-driven branching).

Skill ID One-line description
scrolling_analysis Scrolling analysis main entry: overview -> frame list -> root cause classification -> per-frame diagnosis
flutter_scrolling_analysis Flutter-specific frame analysis, using Flutter thread model
jank_frame_detail Analyze a specific jank frame in detail: deep drill into jank cause and root cause classification
startup_analysis Startup analysis main entry: Iterator mode, big/little core analysis, four-quadrant
startup_detail Analyze a single startup event: main thread duration, Binder, CPU big/little core ratio
anr_analysis ANR v3.0 analysis: system issue vs. app issue, categorized handling
anr_detail Associate ANR thread states/Binder dependencies; deadlock needs additional evidence
cpu_analysis CPU analysis: time distribution, big/little core analysis, scheduling chain
gpu_analysis GPU analysis: frequency distribution, memory usage, frame rendering correlation
memory_analysis Memory analysis: GC events, GC-to-frame correlation, thread states
gc_analysis GC analysis: based on stdlib android_garbage_collection_events
binder_analysis Binder deep analysis: transaction basics, thread states
binder_detail Single Binder transaction detail: CPU big/little core, four-quadrant, blocking cause
thermal_throttling Temperature monitoring, thermal throttling detection, CPU frequency correlation
lock_contention_analysis Lock contention multi-dimensional analysis: based on android.monitor_contention
surfaceflinger_analysis SF frame composition performance: GPU/HWC composition ratio, slow composition detection
click_response_analysis Click response analysis: based on stdlib android_input_events
click_response_detail Single slow input event detail: latency breakdown, four-quadrant, main thread blocking
scroll_session_analysis Single complete scroll session: Touch phase vs Fling phase FPS
navigation_analysis Activity/Fragment navigation performance: lifecycle, transition animations
lmk_analysis LMK analysis: cause distribution, timeline, frequency
dmabuf_analysis Inspect DMA-buffer events and unmatched candidates, not proof of a leak
block_io_analysis Block IO analysis: device-level statistics, queue depth, long-duration IO
io_pressure IO blocking data detection, IO Wait time, severity assessment
suspend_wakeup_analysis Suspend/wakeup analysis: time distribution, wakeup source ranking
network_analysis Network analysis: traffic overview, per-app traffic, protocol distribution
irq_analysis Hard interrupt and soft interrupt frequency, duration, nesting
scene_reconstruction Reconstruct user operation scenarios through user input and screen state
state_timeline Four-lane continuous state timeline: device/user/app/system

The engine supports conditional steps, but this snapshot’s definitions do not use that step type. Separate supported types from present execution paths. Output classifications can still be heuristic; a root_cause name does not establish causality.

Deep Skills (2)

Deep profiling, typically requiring longer execution time.

Skill ID One-line description
cpu_profiling CPU performance profiling: usage hotspots and scheduling efficiency deep analysis
callstack_analysis Call stack hotspot analysis in Running state

Pipeline Skills (28)

Rendering pipeline detection + teaching. Each pipeline skill corresponds to a rendering architecture, including pipeline description, key threads, performance metrics, and optimization recommendations.

Skill ID Rendering architecture
pipeline_android_view_standard_blast Common Android 12+ HWUI/BLAST path; verify version/device evidence
pipeline_android_view_standard_legacy Legacy HWUI/BufferQueue path; Android version alone is insufficient
pipeline_android_view_software CPU Skia software rendering, no RenderThread
pipeline_android_view_mixed View + SurfaceView mixed rendering
pipeline_android_view_multi_window Same-process multi-window (Dialog/PopupWindow)
pipeline_android_pip_freeform Picture-in-Picture and freeform window mode
pipeline_compose_standard Jetpack Compose + HWUI RenderThread
pipeline_flutter_textureview Flutter hosted through TextureView, not necessarily a PlatformView fallback
pipeline_flutter_surfaceview_skia Flutter + Skia engine (JIT Shader)
pipeline_flutter_surfaceview_impeller Flutter SurfaceView + Impeller; runtime pipeline/cache work still needs inspection
pipeline_webview_gl_functor Traditional WebView, App RenderThread synchronous wait
pipeline_webview_surface_control Modern WebView + Viz/OOP-R independent composition
pipeline_webview_textureview_custom X5/UC and other custom WebView engines
pipeline_webview_surfaceview_wrapper WebView fullscreen video wrapper mode
pipeline_chrome_browser_viz Chrome Viz compositor, multi-process architecture
pipeline_opengl_es Direct OpenGL ES / EGL rendering
pipeline_vulkan_native Native Vulkan rendering
pipeline_angle_gles_vulkan ANGLE: OpenGL ES -> Vulkan translation layer
pipeline_game_engine Unity/Unreal/Godot and other game engines
pipeline_surfaceview_blast Standalone SurfaceView + BLAST sync
pipeline_textureview_standard SurfaceTexture texture sampling/composition mode
pipeline_camera_pipeline Camera2/HAL3 multi-stream camera rendering
pipeline_video_overlay_hwc HWC video layer hardware-accelerated overlay
pipeline_hardware_buffer_renderer Android 14+ HBR API direct Buffer rendering
pipeline_surface_control_api NDK SurfaceControl direct transaction submission
pipeline_variable_refresh_rate VRR/ARR + FrameTimeline dynamic refresh rate
pipeline_imagereader_pipeline ImageReader API: ML inference, screen recording, custom camera
pipeline_software_compositing Teaching definition for software-composition candidates, not proof of a universal SF CPU fallback

Note: _base.skill.yaml is the base template file for Pipeline Skills, not registered as an available Skill, and not counted in the total.


Module Skills (18)

Modular analysis configuration, organized by layer. The Agent discovers them via list_skills and invokes on demand.

Hardware layer (5):

Skill ID One-line description
cpu_module CPU frequency, thermal throttling, and power states
gpu_module GPU rendering, frequency, and VRAM usage
memory_module Memory bandwidth, LMK, dmabuf, PSI, page faults
thermal_module Temperature sensors, thermal throttling detection, cooling policy
power_module Wake Lock, CPU idle, power mode, suspend/wakeup

Framework layer (6):

Skill ID One-line description
surfaceflinger_module Frame rendering timing, jank causes, GPU composition
choreographer_module VSync signal, doFrame callbacks, frame production pipeline
ams_module Application lifecycle, process management, startup timing
wms_module Window animations, Activity transitions, multi-window
art_module GC, JIT compilation, and memory allocation
input_module Touch latency, input dispatch, and click response

Kernel layer (4):

Skill ID One-line description
scheduler_module Thread scheduling latency, CPU utilization, big/little core assignment
binder_module Cross-process calls, blocking transactions, call latency
lock_contention_module Mutex/Futex, Java monitor, deadlock detection
filesystem_module Block IO, file operations, database, SharedPreferences

Application layer (3):

Skill ID One-line description
launcher_module Home screen performance, app launch, widget updates
systemui_module Status bar, notification shade, quick settings, navigation bar
third_party_module Third-party app performance, stuttering, and resource usage

Relationships between Skills

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Module Skills (configuration layer)
+-> Define analysis scope and focus areas

Composite Skills (orchestration layer)
+-> Reference multiple Atomic Skills
+-> Iterator: per-frame/per-event traversal deep drill
+-> Conditional: data-driven branching

Atomic Skills (execution layer)
+-> Directly execute SQL, return DataEnvelope

Pipeline Skills (knowledge layer)
+-> Rendering pipeline teaching + detection

Deep Skills (profiling layer)
+-> Callstack / CPU profiling deep analysis

Scrolling path in this snapshot:

1
2
3
4
5
invoke_skill("scrolling_analysis")
-> references cpu_topology_view, frame_pipeline_variance, etc.
-> internal SQL produces overview/list and batch_frame_root_cause classification
Agent may separately invoke jank_frame_detail for optional deep drilling
-> references binder_blocking_in_range, sched_latency_in_range, etc.

This snapshot uses batch SQL classification, not the original “consumer_jank_detection -> iterator -> jank_frame_detail for every frame” chain. Reusing computation is not invoking a same-named Skill. Distinguish inline SQL, explicit Skill references, and later Agent tool calls.


SmartPerfetto Discussion Group

The historical QR code is retained without a guarantee that it remains valid. Current bug reports can use the project issue tracker.

SmartPerfetto discussion group

For contact details, see About the author.

CATALOG
  1. 1. SmartPerfetto Architecture Q&A
    1. 1.1. Q1: Why build a custom YAML Skill system instead of using Claude Code’s standard Skills?
      1. 1.1.1. Key distinction: The two Skill systems operate at different layers
      2. 1.1.2. Even focusing only on “deterministic execution,” YAML Skills have several targeted designs
      3. 1.1.3. Comparison summary
    2. 1.2. Q2: How exactly is “deterministic + flexible” implemented?
      1. 1.2.1. Three-layer mechanism working together
      2. 1.2.2. Layer 1: Strategy files – hard constraints alongside soft guidance
      3. 1.2.3. Layer 2: Planning Gate – forces planning first, but doesn’t limit plan content
      4. 1.2.4. Layer 3: Verifier – multi-dimensional post-hoc checking
      5. 1.2.5. The complete constraint spectrum
      6. 1.2.6. One-sentence summary
    3. 1.3. Q3: What’s the biggest difference between Agent and Workflow? Where are the Agent’s capability boundaries and what determines them?
      1. 1.3.1. The essential difference: Who holds decision-making authority
      2. 1.3.2. The root cause of your pitfalls: Making global assumptions about Agent capabilities
      3. 1.3.3. SmartPerfetto’s approach: A constraint strength spectrum
      4. 1.3.4. What determines Agent capability boundaries
      5. 1.3.5. Addendum: Strategy files are SOPs, and that’s fine
      6. 1.3.6. One-sentence summary
    4. 1.4. Q4: Does the Agent architecture need improvement from a business perspective?
      1. 1.4.1. Essential differences of three mainstream architectures
      2. 1.4.2. Why SmartPerfetto chose Native SDK + custom constraint layers
      3. 1.4.3. Key business-driven architectural designs
      4. 1.4.4. Answering “whether architecture needs business-driven improvement”
      5. 1.4.5. One-sentence summary
    5. 1.5. Q5: How should a performance AI agent handle scene recognition?
      1. 1.5.1. SmartPerfetto’s approach: Three signal layers with clear division of labor
      2. 1.5.2. Evaluating the three paths from the question
      3. 1.5.3. One-sentence summary
    6. 1.6. Q6: How to better leverage AI autonomous exploration in “deterministic steps + AI exploration”?
      1. 1.6.1. First, answering the core question: It’s neither pure AI nor hardcoded guidance
      2. 1.6.2. Mechanism 1: Hypothesis management tools – adding structure to the reasoning process
      3. 1.6.3. Mechanism 2: Knowledge injection – not hardcoded guidance, but on-demand domain knowledge loading
      4. 1.6.4. Mechanism 3: ReAct Reasoning Nudge – triggering reflection when tools return results
      5. 1.6.5. Walking through the complete flow with the Binder example from the article
      6. 1.6.6. Four practical recommendations for making AI autonomous exploration more reliable
      7. 1.6.7. One-sentence summary
    7. 1.7. Q7: How is the Prompt assembled for each turn?
      1. 1.7.1. Overall design: Four-tier layered assembly + cache optimization
      2. 1.7.2. Four-tier assembly structure
      3. 1.7.3. Template loading and variable substitution
      4. 1.7.4. Token budget management
      5. 1.7.5. Complete context construction flow
      6. 1.7.6. Quick vs Full dual mode
      7. 1.7.7. How the prompt changes across multi-turn conversations
      8. 1.7.8. A concrete example: Prompt assembly for scrolling analysis
      9. 1.7.9. One-sentence summary
    8. 1.8. Q8: What Skills does SmartPerfetto have?
      1. 1.8.1. Overview
      2. 1.8.2. Atomic Skills (87)
      3. 1.8.3. Composite Skills (29)
      4. 1.8.4. Deep Skills (2)
      5. 1.8.5. Pipeline Skills (28)
      6. 1.8.6. Module Skills (18)
      7. 1.8.7. Relationships between Skills
    9. 1.9. SmartPerfetto Discussion Group