Change Explainer
Teach the change so the reader can predict its behavior and design the next change. Treat the diff, surrounding code, tests, and supplied observations as evidence; do not turn a plausible story into a claimed fact.
Input Contract
Require one comparison scope:
- A fixed point such as a commit, branch, tag, or merge base
- An explicit request to explain current working-tree changes relative to
HEAD
- A user-supplied patch or diff artifact
If the scope is missing or ambiguous, ask one concise question instead of guessing a base.
Treat every user- or repository-derived ref and path, including a patch path, as opaque data. Never interpolate it unescaped into shell command text. Pass it as one argument through structured execution or correct platform shell escaping, and use an option terminator when a CLI accepts one. For direct filesystem reads, use no-follow APIs, verify the opened descriptor still represents the inspected regular file, and never read through a symlink. If a no-follow read is unavailable, exclude the entry and report it.
For any Git-backed scope, set GIT_NO_LAZY_FETCH=1. Let <git-read> below mean the fixed prefix git --no-pager --no-optional-locks -c core.fsmonitor=false -c log.showSignature=false. For commands that consume exact paths, use <git-read> --literal-pathspecs and place -- before pathspecs; do not interpret those values as pathspec expressions.
- Resolve the repository root with
<git-read> rev-parse --show-toplevel, then run every Git and filesystem read from that root. Resolve HEAD once to an immutable commit OID and keep it as <head-oid>.
- When a fixed point is supplied, append
^{commit} as data and resolve the result with <git-read> rev-parse --verify --end-of-options as one argument. Never substitute the raw ref into a command template.
- For a local or remote branch ref, resolve
<git-read> merge-base <base-oid> <head-oid> and use that result as the baseline. For a commit object or tag ref, use the fixed-point OID itself as the baseline. This Git mode always compares that baseline to the pinned HEAD; if the user names another target, require a supplied patch or diff for that exact range. If the ref kind or the user's intended semantics are unclear, ask. Honor an explicit user choice between merge-base and supplied-snapshot semantics.
- For a fixed-point comparison, read committed changes with
<git-read> diff --no-ext-diff --no-textconv --ignore-submodules=none --submodule=short <baseline-oid> <head-oid> and commits with <git-read> log <baseline-oid>..<head-oid> --oneline. Enumerate changed paths separately with the same diff range plus --name-only -z. Report whether the baseline is a merge base or the supplied snapshot. Read changed and supporting source from those OIDs with snapshot-addressed object reads; do not mix a committed-only scope with the live checkout.
- For a worktree-only comparison, use
<head-oid> as the baseline and omit the commit range. Read tracked changes with <git-read> diff --no-ext-diff --no-textconv --ignore-submodules=none --submodule=short <head-oid>, enumerate tracked paths with the same diff plus --name-only -z, and collect status with <git-read> status --short --untracked-files=all --ignore-submodules=none -z. Enumerate untracked paths with <git-read> ls-files --others --exclude-standard --full-name -z. Inspect regular files inside the requested path scope. For symlinks, record only the link target text without following it; exclude other file types and report the reason. Record each entry's file type plus regular-file content fingerprint, symlink target text, or excluded-type metadata.
- Parse each
-z stream using that command's documented record grammar, never by lines. For short status, parse the XY metadata and paired rename or copy path fields; for --name-only and ls-files, each NUL token is a path. Treat only extracted repository-relative paths as opaque values and pass them as single arguments for later reads.
- Treat mode
160000 gitlinks as repository boundaries. For fixed-point scopes, report only old and new gitlink OIDs. For worktree scopes, also report the superproject-reported dirty state. Do not enter a submodule unless the user supplies it as a separate scope.
- Before answering a fixed-point explanation, re-resolve the original movable refs and
HEAD; restart or report a stale scope only if one changed. Do not inspect live worktree state for this mode.
- Before answering a worktree explanation, re-resolve
HEAD and recheck status, tracked diff, path sets, entry types, regular-file fingerprints, symlink target text, and excluded-type metadata. Restart or report a stale scope if they materially changed.
- Stop with a clear result when the scope is invalid or empty.
For a user-supplied patch or diff, capture the artifact once through the same safe path rules, record its fingerprint, and verify that it is non-empty and structurally readable without applying it. If it came from a path, recheck that entry type and fingerprint before answering. Treat it as self-contained unless the user identifies a matching repository and base that can be verified. Resolve a verified base to an immutable <patch-base-oid>, read surrounding source only from that snapshot, and re-resolve a movable base before answering; never borrow patch context from the live checkout. If the patch identity, type, fingerprint, or resolved base changed, restart or report a stale scope and stop. Without a verified base, mark claims outside the hunks as unknown, and ask for the base only when the requested explanation requires that context.
Default the reader to a repository contributor who knows the language but not this change. Honor a different audience when the user supplies one.
Remain read-only: do not edit source, tests, or project documentation. Do not run tests, builds, application code, or commands with repository or external side effects. Use already available results as evidence, and name a check that would resolve a material uncertainty instead of executing it.
Applicability Gate
After reading the scope, identify whether the change introduces or materially alters any of these:
- Control or data flow
- State or lifecycle
- Integration or persistence boundary
- Invariant, failure path, or concurrency behavior
- Framework or architectural mental model
If none changed, return the compact explanation. Do not manufacture depth or a quiz for a mechanical edit.
Workflow
- Pin the exact scope and audience.
- Reconstruct only the prior system context needed for this change.
- Trace changed symbols through necessary callers, callees, data models, and tests. Do not scan unrelated architecture.
- Choose one representative input, request, event, or state transition and follow it before and after the change.
- Order the explanation by concepts and runtime or dependency flow, not by filename or diff hunk order.
- Connect each material claim to a file, symbol, line, test, or observed command result.
- Separate observed facts from inference and unknowns.
Output Contract
Match the user's language. Omit headings that add no information.
Compact Explanation
Use for mechanical or familiar local changes:
- Intent or Observable Effect — cite a stated intent; when none exists, say intent is unknown and describe only the observed effect
- Before → After — the behavioral difference, or state that behavior is unchanged
- Evidence — the smallest useful file, symbol, or test references
Full Walkthrough
Use for changes that pass the applicability gate:
- Outcome — what capability or constraint changed
- Prior Mental Model — only the old concepts needed to understand the change
- Mechanism and Constraints — the central design move and observed constraints; include rationale only when evidence states it
- Worked Trace — one concrete before-and-after execution or data path
- Literate Change Walkthrough — changed code in concept, execution, or dependency order
- Invariants and Failure Paths — what must remain true and where behavior can stop or diverge
- Verification and Unknowns — what tests or observations establish, what is inferred, and what remains unknown
- Understanding Check — one to three causal or boundary questions for non-trivial changes; omit answers unless requested
Do not repeat the same fact in the outcome, trace, and walkthrough. Do not list every changed file unless every file is necessary to teach the flow.
Evidence Rules
- Cite local files with symbol or line context for material claims.
- For snapshot-only content, cite
<oid>:<path> with symbol or line context. Use a live local-file link only after verifying that the cited path matches that snapshot.
- Label structural conclusions as
inferred when no execution or test confirms them.
- Label missing evidence as
unknown; do not fill gaps with likely intent.
- Describe what a test actually covers, not what its name suggests.
- Prefer one representative trace over several shallow examples.
Responsibility Boundaries
- Do not perform a Standards, Spec, or general defect review. If a possible defect blocks a truthful explanation, isolate it under
Needs review. Suggest $code-review only when documented standards or an originating specification apply; otherwise suggest a separate targeted defect review.
- Do not propose a new architecture unless the user separately asks for design work.
- Do not write the explanation into the repository. Suggest
$project-context only for durable structural knowledge and $solution-capture only for a confirmed reusable lesson.
- Do not create a persistent course, lesson, exercise, or simulator. When the user wants to learn the change across sessions, the sibling
teach skill owns those artifacts and uses this skill as its evidence layer.
Teach and Micro-world Handoff
Keep this skill textual and read-only. A one-off change explanation ends here. For durable learning, exercises, or a micro-world, use $teach as the coordinated entry point; it invokes this skill first with the exact comparison scope, then owns the learning workspace.
Consider that handoff only when hidden state, time, branching, or spatial relationships are central and a static trace or Mermaid diagram cannot answer the reader's "what happens if" question.
When that condition holds:
- State the single question the interactive environment should answer.
- Name the minimum adjustable inputs and internal state that must be visible.
- Include step, reset, or replay only when the behavior needs it.
- Pass the evidence references, fact/inference boundaries, and unknowns to
$teach so the interactive model does not invent runtime semantics.
Do not create a simulator, debugger, migration console, HTML renderer, or project artifact inside this skill.
1---2name: change-explainer3description: Teach a fixed-point code change or supplied patch as a source-grounded walkthrough organized by concepts and execution flow instead of a file-by-file diff summary. Use only when explicitly invoked as `$change-explainer` with a commit, branch, tag, base, patch, diff, or explicit current-changes scope, especially for cross-module behavior, migrations, state or concurrency changes, and unfamiliar frameworks. Do not use for defect review, implementation, or durable project documentation.4---56# Change Explainer78Teach the change so the reader can predict its behavior and design the next change. Treat the diff, surrounding code, tests, and supplied observations as evidence; do not turn a plausible story into a claimed fact.910## Input Contract1112Require one comparison scope:1314- A fixed point such as a commit, branch, tag, or merge base15- An explicit request to explain current working-tree changes relative to `HEAD`16- A user-supplied patch or diff artifact1718If the scope is missing or ambiguous, ask one concise question instead of guessing a base.1920Treat every user- or repository-derived ref and path, including a patch path, as opaque data. Never interpolate it unescaped into shell command text. Pass it as one argument through structured execution or correct platform shell escaping, and use an option terminator when a CLI accepts one. For direct filesystem reads, use no-follow APIs, verify the opened descriptor still represents the inspected regular file, and never read through a symlink. If a no-follow read is unavailable, exclude the entry and report it.2122For any Git-backed scope, set `GIT_NO_LAZY_FETCH=1`. Let `<git-read>` below mean the fixed prefix `git --no-pager --no-optional-locks -c core.fsmonitor=false -c log.showSignature=false`. For commands that consume exact paths, use `<git-read> --literal-pathspecs` and place `--` before pathspecs; do not interpret those values as pathspec expressions.23241. Resolve the repository root with `<git-read> rev-parse --show-toplevel`, then run every Git and filesystem read from that root. Resolve `HEAD` once to an immutable commit OID and keep it as `<head-oid>`.252. When a fixed point is supplied, append `^{commit}` as data and resolve the result with `<git-read> rev-parse --verify --end-of-options` as one argument. Never substitute the raw ref into a command template.263. For a local or remote branch ref, resolve `<git-read> merge-base <base-oid> <head-oid>` and use that result as the baseline. For a commit object or tag ref, use the fixed-point OID itself as the baseline. This Git mode always compares that baseline to the pinned `HEAD`; if the user names another target, require a supplied patch or diff for that exact range. If the ref kind or the user's intended semantics are unclear, ask. Honor an explicit user choice between merge-base and supplied-snapshot semantics.274. For a fixed-point comparison, read committed changes with `<git-read> diff --no-ext-diff --no-textconv --ignore-submodules=none --submodule=short <baseline-oid> <head-oid>` and commits with `<git-read> log <baseline-oid>..<head-oid> --oneline`. Enumerate changed paths separately with the same diff range plus `--name-only -z`. Report whether the baseline is a merge base or the supplied snapshot. Read changed and supporting source from those OIDs with snapshot-addressed object reads; do not mix a committed-only scope with the live checkout.285. For a worktree-only comparison, use `<head-oid>` as the baseline and omit the commit range. Read tracked changes with `<git-read> diff --no-ext-diff --no-textconv --ignore-submodules=none --submodule=short <head-oid>`, enumerate tracked paths with the same diff plus `--name-only -z`, and collect status with `<git-read> status --short --untracked-files=all --ignore-submodules=none -z`. Enumerate untracked paths with `<git-read> ls-files --others --exclude-standard --full-name -z`. Inspect regular files inside the requested path scope. For symlinks, record only the link target text without following it; exclude other file types and report the reason. Record each entry's file type plus regular-file content fingerprint, symlink target text, or excluded-type metadata.296. Parse each `-z` stream using that command's documented record grammar, never by lines. For short status, parse the XY metadata and paired rename or copy path fields; for `--name-only` and `ls-files`, each NUL token is a path. Treat only extracted repository-relative paths as opaque values and pass them as single arguments for later reads.307. Treat mode `160000` gitlinks as repository boundaries. For fixed-point scopes, report only old and new gitlink OIDs. For worktree scopes, also report the superproject-reported dirty state. Do not enter a submodule unless the user supplies it as a separate scope.318. Before answering a fixed-point explanation, re-resolve the original movable refs and `HEAD`; restart or report a stale scope only if one changed. Do not inspect live worktree state for this mode.329. Before answering a worktree explanation, re-resolve `HEAD` and recheck status, tracked diff, path sets, entry types, regular-file fingerprints, symlink target text, and excluded-type metadata. Restart or report a stale scope if they materially changed.3310. Stop with a clear result when the scope is invalid or empty.3435For a user-supplied patch or diff, capture the artifact once through the same safe path rules, record its fingerprint, and verify that it is non-empty and structurally readable without applying it. If it came from a path, recheck that entry type and fingerprint before answering. Treat it as self-contained unless the user identifies a matching repository and base that can be verified. Resolve a verified base to an immutable `<patch-base-oid>`, read surrounding source only from that snapshot, and re-resolve a movable base before answering; never borrow patch context from the live checkout. If the patch identity, type, fingerprint, or resolved base changed, restart or report a stale scope and stop. Without a verified base, mark claims outside the hunks as `unknown`, and ask for the base only when the requested explanation requires that context.3637Default the reader to a repository contributor who knows the language but not this change. Honor a different audience when the user supplies one.3839Remain read-only: do not edit source, tests, or project documentation. Do not run tests, builds, application code, or commands with repository or external side effects. Use already available results as evidence, and name a check that would resolve a material uncertainty instead of executing it.4041## Applicability Gate4243After reading the scope, identify whether the change introduces or materially alters any of these:4445- Control or data flow46- State or lifecycle47- Integration or persistence boundary48- Invariant, failure path, or concurrency behavior49- Framework or architectural mental model5051If none changed, return the compact explanation. Do not manufacture depth or a quiz for a mechanical edit.5253## Workflow54551. Pin the exact scope and audience.562. Reconstruct only the prior system context needed for this change.573. Trace changed symbols through necessary callers, callees, data models, and tests. Do not scan unrelated architecture.584. Choose one representative input, request, event, or state transition and follow it before and after the change.595. Order the explanation by concepts and runtime or dependency flow, not by filename or diff hunk order.606. Connect each material claim to a file, symbol, line, test, or observed command result.617. Separate observed facts from inference and unknowns.6263## Output Contract6465Match the user's language. Omit headings that add no information.6667### Compact Explanation6869Use for mechanical or familiar local changes:70711. **Intent or Observable Effect** — cite a stated intent; when none exists, say intent is unknown and describe only the observed effect722. **Before → After** — the behavioral difference, or state that behavior is unchanged733. **Evidence** — the smallest useful file, symbol, or test references7475### Full Walkthrough7677Use for changes that pass the applicability gate:78791. **Outcome** — what capability or constraint changed802. **Prior Mental Model** — only the old concepts needed to understand the change813. **Mechanism and Constraints** — the central design move and observed constraints; include rationale only when evidence states it824. **Worked Trace** — one concrete before-and-after execution or data path835. **Literate Change Walkthrough** — changed code in concept, execution, or dependency order846. **Invariants and Failure Paths** — what must remain true and where behavior can stop or diverge857. **Verification and Unknowns** — what tests or observations establish, what is inferred, and what remains unknown868. **Understanding Check** — one to three causal or boundary questions for non-trivial changes; omit answers unless requested8788Do not repeat the same fact in the outcome, trace, and walkthrough. Do not list every changed file unless every file is necessary to teach the flow.8990## Evidence Rules9192- Cite local files with symbol or line context for material claims.93- For snapshot-only content, cite `<oid>:<path>` with symbol or line context. Use a live local-file link only after verifying that the cited path matches that snapshot.94- Label structural conclusions as `inferred` when no execution or test confirms them.95- Label missing evidence as `unknown`; do not fill gaps with likely intent.96- Describe what a test actually covers, not what its name suggests.97- Prefer one representative trace over several shallow examples.9899## Responsibility Boundaries100101- Do not perform a Standards, Spec, or general defect review. If a possible defect blocks a truthful explanation, isolate it under `Needs review`. Suggest `$code-review` only when documented standards or an originating specification apply; otherwise suggest a separate targeted defect review.102- Do not propose a new architecture unless the user separately asks for design work.103- Do not write the explanation into the repository. Suggest `$project-context` only for durable structural knowledge and `$solution-capture` only for a confirmed reusable lesson.104- Do not create a persistent course, lesson, exercise, or simulator. When the user wants to learn the change across sessions, the sibling [`teach`](../teach/SKILL.md) skill owns those artifacts and uses this skill as its evidence layer.105106## Teach and Micro-world Handoff107108Keep this skill textual and read-only. A one-off change explanation ends here. For durable learning, exercises, or a micro-world, use `$teach` as the coordinated entry point; it invokes this skill first with the exact comparison scope, then owns the learning workspace.109110Consider that handoff only when hidden state, time, branching, or spatial relationships are central and a static trace or Mermaid diagram cannot answer the reader's "what happens if" question.111112When that condition holds:1131141. State the single question the interactive environment should answer.1152. Name the minimum adjustable inputs and internal state that must be visible.1163. Include step, reset, or replay only when the behavior needs it.1174. Pass the evidence references, fact/inference boundaries, and unknowns to `$teach` so the interactive model does not invent runtime semantics.118119Do not create a simulator, debugger, migration console, HTML renderer, or project artifact inside this skill.