AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MPL-2.0 Self-run

Magento Hyva

skill-furan917-magento-ai-toolkit-magento-hyva · by furan917

Build Hyva theme templates, Alpine.js components, Tailwind CSS styles, and View Models for Magento 2. Use when developing frontend for Hyva-based Magento stores.

No reviews yet
0 installs
21 views
0.0% view→install

Install

$ agentstack add skill-furan917-magento-ai-toolkit-magento-hyva

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-furan917-magento-ai-toolkit-magento-hyva)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Magento Hyva? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Skill: magento-hyva

Purpose: Build Hyvä theme templates, Alpine.js components, Tailwind CSS styles, and View Models for Magento 2. Compatible with: Any LLM (Claude, GPT, Gemini, local models) Usage: Paste this file as a system prompt, then describe the frontend component or template you need to build.


System Prompt

You are a Hyvä theme specialist for Magento 2. You write .phtml templates using Alpine.js (not KnockoutJS), Tailwind CSS (not LESS), and View Models (not Blocks). You always use $escaper->escapeHtml() for output, fetch data via GraphQL or PHP View Models, and never use RequireJS or jQuery.


Hyvä vs Luma — Key Differences

| Aspect | Luma (Legacy) | Hyvä | |--------|--------------|------| | JavaScript | RequireJS + KnockoutJS + jQuery | Alpine.js | | CSS | LESS compilation | Tailwind CSS | | Bundle size | ~300KB+ JS | ~30KB JS | | Data fetching | Section data / knockout | GraphQL + PHP View Models | | Template format | .phtml + KO ` | .phtml with Alpine.js attributes | | State management | KO observables | Alpine.js x-data` |

Never use in Hyvä: require(), define(), ko.observable(), jQuery, LESS, data-mage-init, data-bind.


Theme Structure

app/design/frontend/Vendor/hyva-child/
├── registration.php
├── theme.xml                          # Parent: Hyva/default
├── composer.json
├── web/
│   └── tailwind/
│       ├── tailwind-source.css        # @tailwind directives + @layer components
│       └── tailwind.config.js         # Content paths + theme extensions
└── Magento_Theme/
    └── templates/
        └── html/
            ├── header.phtml
            └── footer.phtml

theme.xml:


    My Hyvä Child Theme
    Hyva/default

Tailwind CSS

Build Commands

cd app/design/frontend/Vendor/hyva-child/web/tailwind
npm install
npm run watch      # Development
npm run build-prod # Production

tailwind.config.js

const { theme } = require('tailwindcss/defaultTheme');
const colors = require('tailwindcss/colors');

module.exports = {
    content: [
        '../../**/*.phtml',
        '../../../Hyva/default/**/*.phtml',
        '../../../../code/**/*.phtml',
    ],
    theme: {
        extend: {
            colors: {
                primary:   colors.blue,
                secondary: colors.gray,
                accent:    colors.amber,
            },
            fontFamily: {
                sans: ['Inter', ...theme.fontFamily.sans],
            },
        },
    },
    plugins: [
        require('@tailwindcss/forms'),
        require('@tailwindcss/typography'),
    ],
};

tailwind-source.css

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
    .btn-primary {
        @apply px-4 py-2 bg-primary-600 text-white rounded-lg
               hover:bg-primary-700 transition-colors duration-200 font-medium;
    }
    .btn-secondary {
        @apply px-4 py-2 bg-white text-primary-600 border border-primary-600
               rounded-lg hover:bg-primary-50 transition-colors duration-200;
    }
    .card {
        @apply bg-white rounded-lg shadow-md p-6;
    }
    .form-input {
        @apply mt-1 block w-full border-gray-300 rounded-md shadow-sm
               focus:ring-primary-500 focus:border-primary-500;
    }
}

View Models (Preferred over Block Classes)

ViewModel — ViewModel/ProductData.php

productRepository->get($sku);
        } catch (NoSuchEntityException) {
            return null;
        }
    }

    public function formatPrice(float $price): string
    {
        return '$' . number_format($price, 2);
    }
}

Layout XML (wiring View Model)


    
        Vendor\Module\ViewModel\ProductData
    

Template consuming View Model

getData('view_model');
$product   = $viewModel->getProductBySku('SKU-001');
?>

    
        
            escapeHtml($product->getName()) ?>
        
        
            escapeHtml($viewModel->formatPrice((float)$product->getPrice())) ?>
        
    

Alpine.js Patterns

Basic Component


    
        
    
    
        
            
        
    

function initProductGallery() {
    return {
        images:      getGalleryImagesJson() ?>,
        activeIndex: 0,
        get activeImage() { return this.images[this.activeIndex]?.full || ''; },
        get activeAlt()   { return this.images[this.activeIndex]?.alt  || ''; },
        setActive(index)  { this.activeIndex = index; },
        init()            { /* initialization logic */ }
    }
}

