| name | r2000-analyze-program |
| description | Orchestrates full-program analysis by running block classification, then analyzing all unanalyzed routines and symbols in parallel using subagents. |
Analyze Program Workflow
Use this skill when the user asks to "analyze this program", "analyze everything", "full analysis",
or wants a complete end-to-end pass over the loaded binary — classifying blocks, documenting
routines, and naming symbols.
This skill orchestrates the following existing skills in order:
r2000-analyze-blocks — Classify all memory regions (code vs data vs text, etc.).
r2000-analyze-routine — Analyze and document each subroutine.
r2000-analyze-symbol — Analyze and name each data symbol.
Phase 0 — Gather Context & Entropy Unpack Check
Before starting or launching any subagents, you must gather context and check if the binary is packed/compressed.
- Get Binary Info: Call
r2000_get_binary_info.
- Read the returned
"entropy" value.
- Also read the description of the
r2000_get_binary_info tool (e.g. from tools/list) to find the entropy threshold preference (e.g., 7.5).
- If the binary's
entropy is greater than or equal to the threshold (values above the threshold suggest the binary might be compressed):
- Ask the user (using regular text in chat) if they would like to unpack the binary before proceeding with the analysis.
- If the user accepts:
- Call the
r2000_unpack_binary tool.
- Note:
r2000_unpack_binary is a destructive action (clears existing comments/labels/blocks) and may take up to 10 seconds or more.
- If
r2000_unpack_binary returns an error: The binary was not unpacked. Log the failure and continue the analysis on the current binary.
- If it succeeds: The binary has been unpacked and a new unpacked binary has been loaded in its place. You must restart this phase (Phase 0) from scratch, calling
r2000_get_binary_info again to fetch the new unpacked binary's info and continue.
- If the user declines: Continue the analysis on the current binary.
Phase 1 — Classify Blocks (r2000-analyze-blocks)
Block classification is a prerequisite for all subsequent analysis.
- Read the skill file at
.agent/skills/r2000-analyze-blocks/SKILL.md.
- Execute the
r2000-analyze-blocks workflow directly (not via a subagent — this is a single long-running pass over the entire binary that you perform yourself).
Phase 2 — Analyze Routines (parallel subagents)
Goal: For every subroutine that hasn't been analyzed yet, launch a subagent to analyze it.
2.1 Identify Unanalyzed Subroutines
A subroutine is considered already analyzed if its entry point has any line comment (the presence of a line comment indicates it has already been documented).
To build the candidate list:
- Call
r2000_get_symbols to get all labels (user + system), including external labels, and save the symbols since they will be used later.
- Call
r2000_get_comments to get all the comments, and save the comments since they will be used later.
- Filter labels that represent subroutine entry points:
- Labels whose name starts with
s_ (auto-generated subroutine labels), OR
- Labels in a
Code block that are the target of at least one JSR cross-reference, OR
- Pointer-to-code labels — any
p_XXXX label that is inside a Code block. These are addresses referenced as pointers (via immediate lo/hi byte loads like LDX #<addr / LDY #>addr, or stored in address tables) and point to executable code. They are almost always one of:
- Chained raster IRQ handlers: In C64/C128 demos, multiple raster interrupts are "chained" — each handler sets the next handler's address into the IRQ vector (
$0314/$0315) via a helper routine. The pointer labels are created from the LDX #<p_XXXX / LDY #>p_XXXX immediate loads, not from direct vector writes. This is the most common case.
- NMI/IRQ handlers loaded directly into hardware vectors (
$FFFA–$FFFF) or shadow vectors ($0314/$0315, $0318/$0319).
- Jump table targets or callback pointers stored via indirect addressing.
- Since all of these are code entry points that deserve analysis, treat every
p_XXXX label in a Code block as a routine candidate. This avoids the need for fragile pattern-matching against specific vector addresses or instruction sequences.
- Entry point label — a label named exactly
start. This is the program's entry point and is critical for understanding the overall program flow.
- For each candidate, check if it already has a line comment (from the refreshed
r2000_get_comments data). If yes → skip it (already documented).
- The remaining list = unanalyzed routines.
- Ordering: If
start is in the unanalyzed list, it must be placed first — it is the program entry point and should be analyzed before all other routines. This ensures that the entry-point context is available when analyzing subsequent routines.
2.2 Launch Parallel Subagents
-
CRITICAL: Always launch each subagent with an explicit target address (e.g., $XXXX or decimal NNNNN). NEVER use the "current cursor address" or rely on the active cursor location in the editor, as the cursor will change dynamically when running parallel subagents.
-
Use a rolling window of up to 7 concurrent subagents (to avoid hitting rate limit quota errors like RESOURCE_EXHAUSTED).
-
For each subagent, provide this prompt:
Read the skill file at .agent/skills/r2000-analyze-routine/SKILL.md and follow its workflow.
Analyze the routine at address $XXXX (decimal: NNNNN).
Binary info: system = {system}, filename = {filename}, description = {description}, may_contain_undocumented_opcodes = {hint}.
Apply all changes automatically — rename the label, add the header comment block, add side comments to key instructions, and apply low/high byte formatting (r2000_set_immediate_format) to any immediate pointer loads. Do NOT ask for user confirmation.
When done, report: the new label name, a one-line summary of what the routine does, and any uncertain areas.
-
Rolling window strategy:
- Launch the first 7 subagents (or fewer if the queue is smaller) to fill all slots.
- When any subagent completes, immediately launch the next routine from the queue into the freed slot — do NOT wait for the entire batch to finish.
- Continue until all routines in the queue have been launched and all subagents have completed.
- This keeps utilization high — if one subagent is slow, the other 6 slots stay busy.
- Error Fallback: If any subagent encounters a quota or model capacity error (e.g.,
RESOURCE_EXHAUSTED / Code 429), immediately catch the failure, log it, and queue the routine to be processed sequentially or directly by the parent orchestrator after a brief delay.
2.3 Post-Phase Refresh
After all routine subagents complete:
- Call
r2000_save_project to persist changes so far.
Phase 3 — Analyze Symbols (parallel subagents)
Goal: For every data symbol and external jump symbol (internal + external) that hasn't been analyzed yet, launch a subagent.
3.1 Identify Unanalyzed Symbols
A symbol is considered already analyzed if:
- It has a user-defined name (i.e., NOT an auto-generated prefix name like
a_XXXX, f_XXXX, p_XXXX, zpa_XX, zpf_XX, zpp_XX, e_XXXX), OR
- It is a well-known system address (hardware register, KERNAL entry point, OS variable).
To build the candidate list:
- Call
r2000_get_symbols again (labels were renamed by subagents).
- From the refreshed
r2000_get_symbols data, collect all labels whose name matches auto-generated patterns:
zpp_XX, zpf_XX and zpa_XX — auto-generated pointers, fields and absolute addresses in the zero page.
p_XXXX, f_XXXX, a_XXXX and e_XXXX — auto-generated pointers, fields, absolute addresses, and external ROM jump vectors outside the zero page.
- Do NOT include:
s_XXXX labels — those were handled in Phase 2.
b_XXXX labels — those are branch labels, not data symbols.
p_XXXX labels that are inside a Code block — those were handled as routine candidates in Phase 2.
- The remaining list = unanalyzed symbols.
3.2 Launch Parallel Subagents
-
CRITICAL: Always launch each subagent with an explicit target address (e.g., $XXXX or decimal NNNNN). NEVER use the "current cursor address" or rely on the active cursor location in the editor, as the cursor will change dynamically when running parallel subagents.
-
Up to 7 concurrent subagents (to avoid hitting rate limit quota errors like RESOURCE_EXHAUSTED).
-
Complete Queue Coverage: Unlike the routine phase, the symbol queue can be large. You MUST run the rolling window continuously until the entire remaining symbol queue is processed. Do not skip any unanalyzed custom symbols.
-
NO PREMATURE HALTING: The orchestrator MUST NOT truncate the candidate queue, skip custom symbols, or exit the rolling window phase early. Even if the custom symbol queue is very large (e.g., 50+ symbols), you must feed the queue continuously into the rolling window (replacing active slots immediately as subagents finish) until the entire list of unanalyzed custom symbols is fully processed. Halting early or classifying unanalyzed custom symbols as "skipped for review" is considered a workflow failure.
-
For each subagent, provide this prompt:
Read the skill file at .agent/skills/r2000-analyze-symbol/SKILL.md and follow its workflow.
Analyze the symbol at address $XXXX (decimal: NNNNN). Current label: {current_label}.
Binary info: system = {system}, filename = {filename}, description = {description}, may_contain_undocumented_opcodes = {hint}.
Apply all changes automatically — rename the label, add comments (line and/or side), and apply low/high byte formatting (r2000_set_immediate_format) to any instructions initializing the symbol. Do NOT ask for user confirmation.
When done, report: the old label, the new label name, the classification (flag, counter, pointer, state variable, etc.), and any uncertain areas.
-
Rolling window strategy:
- Launch the first 7 subagents (or fewer if the queue is smaller) to fill all slots.
- When any subagent completes, immediately launch the next symbol from the queue into the freed slot — do NOT wait for the entire batch to finish.
- Continue until all symbols in the queue have been launched and all subagents have completed.
- This keeps utilization high — if one subagent is slow, the other 6 slots stay busy.
- Error Fallback: If any subagent encounters a quota or model capacity error (e.g.,
RESOURCE_EXHAUSTED / Code 429), immediately catch the failure, log it, and queue the symbol to be processed sequentially or directly by the parent orchestrator after a brief delay.
3.3 Post-Phase Refresh
After all symbol subagents complete:
- Call
r2000_save_project to persist all changes.
Phase 4 — Save & Report
- Call
r2000_save_project one final time to ensure everything is persisted.
- Create a summary report for the user, including:
Blocks Summary
- Total number of blocks classified, grouped by type (Code, Byte, Word, PETSCII, etc.).
- Notable findings from block analysis (e.g., "Found 3 text strings at $1200", "Jump table at $0A00").
Routines Summary
Symbols Summary
Uncertain, Skipped, or Unanalyzed Items
- CRITICAL: The final report MUST document and list all symbols and routines that were left unanalyzed or skipped during the process. This includes any symbols/routines that:
- Were skipped due to queue size constraints or orchestrator prioritization.
- Were bypassed to prevent API quota/capacity exhaustions.
- Were flagged as uncertain or undetermined by subagents.
- You MUST NEVER report "no uncertain areas" or "0 errors/exhaustions" if there are any remaining unanalyzed auto-generated symbols (e.g.
f_XXXX, a_XXXX) or unanalyzed subroutines in the queue. They must be explicitly listed as Unanalyzed / Skipped Candidates for manual human review.
Errors, Resource Quotas & Fallbacks
- CRITICAL: Log any subagents that encountered errors, timeouts, or API capacity limits (e.g.
RESOURCE_EXHAUSTED / Code 429) during analysis.
- If the rolling queue was truncated or execution had to yield due to safe-guards (such as skipping a large queue of secondary data symbols), document this as a safety fallback.
- Include a structured table detailing:
- The target address.
- The symbol/routine entry point name.
- The planned subagent analysis role.
- The specific error code/message encountered (e.g.
RESOURCE_EXHAUSTED (code 429) or Orchestration safe-guard skip).
- The fallback handling mechanism used (e.g. "Resolved directly and sequentially by the parent orchestrator" or "Bypassed for manual human review due to queue limit").
Error Handling
- If a subagent fails, times out, or hits a rate limit (e.g.
RESOURCE_EXHAUSTED / Code 429), log the failure, cleanly terminate the background task if necessary, and fallback to direct sequential analysis of the failed target.
- CRITICAL: Do NOT discard or ignore these failures. You MUST document all such failed subagent targets, their addresses, error codes/messages, and their fallback resolutions in the final summary report under the dedicated "Errors, Resource Quotas & Fallbacks" section.
- If
r2000_save_project fails, warn the user immediately.
Example Invocation
The user says:
"Analyze this program"
The agent:
- Reads this skill file.
- Gathers context (Phase 0).
- Classifies blocks (Phase 1) — this may take several minutes for large binaries.
- Identifies 8 unanalyzed subroutines → launches 7 subagents, and as each one finishes immediately launches the next from the remaining 0 (Phase 2).
- Identifies 70 unanalyzed symbols → launches 7 subagents, and as each one finishes immediately launches the next from the remaining 63 (Phase 3).
- Saves and produces the summary report (Phase 4).