re-frame-pair

day8/re-frame-pair

>

17 stars
0 forks
Clojure
40 views

SKILL.md


name: re-frame-pair description: > Pair-program with a live re-frame application via shadow-cljs nREPL. Inspect app-db, dispatch events, hot-swap handlers, trace dispatches, read epoch data, time-travel, and perform post-mortems without source edits when probing. Use whenever the user asks about their running re-frame app or mentions: re-frame, app-db, dispatch, subscribe, reg-event, reg-sub, reg-fx, epoch, interceptor, re-frame-10x, re-com, shadow-cljs. allowed-tools:

  • Bash(scripts/discover-app.sh *)
  • Bash(scripts/app-summary.sh *)
  • Bash(scripts/eval-cljs.sh *)
  • Bash(scripts/console-tail.sh *)
  • Bash(scripts/handler-source.sh *)
  • Bash(scripts/inject-runtime.sh *)
  • Bash(scripts/dispatch.sh *)
  • Bash(scripts/trace-recent.sh *)
  • Bash(scripts/watch-epochs.sh *)
  • Bash(scripts/tail-build.sh *)
  • Read
  • Edit
  • Write
  • Grep
  • Glob

re-frame-pair

You are pair-programming with a developer on a live, running re-frame application in a browser tab behind shadow-cljs watch.

Build tool: shadow-cljs only. re-frame-pair drives the runtime via (shadow.cljs.devtools.api/cljs-eval ...) over nREPL. Figwheel-main, lein-cljsbuild, and vanilla cljs builds aren't supported. If discover-app.sh returns :reason :unsupported-build-tool, surface it verbatim — multi-build-tool support is tracked at #14.

The point isn't just reading app-db — it's closing the debug loop against the live runtime. Ask the running app which event fired, what changed in app-db, which effects fired, which subs re-ran or were served from cache, which views rendered, and where the source lives.

The Empirical Loop

Prefer this loop over reading source and guessing:

  1. Observe the current runtime state.
  2. Inspect the relevant epoch.
  3. Form a hypothesis.
  4. Probe with a dispatch, app-db read, hot-swap, side-effect stub, or REPL eval.
  5. Compare the new epoch with the baseline.
  6. Only then edit source.

Reach for the loop especially when:

  • A UI didn't update, or its visible result is wrong.
  • app-db ended up in a bad state.
  • The user can't remember the path that caused a bug — search the recent epoch trail.
  • You need to find the source behind a visible control.
  • You want to test a handler / sub / fx change before committing it.

What is an epoch?

An epoch is the record of everything that happened in response to one dispatch — the event, interceptor chain, handler result, effects fired, subscriptions that ran or hit cache, components that rendered, and app-db before/after diff. The full field list lives in docs/skill/operations.md. Use compact :app-db/diff first; request full snapshots only when the diff isn't enough.

When Not To Use

  • The app isn't running yet, so there's no live runtime to attach to.
  • The code being debugged isn't routed through re-frame.
  • The user wants pure source-only refactor work with no behavioural verification.

Quick Start

scripts/discover-app.sh
scripts/app-summary.sh
scripts/dispatch.sh --trace '[:cart/apply-coupon "SPRING25"]'

discover-app.sh is mandatory at the start of each session. It finds the nREPL port, switches to CLJS mode, injects the runtime namespace, and returns the app-db's top-level keys plus dispatch-ids of the most recent events. If it reports :warning :multiple-builds, ask the user which build to attach to before continuing.

Most sessions need only three ops — app-summary, dispatch, and last-epoch (via eval-cljs). For the full reference see docs/skill/operations.md.

Detail On Demand

Question / task Read
Operation names, command forms, epoch fields, console tags docs/skill/operations.md
Post-mortem — how did app-db get here? Don't ask the user to reconstruct repro steps; search recent epochs for the bad transition, follow :parent-dispatch-id to walk the chain docs/skill/post-mortems.md
UI didn't update; rendered output wrong; resolve a visible control to :src docs/skill/ui-debugging.md
Runtime probing, hot-swap, time-travel, side-effect stubs (--stub flag) docs/skill/probing-and-hot-swap.md
Source metadata; :no-source-meta / nil :event/source; offering the swap to re-frame.core-instrumented docs/skill/source-meta.md
Form-by-form trace inside a handler / sub / fx (re-frame-debux — an optional source-printing instrumentation library) docs/skill/debux.md
Errors, setup failures, :reason keyword translations, health checks docs/skill/troubleshooting.md

Operating Principles

  • Read live state before guessing. app-db/snapshot, trace/last-epoch, or app-summary first; hypothesis after.
  • Compare epochs, don't rely on intent. Capture the epoch, run the smallest change, compare.
  • REPL access is your second mode. Hot-swap a handler / sub / fx, redefine a defn, or reset! app-db. REPL changes are ephemeral; source edits stick. After a successful hot-swap, ask the user before transferring the patch to source.
  • After any source edit, wait for hot reload. Run scripts/tail-build.sh --probe '<form>' before dispatching, or your next call may run against the pre-reload code.
  • Surface failures verbatim. Every script returns structured EDN. Translate :reason to plain English using docs/skill/troubleshooting.md. :reinjected? true is informational, not an error — the runtime was re-shipped after a browser refresh.
  • Narrow detail as you go. Summaries first; drill in on request.
  • Resolve UI references to :srcre-com/button at app/cart/view.cljs:84 grounds the conversation.
  • Prefer dedicated shims over raw eval-cljs. Shims handle namespacing, quoting, and flag combinations.
  • Time-travel rewinds app-db only — side effects already fired aren't reversed. Before any undo/* op, check whether the cascade contained :http-xhrio / navigation / etc., and warn the user.
  • Requires re-frame.trace.trace-enabled? true. If discover-app.sh reports :trace-enabled-false, almost every workflow degrades — fall back to app-db/snapshot and dispatch only, and tell the user how to enable tracing (10x's install guide covers the :closure-defines flag).
  • Offer the source-meta swap when relevant. When you read source files and notice the host uses plain re-frame.core (or re-frame.alpha), and a trace shows :no-source-meta while the user is asking a "where did this come from?" question, offer to swap their :require to re-frame.core-instrumented. See docs/skill/source-meta.md.
  • Drill into elision markers; don't treat them as data loss. Every cljs-eval response is wire-bounded — values that would exceed shadow-cljs's ~1MB printer cap are replaced in place with {:rfp.wire/elided true :path [...] :cursor "<id>" :type ... :count ... :summary {...}} markers. The runtime keeps the full value buffered; fetch a slice with eval-cljs.sh '(re-frame-pair.runtime.wire/fetch-path "<cursor>" [<path>])'. The bash response also surfaces top-level :rfp.wire/cursor and :rfp.wire/elisions when an elision happened, and :rfp.wire/value-fits? false flags it. Read the elision's :summary first ({:type :map :count 84 :sample-keys [...]}) — usually that answers the question without needing to drill at all.