Agent skill

Turbo

by smnandre in smnandre/symfony-ux-skills

Hotwire Turbo for Symfony UX -- SPA-like speed with zero JavaScript.

MITAuto-check passedBackend & APIs

Install Turbo

skills CLI
$ npx skills add smnandre/symfony-ux-skills --skill turbo -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install smnandre/symfony-ux-skills turbo --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/smnandre/symfony-ux-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/turbo .claude/skills/turbo && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
turbo
GitHub stars
180
Token cost
~2.9k tokens
SKILL.md length
533 words
Files
4 (incl. references)
Skills in repo
7
Repo updated
First seen
Licence
MIT

At a glance

Hotwire Turbo for Symfony UX -- SPA-like speed with zero JavaScript.

  • Building ajax navigation
  • SKILL.md covers Decision Tree, Installation, Turbo Drive and Turbo Frames, plus 6 more sections
  • Calls composer
  • Lazy-loaded sections

What it does

Turbo is an agent skill from smnandre/symfony-ux-skills. Hotwire Turbo for Symfony UX -- SPA-like speed with zero JavaScript. Covers Drive (navigation), Frames (partial page sections), and Streams (multi-target updates). Use when building ajax navigation, lazy-loaded sections, inline editing, pagination without reload, modals from the server, flash messages via streams, or real-time updates via Mercure/SSE. Code triggers: turbo-frame, turbo-stream, data-turbo-frame, data-turbo, data-turbo-action, turbo-stream-source, TurboStreamResponse, <twig:Turbo:Frame…

Its SKILL.md is about 2.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files, including reference files (for example `references/api.md`, `references/gotchas.md` and `references/patterns.md`).

It sits in Backend & APIs. It works with Symfony, JavaScript and Google Gemini. The repository describes itself as: Symfony UX skills for Claude, Gemini, Codex, ... Live Component, Twig Component, Turbo, Stimulus. The licence is MIT.

When your agent uses it

  • Building ajax navigation
  • Lazy-loaded sections
  • Pagination without reload
  • Modals from the server

Example prompts

  • “how to update part of the page without reload”
  • “how to make navigation feel like SPA”
  • “how to lazy-load a section”
  • “/turbo”

What it can do on your machine

Read from SKILL.md and the folder at commit 1e99301. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • composer

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Turbo loads about 2.9k tokens when it runs, and up to ~11k if it reads all its reference files. Until then it costs about 254 tokens; SKILL.md has 533 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~254
When it runs · the whole SKILL.md, loaded when a task matches
~2.9k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~11k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from smnandre/symfony-ux-skills at commit 1e99301, republished under its MIT licence (© smnandre). 533 words, ~2,872 tokens.

Download SKILL.mdSave it as .claude/skills/turbo/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.
name
turbo
description
Hotwire Turbo for Symfony UX -- SPA-like speed with zero JavaScript. Covers Drive (navigation), Frames (partial page sections), and Streams (multi-target updates). Use when building ajax navigation, lazy-loaded sections, inline editing, pagination without reload, modals from the server, flash messages via streams, or real-time updates via Mercure/SSE. Code triggers: turbo-frame, turbo-stream, data-turbo-frame, data-turbo, data-turbo-action, turbo-stream-source, TurboStreamResponse, <twig:Turbo:Frame>, <twig:Turbo:Stream:Append>, <twig:Turbo:Stream:Replace>, turbo:before-fetch-request. Also trigger when the user asks "how to update part of the page without reload", "how to make navigation feel like SPA", "how to lazy-load a section", "how to do inline editing", "how to push real-time updates from server", "how to use Mercure with Turbo". Do NOT trigger for client-side JS behavior (use stimulus), server-rendered reactive components (use live-component), or reusable static UI (use twig-component).
license
MIT
metadata.author
Simon Andre
metadata.email
smn.andre@gmail.com
metadata.url
https://smnandre.dev
metadata.version
1.2.0

Turbo

