diff --git a/README.md b/README.md
index b18f307c..638df4e6 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,13 @@
[![License][license-src]][license-href]
[![Nuxt][nuxt-src]][nuxt-href]
[![Volta][volta-src]][volta-href]
+
+
+
+
+
+
+
# Nuxt Scripts
@@ -38,10 +45,7 @@ npx nuxi@latest module add scripts
```
> [!TIP]
-> Generate an Agent Skill for this package using [skilld](https://github.com/harlan-zw/skilld):
-> ```bash
-> npx skilld add @nuxt/scripts
-> ```
+> Using an AI agent? Get the @nuxt/scripts Skill on [skilld.dev/gh/nuxt/scripts/nuxt-scripts](https://skilld.dev/gh/nuxt/scripts/nuxt-scripts).
That's it. The Nuxt Scripts module should be downloaded and added to your Nuxt Config `modules`.
diff --git a/docs/content/docs/1.getting-started/2.installation.md b/docs/content/docs/1.getting-started/2.installation.md
index dbd67223..405627d6 100644
--- a/docs/content/docs/1.getting-started/2.installation.md
+++ b/docs/content/docs/1.getting-started/2.installation.md
@@ -20,10 +20,7 @@ npx nuxi@latest module add scripts
```
> [!TIP]
-> Generate an Agent Skill for this package using [skilld](https://github.com/skilld-dev/skilld):
-> ```bash
-> npx skilld add @nuxt/scripts
-> ```
+> Using an AI agent? Get the @nuxt/scripts Skill on [skilld.dev/gh/nuxt/scripts/nuxt-scripts](https://skilld.dev/gh/nuxt/scripts/nuxt-scripts).
The [Nuxt module command](https://nuxt.com/docs/api/commands/module) installs Nuxt Scripts and adds it to the `modules` array in your Nuxt config.
diff --git a/packages/script/package.json b/packages/script/package.json
index 5cc097b7..ee80f3eb 100644
--- a/packages/script/package.json
+++ b/packages/script/package.json
@@ -47,7 +47,8 @@
},
"files": [
"THIRD_PARTY_LICENSES.md",
- "dist"
+ "dist",
+ "skills"
],
"engines": {
"node": "^22.22.3 || ^24.15.0 || >=26.0.0"
diff --git a/packages/script/skills/nuxt-scripts/SKILL.md b/packages/script/skills/nuxt-scripts/SKILL.md
new file mode 100644
index 00000000..f30ff87e
--- /dev/null
+++ b/packages/script/skills/nuxt-scripts/SKILL.md
@@ -0,0 +1,192 @@
+---
+name: nuxt-scripts
+description: Loads and controls third-party scripts in Nuxt with @nuxt/scripts v2, covering the scripts.registry config key, useScript, registry composables such as useScriptGoogleAnalytics and useScriptMetaPixel, consent triggers, bundling, and the first-party proxy. Use when adding analytics, pixels, or chat scripts to Nuxt, upgrading @nuxt/scripts from v1 to v2, or when a script never loads, loads before consent, or fails the build while downloading.
+---
+
+# @nuxt/scripts
+
+Tested against `@nuxt/scripts` 2.0.0-beta.14 (npm `beta`) with Nuxt 4.6.0.
+v2 needs Nuxt `^4.6.0 || ^5.0.0`, `@unhead/vue` and `unhead` `^3.4.2`, and Node.js `^22.22.3 || ^24.15.0 || >=26.0.0`.
+Composables and components are auto-imported. The examples import from `#imports` only to stay complete modules. Paths assume the Nuxt 4 `app/` source directory.
+
+## Setup
+
+Install with `npx nuxi module add @nuxt/scripts@2.0.0-beta.14`. It also adds the `unhead` and `@unhead/vue` peers. Keep the version: without it, nuxi installs the npm `latest` tag, which can be another major.
+
+A registry entry is a flat object, `'mock'`, or `false`; any other shape throws. Its `trigger` decides whether it loads globally:
+
+| `scripts.registry` entry | Global script | Composable called with no options |
+|---|---|---|
+| `{ id, trigger: 'onNuxtReady' }` | loads on every page | returns the global instance |
+| `{ id }` or `{}` | none | loads with the default `onNuxtReady` trigger |
+| `{ id, trigger: false }` | none | never loads: it inherits `trigger: false` |
+| `'mock'` | none | stays `awaitingLoad`; proxy calls do nothing |
+
+```ts
+// nuxt.config.ts
+import { defineNuxtConfig } from 'nuxt/config'
+
+export default defineNuxtConfig({
+ modules: ['@nuxt/scripts'],
+ scripts: {
+ registry: {
+ // Cookieless, so it loads on every page. The script ID comes from
+ // NUXT_PUBLIC_SCRIPTS_PLAUSIBLE_ANALYTICS_SCRIPT_ID and must be real
+ // at build time (see Deploy).
+ plausibleAnalytics: { trigger: 'onNuxtReady' },
+ // No trigger: app.vue loads it after consent. The ID comes from
+ // NUXT_PUBLIC_SCRIPTS_GOOGLE_ANALYTICS_ID.
+ googleAnalytics: {},
+ },
+ },
+})
+```
+
+Each registry key reads `NUXT_PUBLIC_SCRIPTS__` (camelCase key and field in SCREAMING_SNAKE_CASE) without a `runtimeConfig` declaration.
+The key must be in `scripts.registry`; otherwise the module warns and ignores the variable. These values are public.
+
+## Automatic behaviour
+
+- SSR HTML contains no script tags. Scripts load on the client after hydration (`onNuxtReady`).
+- SSR adds `` for `onNuxtReady` and `client` triggers. `warmupStrategy: false` stops it for `onNuxtReady`; a `client` trigger always preloads.
+- Cross-origin tags get `crossorigin="anonymous"` and `referrerpolicy="no-referrer"`.
+- Registry scripts that support bundling are downloaded at build and served from `/_scripts/assets/.js`. Set `bundle: false` on an entry to load from the vendor. For most scripts this also stops the proxy, because the proxy rewrites the bundle.
+- Collection requests of supported scripts go through `/_scripts/p//...`. Each script has a privacy tier, and every tier anonymises the IP. Set `proxy: false` on an entry to send them direct.
+- Calls with the same `key`, else `src`, share one script. A second call returns the shared instance and ignores its input, `use`, and `resolve`. Its `trigger` still runs, and a call with no trigger uses `onNuxtReady`.
+- Each call gets its own consumer scope. Unmounting the component releases that call's callbacks and triggers; the shared script stays.
+
+## Common tasks
+
+Load consent-gated scripts. A module-level trigger in `app/utils/` is shared by every component:
+
+```ts
+// app/utils/consent.ts
+import { useScriptTriggerConsent } from '#imports'
+
+export const scriptsConsent = useScriptTriggerConsent()
+```
+
+```vue
+
+
+
+
+
+
+
+```
+
+Pass `scriptOptions: { trigger: scriptsConsent }` to every call of a consent-gated script, such as a component that tracks an event. One call without it loads the script before consent.
+`scriptsConsent.revoke()` sets `consented` to `false` but does not unload a loaded script. Call the vendor API through `consent` instead.
+
+Call a vendor API. Proxy calls queue until load and return `undefined`; use `onLoaded` for a return value:
+
+```vue
+
+
+
+
+
+
+```
+
+If the SDK signals readiness through a callback, use `resolve({ waitFor })`. `load()` then resolves only when the callback fires. The returned cleanup runs when the callback fires, or earlier if the script lifecycle ends:
+
+```vue
+
+
+
+
+
{{ sdk.status }}
+
+```
+
+Give each instance a unique `key` to load one script twice with different options.
+
+## Integrations
+
+- `partytown: true` needs `@nuxtjs/partytown`. It writes `