
A Claude Code skill that gives Claude **internals-informed mental models** for building and debugging Hotwire applications. Core philosophy: *enhance the browser, don't reinvent it* — start by imagining a JS-free, plain-HTML version of every feature, then compose the pages into an integrated UI with Turbo. HTML is the source of truth for state, everywhere.

It complements [Better Stimulus](/documentation/ai-tools/better-stimulus/) (the authority for *writing* controllers) and [Rails Hotwire Driver](/documentation/ai-tools/rails-hotwire-driver/) (which *exercises* a running Hotwire app from the terminal). This skill is the **knowledge layer** — how Turbo and Stimulus actually work under the hood.

---

## What Is This?

A Claude Code skill that helps Claude reason about:

- **Turbo Drive, Frames, and Streams** — how each observer scopes an update, and the classic frame-id mismatch that produces "Content missing"
- **Morphing** — the idiomorph algorithm, exactly when a morph runs, and how to exclude elements
- **Turbo Cache** — snapshot mechanics, preview flashing, `turbo-permanent`, and cache-control
- **Broadcasting** — ActionCable stream sources, the ~0.5s debounce, and request-id dedup
- **Stimulus design** — callbacks over `connect`, composition via events vs outlets
- **Hotwire Native** — Path Configuration, Bridge Components, and the native-adapter mental model
- **Testing & debugging** — system-test flakiness, collaborative tests, legacy migration, and internals-informed debugging

It is delivered as a **skill** (a knowledge module plus focused reference files), not an autonomous agent. Claude reads `SKILL.md` for the decision frameworks and pulls in a reference only when a specific branch needs it.

---

## The Escalation Ladder

The skill's central idea: Hotwire is a **cost/benefit dial, not a single approach**. Choose the cheapest tool that works, and escalate only when the previous rung stops being a good tradeoff:

1. **Turbo Drive + Morphing refreshes** — re-render everything server-side; fastest to build.
2. **Turbo Frames** — decompose the page; localize updates without touching the rest.
3. **Turbo Stream actions** — surgical DOM updates; more precise, more maintenance cost.
4. **Stimulus** — small client-side behavior where a server round-trip makes no sense.
5. **Island of a reactive framework or API calls** — only for genuinely high-interactivity widgets (maps, editors).

Different parts of one app can sit on different rungs; it all composes.

---

## Quick Start

### 1. Add the Marketplace

```bash
/plugin marketplace add maquina-app/rails-claude-code
```

### 2. Install the Plugin

```bash
/plugin install hotwire-patterns@maquina
```

### 3. Ask About Hotwire

The skill triggers on Hotwire design decisions and symptoms:

```
> Why does morphing wipe my form?
> My Turbo Stream broadcast isn't arriving
> This system test is flaky
> How do I add Turbo to a legacy app?
> Wrap my app with Hotwire Native
```

---

## What It Covers

The main `SKILL.md` holds the decision frameworks and per-topic essentials; each deep dive lives in a reference file Claude loads on demand.

| Topic | Reference | Highlights |
|-------|-----------|-----------|
| Turbo internals | (in SKILL.md) | Drive/Frames/Streams observers, `_top` escaping, lazy frames, the frame-id mismatch |
| Morphing | `morphing.md` | idiomorph algorithm, when morph actually runs, scoped exclusion via `turbo:before-morph-element` |
| Turbo Cache | (in SKILL.md) | snapshot `cloneNode`, preview flashing, `data-turbo-temporary`, cache-control meta |
| Broadcasting | (in SKILL.md) | signed stream names, the background-job debounce, originating-client dedup |
| Stimulus design | `stimulus.md` | callbacks over `connect`, events vs outlets, the dynamic-forms server-render pattern |
| Hotwire Native | `hotwire-native.md` | native adapter, Path Configuration, Bridge Components, publishing |
| Testing | `testing-and-legacy.md` | flakiness (assert stable state), multi-session broadcast tests, gradual Turbo adoption |
| Debugging | `debugging.md` | unminify Turbo, DOM break-on breakpoints, source landmarks, ActionCable filtering |

---

## Custom Stream Actions

A recurring theme: the **correct UI update is only known server-side after processing**. Custom Turbo Stream actions are the sanctioned way to run backend-driven browser behavior with a constrained, maintainable vocabulary — and they keep you CSP-compatible (no `unsafe-inline`):

```javascript
Turbo.StreamActions.log = function () {
  console.log(this.getAttribute("message"))
}
```

Pair with a Ruby helper module included into `Turbo::Streams::TagBuilder`. Prefer small, app-specific actions over dropping in large libraries.

---

## Package Contents

```
hotwire-patterns/
└── skills/hotwire-patterns/
    ├── SKILL.md                    # Overview + decision frameworks + per-topic essentials
    └── references/
        ├── morphing.md             # idiomorph algorithm and gotchas
        ├── stimulus.md             # reusable, composable controller design
        ├── hotwire-native.md       # iOS/Android wrapping
        ├── testing-and-legacy.md   # system tests + gradual Turbo adoption
        └── debugging.md            # internals-informed debugging
```

---

## Team Installation

Add to your project's `.claude/settings.json`:

```json
{
  "extraKnownMarketplaces": {
    "maquina": {
      "source": {
        "source": "github",
        "repo": "maquina-app/rails-claude-code"
      }
    }
  },
  "enabledPlugins": [
    "hotwire-patterns@maquina"
  ]
}
```

---

## Next Steps

<div class="not-prose mt-8 grid grid-cols-1 gap-4 sm:grid-cols-2">
  <a href="https://github.com/maquina-app/rails-claude-code" target="_blank" rel="noopener" class="group relative rounded-2xl border border-zinc-200 p-6 hover:border-[#50B1FD]/50 dark:border-zinc-800 dark:hover:border-[#50B1FD]/50 transition">
    <h3 class="font-sora font-semibold text-zinc-900 dark:text-white group-hover:text-[#50B1FD] transition">
      GitHub Repository
    </h3>
    <p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
      View source code and contribute.
    </p>
  </a>

  <a href="/documentation/ai-tools/better-stimulus/" class="group relative rounded-2xl border border-zinc-200 p-6 hover:border-[#50B1FD]/50 dark:border-zinc-800 dark:hover:border-[#50B1FD]/50 transition">
    <h3 class="font-sora font-semibold text-zinc-900 dark:text-white group-hover:text-[#50B1FD] transition">
      Better Stimulus
    </h3>
    <p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
      Write the Stimulus controllers behind your Hotwire UI.
    </p>
  </a>

  <a href="/documentation/ai-tools/rails-hotwire-driver/" class="group relative rounded-2xl border border-zinc-200 p-6 hover:border-[#50B1FD]/50 dark:border-zinc-800 dark:hover:border-[#50B1FD]/50 transition">
    <h3 class="font-sora font-semibold text-zinc-900 dark:text-white group-hover:text-[#50B1FD] transition">
      Rails Hotwire Driver
    </h3>
    <p class="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
      Exercise a running Hotwire app from the terminal.
    </p>
  </a>
</div>