Hotwire Turbo provides SPA-like speed with server-rendered HTML. No JavaScript to write. Three components work together:

  • Drive -- Automatic AJAX navigation for all links and forms (zero config)
  • Frames -- Scoped navigation that updates only one section of the page
  • Streams -- Server-pushed DOM mutations (append, replace, remove, etc.)

Decision Tree

Need to update the page?
+-- Full page navigation          -> Turbo Drive (automatic, already active)
+-- Single section from user click -> Turbo Frame
+-- Multiple sections from action  -> Turbo Stream (HTTP response)
+-- Real-time from server/others   -> Turbo Stream (Mercure / SSE)

Installation

bash
composer require symfony/ux-turbo

That's it. Turbo Drive is active immediately -- all links and forms become AJAX.

Turbo Drive

Automatic SPA-like navigation. Every <a> click and <form> submit is intercepted, fetched via AJAX, and the <body> is swapped. The browser URL and history update normally.

Disabling for Specific Elements
html
<!-- Disable on link/form -->
<a href="/external" data-turbo="false">External Link</a>

<!-- Disable for entire section -->
<div data-turbo="false">
    <a href="/normal">Normal link (no Turbo)</a>
</div>
History and Caching
html
<!-- Replace history instead of push -->
<a href="/page" data-turbo-action="replace">Replace History</a>

<!-- Force full reload when asset changes -->
<link rel="stylesheet" href="/app.css" data-turbo-track="reload">
<script src="/app.js" data-turbo-track="reload"></script>

Turbo Frames

Scope navigation to a section of the page. Links and forms inside a frame update only that frame's content. The rest of the page stays untouched.

Basic Frame
html
<!-- Page with frame -->
<turbo-frame id="messages">
    <h2>Messages</h2>
    <a href="/messages/1">View Message 1</a>  <!-- Updates only this frame -->
</turbo-frame>

<!-- /messages/1 response must contain a matching frame ID -->
<turbo-frame id="messages">
    <h2>Message 1</h2>
    <p>Content here...</p>
    <a href="/messages">Back to list</a>
</turbo-frame>

The server response is a full HTML page, but Turbo extracts only the matching <turbo-frame> and swaps it in.

Lazy Loading

Load frame content asynchronously after the page renders:

html
<turbo-frame id="notifications" src="/notifications" loading="lazy">
    <p>Loading...</p>
</turbo-frame>
Target Another Frame

A link inside one frame can update a different frame:

html
<turbo-frame id="sidebar">
    <a href="/item/1" data-turbo-frame="main-content">View Item</a>
</turbo-frame>

<turbo-frame id="main-content">
    <!-- Content replaced here -->
</turbo-frame>
Break Out of Frame

Navigate the entire page from within a frame:

html
<turbo-frame id="modal">
    <a href="/dashboard" data-turbo-frame="_top">Go to Dashboard</a>
</turbo-frame>
Frame with Form

Forms inside frames submit and update within that frame:

html
<turbo-frame id="search-results">
    <form action="/search" method="get">
        <input type="search" name="q">
        <button>Search</button>
    </form>
    <ul>
        {% for item in results %}
            <li>{{ item.name }}</li>
        {% endfor %}
    </ul>
</turbo-frame>
URL Sync

Update the browser URL when a frame navigates (useful for bookmarkable state):

html
<turbo-frame id="products" data-turbo-action="advance">
    <!-- Browser URL updates when this frame navigates -->
</turbo-frame>

Turbo Streams

Update multiple DOM elements from a single server response. Eight actions available (append, prepend, replace, update, remove, before, after, refresh), each targeting elements by ID or CSS selector.

Stream Actions
html
<turbo-stream action="append" target="messages">
    <template><div id="msg_1">New message</div></template>
</turbo-stream>

<turbo-stream action="prepend" target="messages">
    <template><div id="msg_0">First!</div></template>
</turbo-stream>

<turbo-stream action="replace" target="notification">
    <template><div id="notification">Updated!</div></template>
</turbo-stream>

<turbo-stream action="update" target="counter">
    <template>42</template>
</turbo-stream>

<turbo-stream action="remove" target="msg_5"></turbo-stream>

