Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8007d42
feat(vue-ai-apps): add skill for building AI/agent apps in Vue/Nuxt
elkaix Jun 27, 2026
c3466d3
docs(registry): register vue-ai-apps skill
elkaix Jun 27, 2026
c053169
feat(vue-best-practices): cover Vue 3.5 APIs and 3.6 Vapor mode
elkaix Jun 27, 2026
e240309
chore(tasks): track eval follow-up for new references
elkaix Jun 27, 2026
b040869
test(evals): scaffold eval stubs for new references
elkaix Jun 27, 2026
e47a216
ci(sync): include evals/ in Sync to Main whitelist
elkaix Jun 27, 2026
e9f5770
release(mcp): @pythoughts/vue-skills-mcp 0.2.0
elkaix Jun 27, 2026
c160db7
feat(evals): runnable eval runner and per-scenario project boilerplate
elkaix Jun 27, 2026
a2e546f
ci(sync): add root package.json to Sync to Main whitelist
elkaix Jun 27, 2026
0b7cd3b
chore(tasks): mark eval runner done; remaining = run the matrix
elkaix Jun 27, 2026
447d9c8
fix(evals): make LLM tiers actually exercise the skill
elkaix Jun 27, 2026
e441db1
fix(evals): App.vue shell no longer instantiates the subject component
elkaix Jun 27, 2026
c5a0c27
chore(evals): record matrix results and harness/assertion findings
elkaix Jun 27, 2026
ed507d0
fix(evals): strip comments before reactive-props negative assertion
elkaix Jun 27, 2026
5428c30
chore(evals): corrected matrix results after assertion + harness fixes
elkaix Jun 27, 2026
4ef2fc9
chore(tasks): refresh stale follow-up notes
elkaix Jun 27, 2026
8524e1c
docs(vue-ai-apps): align with ai@7 / @ai-sdk/vue@4 (skill v1.1.0)
elkaix Jun 27, 2026
1cb4a55
chore(tasks): mark AI SDK refresh done
elkaix Jun 27, 2026
41a527e
release(mcp): @pythoughts/vue-skills-mcp 0.3.0
elkaix Jun 27, 2026
7d5ea03
test(evals): record corrected vue-best-practices results
elkaix Jun 27, 2026
7b6dde9
fix(evals): drop HTML-comment strip in reactive-props assertion (CodeQL)
elkaix Jun 27, 2026
c02428e
Fix: await convertToModelMessages (async in ai@7)
elkaix Jun 27, 2026
d0aa0af
chore(mcp): bump to 0.3.1
elkaix Jun 27, 2026
80747a8
ci: dry-build eval scenarios on eval changes
elkaix Jun 27, 2026
aa16d28
docs(tasks): record eval-smoke CI check
elkaix Jun 27, 2026
baa3cfd
Migrate to PyModel org + ecosystem refresh (Vue Router 5, Pinia 4, Vi…
elkaix Aug 16, 2026
dc151ad
chore(release): v0.3.2
elkaix Aug 16, 2026
2a63041
ci(sync-to-main): don't fail on expected merge conflicts
elkaix Aug 16, 2026
3a2dc06
ci(sync-to-main): sync mcp/ to main
elkaix Aug 16, 2026
64a4f7a
docs: skills.sh + npm badges, npx MCP install, fix stale router descr…
elkaix Aug 16, 2026
bd1388e
docs: add npm downloads badge, drop hardcoded skills count
elkaix Aug 16, 2026
170a907
sync: merge dev into main
github-actions[bot] Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"name": "vue3-best-practices",
"description": "A collection of skills for Vue.js development.",
"owner": {
"name": "Pythoughts-labs",
"url": "https://github.com/Pythoughts-labs/vue3-best-practices"
"name": "PyModel",
"url": "https://github.com/PyModel/vue3-best-practices"
},
"plugins": [
{
Expand Down Expand Up @@ -39,7 +39,7 @@
{
"name": "vue-router-best-practices",
"source": "./skills/vue-router-best-practices",
"description": "Vue Router 4 patterns, navigation guards, route params, and route-component lifecycle interactions."
"description": "Vue Router 4/5 patterns, navigation guards, route params, file-based routing, and route-component lifecycle interactions."
},
{
"name": "vue-testing-best-practices",
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/eval-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Eval smoke

# Dry-builds every eval scenario (no LLM calls) so boilerplate rot —
# a broken stub, tsconfig, or App.vue shell — fails a PR instead of a paid eval run.
# Only fires when the eval suite or its harness changes.
on:
pull_request:
paths:
- 'evals/**'
- 'package.json'
push:
branches: [dev]
paths:
- 'evals/**'
- 'package.json'

permissions:
contents: read

jobs:
dry:
name: Eval dry build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v6
with:
node-version: '24'
- name: Dry-build all eval scenarios
run: pnpm eval --all --dry
12 changes: 9 additions & 3 deletions .github/workflows/sync-to-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,21 @@ jobs:
BRANCH="sync/dev-to-main-$(date +%Y%m%d%H%M%S)"
git checkout -b "$BRANCH"

# Create a merge commit, but don't commit yet
git merge --no-ff --no-commit origin/dev
# Create a merge commit, but don't commit yet.
# This is only here to record dev as a second parent — the merge's
# own content is thrown away by the restore below, so conflicts are
# expected and must not fail the step (the shell runs with -e).
git merge --no-ff --no-commit origin/dev || true

# Reset everything back to main...
git restore --source=ORIG_HEAD --staged --worktree -- .

# ...then re-apply only whitelisted paths from dev
# mcp/ must stay in this list: .github/ is synced, so main runs the
# MCP server job, and without mcp/ that job tests a stale tree (old
# package name, old version, unpatched lockfile) and always fails.
git restore --source=origin/dev --staged --worktree -- \
skills/ evals/ package.json .github/ .claude-plugin/ README.md AGENTS.md CLAUDE.md LICENSE
skills/ evals/ mcp/ package.json .github/ .claude-plugin/ README.md AGENTS.md CLAUDE.md LICENSE

git add -A
if git diff --staged --quiet; then
Expand Down
33 changes: 16 additions & 17 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@

| Branch | Purpose | Direct commits |
|--------|---------|----------------|
| `main` | Publishing (`npx skills add Pythoughts-labs/vue3-best-practices`) | Forbidden |
| `main` | Publishing (`npx skills add PyModel/vue3-best-practices`) | Forbidden |
| `dev` | Development, tests, experiments | Via PR only |

## Development Workflow

After completing any task, run:
After completing any task, run the repo's structure and server checks:

```bash
pnpm typecheck
node --test scripts/validate-skills.test.mjs # skill front matter, references, marketplace
npm --prefix mcp test # MCP server smoke test
```

This ensures TypeScript types are correct before committing.
There is no root TypeScript project, so there is no root `typecheck` script.
Eval scenarios carry their own `vue-tsc` setup and are type-checked by their own
`pnpm run build` inside the eval run.

## Skill Scopes

Expand All @@ -31,7 +34,7 @@ This ensures TypeScript types are correct before committing.
| **vue-options-api-best-practices** | Vue 3 Options API style (`data()`, `methods`, `this` context). Each rule shows Options API solution only. |
| **vue-jsx-best-practices** | JSX syntax in Vue (e.g., `class` vs `className`, JSX plugin config). |
| **vue-testing-best-practices** | Testing with Vitest, Vue Test Utils, and Playwright for E2E. |
| **vue-router-best-practices** | Vue Router 4 patterns, navigation guards, route params, and route-component lifecycle interactions. |
| **vue-router-best-practices** | Vue Router 4/5 patterns, navigation guards, route params, file-based routing, and route-component lifecycle interactions. |
| **vue-pinia-best-practices** | Pinia stores, state management patterns, store setup, and reactivity with stores. |
| **vue-debug-guides** | Debugging and troubleshooting Vue 3: runtime errors, warnings, async error handling, SSR hydration issues. |

Expand Down Expand Up @@ -250,8 +253,8 @@ pnpm eval computed-vs-methods --dry
# Verbose output (keep temp dir, show details)
pnpm eval computed-vs-methods --verbose

# Type check evals library
pnpm --filter @vue-skills/evals typecheck
# Validate skill structure (front matter, references, marketplace registration)
node --test scripts/validate-skills.test.mjs
```

**Skip logic:**
Expand All @@ -273,16 +276,12 @@ pnpm --filter @vue-skills/evals typecheck

| Eval | Skill | Tests |
|------|-------|-------|
| `computed-vs-methods` | vue-best-practices | Uses computed() for derived data |
| `no-v-if-with-v-for` | vue-best-practices | Separates v-if and v-for |
| `v-for-key-attribute` | vue-best-practices | Uses :key with unique id |
| `testing-vitest` | vue-testing-best-practices | Uses Vitest + Vue Test Utils |
| `testing-async-flushpromises` | vue-testing-best-practices | Uses flushPromises for async |
| `router-param-change` | vue-router-best-practices | Watches route params |
| `pinia-store-destructuring` | vue-pinia-best-practices | Uses storeToRefs |
| `no-arrow-functions-methods` | vue-options-api-best-practices | Regular function syntax |
| `jsx-vue-vs-react` | vue-jsx-best-practices | Uses class not className |
| `create-composable` | vue-best-practices | Creates reusable composable |
| `reactive-props-destructure` | vue-best-practices | Reactive props destructure with defaults |
| `vue-3-5-helpers` | vue-best-practices | Vue 3.5 helpers (useTemplateRef, useId, onWatcherCleanup) |
| `streaming-chat-ui` | vue-ai-apps | Streaming chat with Vercel AI SDK useChat |
| `tool-calling` | vue-ai-apps | Tool calling with useChat |
| `structured-output` | vue-ai-apps | Structured output generation |
| `error-handling-and-abort` | vue-ai-apps | Abort handling and error states in chat UI |

### Full Eval Matrix

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2026 Pythoughts-labs, Mohamed Elkholy (elkaix) <https://github.com/Pythoughts-labs/vue3-best-practices>
Copyright (c) 2026 PyModel, Mohamed Elkholy (elkaix) <https://github.com/PyModel/vue3-best-practices>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
</p>

<p align="center">
<a href="https://github.com/Pythoughts-labs/vue3-best-practices/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Pythoughts-labs/vue3-best-practices/actions/workflows/ci.yml/badge.svg"></a>
<a href="https://github.com/PyModel/vue3-best-practices/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/PyModel/vue3-best-practices/actions/workflows/ci.yml/badge.svg"></a>
<a href="https://skills.sh/PyModel/vue3-best-practices"><img alt="skills.sh" src="https://skills.sh/b/PyModel/vue3-best-practices"></a>
<a href="https://www.npmjs.com/package/@pymodel/vue-skills-mcp"><img alt="npm" src="https://img.shields.io/npm/v/@pymodel/vue-skills-mcp?logo=npm&color=42b883"></a>
<a href="https://www.npmjs.com/package/@pymodel/vue-skills-mcp"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@pymodel/vue-skills-mcp?logo=npm&color=35495e&label=downloads"></a>
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-42b883.svg"></a>
<img alt="Vue 3.5+" src="https://img.shields.io/badge/Vue-3.5%2B-42b883?logo=vuedotjs&logoColor=white">
<img alt="Skills: 8" src="https://img.shields.io/badge/skills-8-35495e">
<img alt="MCP server" src="https://img.shields.io/badge/MCP-server-35495e">
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-strict-3178c6?logo=typescript&logoColor=white">
<a href="#contributing"><img alt="PRs welcome" src="https://img.shields.io/badge/PRs-welcome-42b883"></a>
</p>

<p align="center">
Agent skills that teach AI coding agents current Vue 3 patterns, validated with automated evals.<br>
Maintained by <a href="https://github.com/Pythoughts-labs">Pythoughts-labs</a>.
Maintained by <a href="https://github.com/PyModel">PyModel</a>.
</p>

<p align="center">
Expand All @@ -32,14 +34,14 @@
Add the skills to any agent that supports the `skills` registry:

```bash
npx skills add Pythoughts-labs/vue3-best-practices
npx skills add PyModel/vue3-best-practices
```

### Claude Code marketplace

```bash
# Add the marketplace
/plugin marketplace add Pythoughts-labs/vue3-best-practices
/plugin marketplace add PyModel/vue3-best-practices

# Install everything at once
/plugin install vue-skills-bundle@vue3-best-practices
Expand All @@ -63,6 +65,14 @@ Without the prefix, triggering depends on how closely the prompt matches a skill

For agents that consume MCP instead of the skills registry, [`mcp/`](mcp/) exposes every skill as MCP tools. The agent calls `vue_best_practices` when it detects Vue work, then pulls individual reference files on demand.

The server is published as [`@pymodel/vue-skills-mcp`](https://www.npmjs.com/package/@pymodel/vue-skills-mcp) with the skills bundled, so no clone is needed:

```bash
claude mcp add vue-skills -- npx -y @pymodel/vue-skills-mcp
```

To run it from a local clone instead:

```bash
cd mcp && npm install
```
Expand Down Expand Up @@ -129,7 +139,7 @@ claude mcp add vue-skills -- node <REPO>/mcp/index.mjs
|-------|-------------|--------|
| **vue-best-practices** | Vue 3 + Composition API + TypeScript | Reactivity, SFC structure, data flow, composables, SSR, performance |
| **vue-options-api-best-practices** | Options API (`data()`, `methods`) | `this` context, lifecycle, TypeScript with Options API |
| **vue-router-best-practices** | Vue Router 4 | Navigation guards, route params, route-component lifecycle |
| **vue-router-best-practices** | Vue Router 4/5 | Navigation guards, route params, file-based routing, route-component lifecycle |
| **vue-pinia-best-practices** | Pinia state management | Store setup, reactivity, `storeToRefs`, state patterns |
| **vue-testing-best-practices** | Component or E2E tests | Vitest, Vue Test Utils, Playwright |
| **vue-jsx-best-practices** | JSX in Vue | Syntax differences from React JSX, plugin config |
Expand Down
4 changes: 3 additions & 1 deletion evals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ Each scenario is a self-contained Vue + Vite + Vitest project:
### Verified vs. requires budget

- **Verified:** `--dry` (install + build) passes on all scenarios; arg validation; results.json I/O.
CI runs `pnpm eval --all --dry` (no LLM, no cost) on any PR touching `evals/**`, so stub/boilerplate
rot fails the PR instead of a paid eval run — see `.github/workflows/eval-smoke.yml`.
- **Requires API budget + `claude` CLI:** the four LLM tiers (`baseline`, `with-skill`,
`with-skill-prompt`, `with-agents-md`). These are billed and user-triggered — not run in CI.
- Skill install for the `with-skill*` tiers uses `npx skills add` against
`$VUE_SKILLS_SOURCE` (default `Pythoughts-labs/vue3-best-practices`); override for local setups.
`$VUE_SKILLS_SOURCE` (default `PyModel/vue3-best-practices`); override for local setups.

## Covered references

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"test": "vitest run"
},
"dependencies": {
"vue": "^3.5.13"
"vue": "^3.5.41"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^3.0.0",
"vue-tsc": "^2.2.0"
"@vitejs/plugin-vue": "^6.0.8",
"typescript": "^5.9.3",
"vite": "^8.2.1",
"vitest": "^4.1.10",
"vue-tsc": "^3.3.10"
}
}
Loading
Loading