Skip to content

Ripple Edits

Ripple edits answer the question every refactor begs: “What else needs to change because I changed this?” After each edit, BMO walks the LSP reference graph from the touched symbols, ranks the affected sites, and surfaces them as context for the agent. When suggested edits are enabled, BMO can also return concrete follow-up edits.

Ripple analysis runs at four call sites. The trigger field on ripple.fired distinguishes them:

TriggerWherePurpose
pre_editBefore write / edit / multiedit apply changesWarns the agent about likely follow-ups before it commits to an edit shape
post_editAfter edit, multiedit, and lsp_symbol_edit succeedLists concrete files/symbols whose references the edit just shifted
toolDirect lsp_ripple_impact agent-tool callLets the agent ask “what depends on this file?” without making a change
analyze_ripple_impactSuggested-edits analyzer, also the embedded path used by edit/multiedit to produce suggestionsReturns ranked rename-style suggestions, not just an impact list
  • Impact analysis. Ripple walks LSP findReferences, applies CODEOWNERS scoping, and returns affected files and symbol counts. It is always on whenever an LSP client is configured.
  • Suggested edits. BMO can build on impact analysis by computing a rename map and a single before/after diff, gated by [options.suggested_edits].mode:
    • advisory (default) — surface suggestions; the agent decides.
    • required — when ripple is unavailable, or when cached reference locations are missing or expired, the edit still succeeds but the response metadata and downstream change contract mark the follow-up requirement unmet.

The full reference lives in the [options.suggested_edits] section. Minimal example:

[options.suggested_edits]
mode = "advisory" # or "required"

Caps, the suggested-edits cache TTL, and the analyzer timeout are compile-time constants today. View their effective values with bmo config show-ripple or /ripple (see below).

Aliases: /ripple-status, /rip. Read-only. Renders:

  • State (ready (LSP clients: N) or ripple unavailable — LSP not configured or ready)
  • Effective caps (symbols_per_file, affected_files, rename_map_entries)
  • Default analyzer timeout and cached-reference TTL
  • Resolved [options.suggested_edits] mode
  • The most recent paired ripple.fired / ripple.action from a process-scoped 16-entry ring buffer

The default text view renders the same snapshot contract as /ripple, but in detached CLI mode it truthfully reports that recent ripple events are not available from another process. Use bmo config show-ripple --format=json for the canonical config-only snapshot payload. Live recent-event tails remain in-process only.

The TUI sidebar shows a one-line Ripple: status — ready, capped N, warn, or LSP unavailable — derived from the same ring buffer. Missing LSP is reported as dependency-unavailable state; BMO reserves disabled wording for operator/config gates.

Both lsp_ripple_impact and analyze_ripple_impact are exposed to agents. The /ripple command is registered as AgentParityReadOnly with those two tool hints, so agents discovering the operator surface map see the corresponding tools.

OutcomeWhenLevelWhat operators see
skipped_no_lspNo LSP client configured for the source file’s languageinfoSingle ripple.action event; ripple did not run
skipped_no_symbolsLSP returned no document symbolsinfoSingle ripple.action; nothing to walk
timed_outAnalyzer exceeded the default timeout (1s pre-edit, 2s post-edit)warnripple.action action="timed_out" elapsed_ms=...
erroredLSP findReferences or CODEOWNERS lookup failedwarnripple.action action="errored" continuation event
phase_errorA non-fatal phase failed mid-analysis (codeowners load, per-symbol find-references)warnripple.action action="phase_error" phase=... [symbol=...] error=... — analysis continues with partial results
cappedHit symbols_per_file, affected_files, or rename_map_entries=50 capwarnAdvisory ripple.action action="capped" cap=..., paired with a terminal action that still completes

capped is an advisory event — the run continues with truncated input. The Last-analysis line in /ripple always shows the terminal action, not the capped advisory. When required mode cannot turn ripple output into concrete follow-up suggestions because cached references are unavailable, the tool metadata and change contract preserve that requirement gap instead of collapsing it into a silent empty-success case.

Ripple emits exactly two structured slog events per analysis. Every ripple.fired is paired with exactly one terminal ripple.action (with zero or more capped advisories interleaved).

FieldTypeWhen set
invocation_iduint64Always — pairs fired with its closing action
session_idstringAlways
source_filestringAlways
triggerstringOne of pre_edit, post_edit, tool, analyze_ripple_impact, or "" (legacy Analyze callers)
modestringSuggested edits only: advisory or required
rename_map_sizeintSuggested edits only
timeout_msintImpact analysis only
FieldTypeWhen set
invocation_iduint64Always — mirrors the paired ripple.fired
session_idstringAlways
source_filestringAlways
triggerstringMirrors the paired ripple.fired
actionstringOne of: analyzed, skipped_no_lsp, skipped_no_symbols, timed_out, errored, succeeded, no_suggestions, unavailable_advisory, unavailable_required, capped, phase_error
affected_countintImpact-analysis terminal actions
symbol_countintImpact-analysis terminal actions
suggestions_countintSuggested-edits terminal actions
modestringSuggested edits
capstringaction="capped" only — one of symbols_per_file, affected_files, rename_map_entries
input_sizeintaction="capped" only — pre-truncation size
cap_sizeintaction="capped" only — applied cap
phasestringaction="phase_error" only — e.g. codeowners_load, find_references
symbolstringaction="phase_error" only — symbol name when the phase is per-symbol
errorstringaction="phase_error" only — wrapped error message
elapsed_msint64Impact-analysis terminal actions

Levels: terminal impact-analysis successes (analyzed, skipped_*) and suggested-edits advisory outcomes log at info. timed_out, errored, unavailable_required, phase_error, and all capped advisories log at warn.