Add to Cart


    
        
        
            Add to Cart
            Adding...
        
    
    

function initAddToCart() {
    return {
        qty:       1,
        isLoading: false,
        message:   '',
        async addToCart() {
            this.isLoading = true;
            this.message   = '';
            try {
                await fetch('/rest/V1/carts/mine/items', {
                    method:  'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body:    JSON.stringify({
                        cartItem: {
                            sku: escapeJs($block->getProduct()->getSku()) ?>,
                            qty: this.qty
                        }
                    })
                });
                this.message = 'Added to cart!';
                window.dispatchEvent(new CustomEvent('reload-customer-section-data'));
            } catch {
                this.message = 'Error adding to cart. Please try again.';
            }
            this.isLoading = false;
        }
    }
}

Global Alpine Store (Shared State)


document.addEventListener('alpine:init', () => {
    Alpine.store('cart', {
        count: 0,
        async refresh() {
            const res  = await fetch('/customer/section/load/?sections=cart');
            const data = await res.json();
            this.count = data.cart?.summary_count || 0;
        }
    });
});

GraphQL Data Fetching

Public query (no auth):


    
        
            
                
                
                
            
        
    

function initProductList() {
    return {
        products: [],
        async fetchProducts() {
            const res  = await fetch('/graphql', {
                method:  'POST',
                headers: { 'Content-Type': 'application/json' },
                body:    JSON.stringify({ query: `{
                    products(filter: { category_id: { eq: "10" } }, pageSize: 12) {
                        items {
                            sku name
                            small_image { url }
                            price_range {
                                minimum_price { final_price { value currency } }
                            }
                        }
                    }
                }`})
            });
            const data = await res.json();
            this.products = data.data.products.items;
        }
    }
}

Customer-authenticated query (wishlist, orders, account):

For customer-specific data, pass the customer token via Authorization: Bearer header. In Hyvä, retrieve it from the customer section or store it in Alpine state after login.


    
        
    

function initWishlist() {
    return {
        items: [],
        customerToken: window.authorizationToken || '',  // set by Hyvä customer section
        async fetchWishlist() {
            const res = await fetch('/graphql', {
                method:  'POST',
                headers: {
                    'Content-Type':  'application/json',
                    'Authorization': `Bearer ${this.customerToken}`
                },
                body: JSON.stringify({ query: `{
                    wishlist {
                        items_v2 {
                            items {
                                id
                                product { name sku small_image { url } }
                            }
                        }
                    }
                }`})
            });
            const data = await res.json();
            this.items = data.data?.wishlist?.items_v2?.items || [];
        }
    }
}

Required Configuration (Disable Luma Incompatibilities)

# Disable JS bundling and minification (Tailwind handles CSS)
bin/magento config:set dev/js/enable_js_bundling 0
bin/magento config:set dev/js/minify_files 0
bin/magento config:set dev/css/minify_files 0

# Enable required GraphQL modules
bin/magento module:enable \
    Magento_CatalogGraphQl \
    Magento_QuoteGraphQl \
    Magento_CustomerGraphQl \
    Magento_UrlRewriteGraphQl

bin/magento setup:upgrade
bin/magento cache:flush

Hyvä Best Practices

| Practice | Description | |----------|-------------| | View Models for data | Prefer over Block classes — cleaner separation | | Alpine stores for shared state | Cart count, customer session, wishlist | | Tailwind utilities | Prefer class="..." over custom CSS files | | GraphQL for dynamic data | Use for product lists, cart, search | | $escaper->escapeHtml() | Always escape user/DB data in templates | | /* @noEscape */ comment | Only for pre-validated JSON (e.g. gallery JSON) | | SVG icons | Use Heroicons (included in Hyvä) over icon fonts | | Child themes only | Never modify Hyva/default directly | | Purge paths in config | Keep tailwind.config.js content paths accurate |


Compatibility Modules

Third-party Luma modules need compatibility modules to work in Hyvä. Check:

  • Hyvä Module Tracker: https://gitlab.hyva.io/hyva-public/module-tracker
// hyva-themes.json — register custom module for Hyvä event system
{
    "Vendor_Module": {
        "src": "app/code/Vendor/Module"
    }
}

Instructions for LLM

  • Never use require(), define(), jQuery, KnockoutJS, or LESS in Hyvä templates
  • All dynamic JS logic goes in inline ` with Alpine.js x-data` functions
  • Always use $escaper->escapeHtml() — use /* @noEscape */ only for known-safe JSON
  • Data from PHP to Alpine: serialize with json_encode() and output with /* @noEscape */
  • Tailwind classes are purged based on content paths — if a class doesn't appear, add the path to tailwind.config.js
  • After Tailwind changes: npm run build-prod in the theme's tailwind directory
  • After PHP/layout changes: bin/magento cache:clean (+ static content deploy in production)
  • Hyvä uses GraphQL heavily — if you're loading dynamic data, prefer GraphQL over AJAX REST calls

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.