<turbo-stream action="before" target="msg_3">
    <template><div id="msg_2">Inserted before</div></template>
</turbo-stream>

<turbo-stream action="after" target="msg_3">
    <template><div id="msg_4">Inserted after</div></template>
</turbo-stream>

<turbo-stream action="refresh"></turbo-stream>

replace and update support an optional method="morph" attribute for smooth DOM morphing instead of full replacement:

html
<turbo-stream action="replace" method="morph" target="user-card">
    <template><div id="user-card">Updated content</div></template>
</turbo-stream>
Target Multiple Elements (CSS Selector)

Use targets (plural) with a CSS selector to affect multiple elements:

html
<turbo-stream action="remove" targets=".notification.read"></turbo-stream>

<turbo-stream action="update" targets=".price">
    <template>99.00 EUR</template>
</turbo-stream>
Twig Component Syntax for Streams

Since Symfony UX 2.22+, you can use <twig:Turbo:Stream:*> components instead of raw HTML:

twig
<twig:Turbo:Stream:Append target="comments">
    {{ include('comment/_comment.html.twig') }}
</twig:Turbo:Stream:Append>

<twig:Turbo:Stream:Update target="comment-count">
    {{ count }}
</twig:Turbo:Stream:Update>

<twig:Turbo:Stream:Remove target="msg_5" />

Symfony Integration

Stream Response from Controller
php
use Symfony\UX\Turbo\TurboBundle;

#[Route('/messages', name: 'message_create', methods: ['POST'])]
public function create(Request $request): Response
{
    $message = new Message();
    // ... handle form

    $this->em->persist($message);
    $this->em->flush();

    // Return stream response for Turbo requests
    $request->setRequestFormat(TurboBundle::STREAM_FORMAT);

    return $this->render('message/create.stream.html.twig', [
        'message' => $message,
        'count' => $count,
    ]);
}

You can also use the TurboStreamResponse helper or TurboStream helper methods for programmatic stream building.

Stream Template
twig
{# templates/message/create.stream.html.twig #}
<turbo-stream action="append" target="messages">
    <template>
        {{ include('message/_message.html.twig', {message: message}) }}
    </template>
</turbo-stream>
<turbo-stream action="update" target="message-count">
    <template>{{ count }}</template>
</turbo-stream>
<turbo-stream action="replace" target="new-message-form">
    <template>
        {{ include('message/_form.html.twig', {message: null}) }}
    </template>
</turbo-stream>
Detect Frame Request
php
public function show(Request $request, int $id): Response
{
    if ($request->headers->has('Turbo-Frame')) {
        $frameId = $request->headers->get('Turbo-Frame');
        // Return only the frame content (or a full page -- Turbo extracts the frame)
    }

    return $this->render('page/show.html.twig');
}
Show full SKILL.md (217 more words)Show less
Mercure Broadcasts (Real-time)

Push changes to all connected browsers via SSE:

php
use Symfony\UX\Turbo\Attribute\Broadcast;

#[Broadcast]
class Message
{
    // Entity changes broadcast automatically to subscribed clients
}
twig
{# Subscribe to Mercure topic #}
<turbo-stream-source src="{{ mercure('chat-room-1')|escape('html_attr') }}">
</turbo-stream-source>

<div id="messages">
    {# Messages appear here in real-time #}
</div>

Common Patterns

Inline Edit
html
<!-- Display mode -->
<turbo-frame id="task_{{ task.id }}">
    <span>{{ task.title }}</span>
    <a href="/tasks/{{ task.id }}/edit">Edit</a>
</turbo-frame>

<!-- Edit mode (response from /tasks/1/edit) -->
<turbo-frame id="task_1">
    <form action="/tasks/1" method="post">
        <input name="title" value="Task title">
        <button>Save</button>
        <a href="/tasks/1">Cancel</a>
    </form>
</turbo-frame>
Modal in Frame
html
<turbo-frame id="modal"><!-- Empty by default --></turbo-frame>

<a href="/items/1/delete" data-turbo-frame="modal">Delete</a>

<!-- /items/1/delete response -->
<turbo-frame id="modal">
    <dialog open>
        <p>Confirm delete?</p>
        <form method="post">
            <button>Delete</button>
        </form>
        <a href="/items" data-turbo-frame="modal">Cancel</a>
    </dialog>
</turbo-frame>
Flash Messages with Stream
twig
<turbo-stream action="prepend" target="flash-messages">
    <template>
        <div class="alert alert-success" role="alert">
            Item saved successfully!
        </div>
    </template>
</turbo-stream>

Key Principles

Server returns full HTML pages. Turbo works best when the server always returns a complete, valid HTML page. Turbo Drive replaces the body, Turbo Frames extract the matching frame. Don't try to return partial HTML snippets (except for Stream templates).

Frame IDs must match. The frame in the response must have the same id as the frame on the page. If they don't match, Turbo shows an error.

Streams are for side effects. Use Streams when a single action needs to update multiple unrelated parts of the page. If you're only updating one section, a Frame is simpler.

Stimulus complements Turbo. Turbo handles navigation and server communication. Stimulus handles client-side behavior (animations, toggles, clipboard). They work together -- Stimulus controllers survive Turbo Frame swaps within their scope, and reconnect properly on Drive navigation.

References

See Also

  • UX Map works inside Turbo Frames. The map Stimulus controller reconnects properly on frame swaps.
  • UX Icons are inline SVG and survive Turbo Drive navigation and Frame swaps with no special handling.

© smnandre, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 3 other files (references) in skills/turbo of smnandre/symfony-ux-skills.

  • SKILL.md
  • references/api.md
  • references/gotchas.md
  • references/patterns.md

Open the folder on GitHubat commit 1e99301

Compare with similar skills

Turbo next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Turbo compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Turbo this skillsmnandre/symfony-ux-skills180—~2.9kAutomated safety check: PassMIT
Gemini Live API Devgoogle-gemini/gemini-skills4.3k—~4.6kAutomated safety check: PassApache-2.0
Gemini Live API Devsickn33/agentic-awesome-skills47k1 repos~3.7kAutomated safety check: PassApache-2.0
Gemini Live API DevJetBrains/skills366—~2.6kAutomated safety check: PassNone
Gemini API Devgoogle-gemini/gemini-skills4.3k—~5.1kAutomated safety check: PassApache-2.0
Gemini Interactions APIAyuilos/Miffan208—~4.6kAutomated safety check: PassAGPL-3.0

Similar skills

  • Gemini Live API Dev

    google-gemini/gemini-skills

    Official

    A skill your agent uses when building real-time, bidirectional streaming applications with the Gemini Live API, or migrating legacy Live models (2.0/2.5/3.1) to Gemini 3.8 Live.

    4.3k GitHub stars~4.6k tokensUpdated 2 days ago
    Backend & APIsAuto-check passed
  • Gemini Live API Dev

    sickn33/agentic-awesome-skills

    A skill your agent uses when building real-time, bidirectional streaming applications with the Gemini Live API.

    47k GitHub starsUsed in 1 repo~3.7k tokens
    Backend & APIsAuto-check passed
  • Gemini Live API Dev

    JetBrains/skills

    Official

    A skill your agent uses when building real-time, bidirectional streaming applications with the Gemini Live API.

    366 GitHub stars~2.6k tokensUpdated 3 mo ago
    Backend & APIsAuto-check passed
  • Gemini API Dev

    google-gemini/gemini-skills

    Official

    A skill your agent uses when writing code that calls the Gemini API for text generation, multi-turn chat, multimodal understanding, image generation, video generation, speech generation (TTS), voice…

    4.3k GitHub stars~5.1k tokensUpdated 2 days ago
    AI & LLM EngineeringAuto-check passed
  • A skill your agent uses when writing code that calls the Gemini API for text generation, multi-turn chat, multimodal understanding, image generation, video generation, streaming responses…

    208 GitHub stars~4.6k tokensUpdated today
    Media & CreativeAuto-check passed
  • Gemini API Dev

    Ayuilos/Miffan

    A skill your agent uses when building applications with Gemini API hosted models, including Gemini and Gemma 4, working with multimodal content (text, images, audio, video), implementing function…

    208 GitHub stars~1.4k tokensUpdated today
    AI & LLM EngineeringAuto-check passed

More from smnandre/symfony-ux-skills

  • Live Component

    smnandre/symfony-ux-skills

    Symfony UX LiveComponent for reactive server-rendered UI -- components that re-render via AJAX on user interaction, zero JavaScript required.

    180 GitHub stars~3.3k tokensUpdated 3 mo ago
    Auto-check passed
  • Stimulus

    smnandre/symfony-ux-skills

    Stimulus JS framework for Symfony UX -- client-side behavior via HTML data attributes, zero server round-trips.

    180 GitHub stars~2.1k tokensUpdated 3 mo ago
    Auto-check passed
  • Twig Component

    smnandre/symfony-ux-skills

    Symfony UX TwigComponent for reusable UI building blocks -- server-rendered components with PHP classes and Twig templates.

    180 GitHub stars~2.5k tokensUpdated 3 mo ago
    Auto-check passed
  • UX Icons

    smnandre/symfony-ux-skills

    Symfony UX Icons for rendering SVG icons in Twig templates. An agent skill from smnandre/symfony-ux-skills.

    180 GitHub stars~1.9k tokensUpdated 3 mo ago
    Auto-check passed
  • UX Map

    smnandre/symfony-ux-skills

    Symfony UX Map for interactive maps with Leaflet or Google Maps in Symfony.

    180 GitHub stars~3k tokensUpdated 3 mo ago
    Auto-check: notes
  • Symfony UX

    smnandre/symfony-ux-skills

    Symfony UX frontend stack -- decision tree and orchestrator for choosing between Stimulus, Turbo, TwigComponent, LiveComponent, UX Icons, and UX Map.

    180 GitHub stars~3.4k tokensUpdated 3 mo ago
    Auto-check passed

Categories

Questions about Turbo

What does Turbo do?

Hotwire Turbo for Symfony UX -- SPA-like speed with zero JavaScript. Turbo is an agent skill from smnandre/symfony-ux-skills. Hotwire Turbo for Symfony UX -- SPA-like speed with zero JavaScript.

When should I use Turbo?

Turbo fits situations like: building ajax navigation; lazy-loaded sections; pagination without reload; modals from the server.

How do I install Turbo in Claude Code?

Run `npx skills add smnandre/symfony-ux-skills --skill turbo -a claude-code`. Or copy the skill folder (skills/turbo in smnandre/symfony-ux-skills) into .claude/skills/turbo in your project. Claude Code loads it when a task matches its description.

How do I install Turbo in Codex?

Run `npx skills add smnandre/symfony-ux-skills --skill turbo -a codex`. Or copy the skill folder (skills/turbo in smnandre/symfony-ux-skills) into .agents/skills/turbo in your project. Codex loads it when a task matches its description.

Can I use Turbo in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add smnandre/symfony-ux-skills --skill turbo -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/turbo, .gemini/skills/turbo, .github/skills/turbo and .opencode/skills/turbo in your project.

What does Turbo need to run?

Going by SKILL.md and its folder, Turbo needs the command-line tools its instructions call (composer).

Does Turbo access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Turbo safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Turbo use?

Turbo is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Turbo use?

About 2.9k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 8.1k tokens, read only when the agent opens those files.

What are the alternatives to Turbo?

Skills that share tags, products or a category with Turbo: Gemini Live API Dev (google-gemini/gemini-skills, 4.3k stars), Gemini Live API Dev (sickn33/agentic-awesome-skills, 47k stars), Gemini Live API Dev (JetBrains/skills, 366 stars) and Gemini API Dev (google-gemini/gemini-skills, 4.3k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Turbo?

smnandre (a GitHub user) maintains it in smnandre/symfony-ux-skills, which has 180 GitHub stars. The repository holds 7 skills in this directory. The repository was last updated on June 14, 2026.

Source: smnandre/symfony-ux-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.