{"id":"0958def4-b421-4287-a629-b9d4213fae60","shortId":"7JfJK5","kind":"skill","title":"vue","tagline":"Use when editing Vue projects, .vue files, vue.config.js, Vue 3 components, Composition API, <script setup>, SFC state, deployment workflows, or Vue CI configuration.","description":"# Vue 3 Framework Skill\n\n<workflow>\n\n## Quick Reference\n\n### Composition API Component\n\n<example>\n\n```vue\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted } from 'vue';\n\ninterface Props {\n  title: string;\n  items: Item[];\n}\n\nconst props = defineProps<Props>();\nconst emit = defineEmits<{\n  select: [item: Item];\n}>();\n\nconst selected = ref<Item | null>(null);\nconst count = computed(() => props.items.length);\n\nfunction handleSelect(item: Item) {\n  selected.value = item;\n  emit('select', item);\n}\n\nonMounted(() => {\n  console.log('Component mounted');\n});\n</script>\n\n<template>\n  <div>\n    <h2>{{ title }} ({{ count }})</h2>\n    <ul>\n      <li\n        v-for=\"item in items\"\n        :key=\"item.id\"\n        @click=\"handleSelect(item)\"\n      >\n        {{ item.name }}\n      </li>\n    </ul>\n  </div>\n</template>\n```\n\n</example>\n\n### Composables\n\n<example>\n\n```ts\n// composables/useFetch.ts\nimport { ref, watchEffect, type Ref } from 'vue';\n\nexport function useFetch<T>(url: Ref<string> | string) {\n  const data = ref<T | null>(null) as Ref<T | null>;\n  const loading = ref(true);\n  const error = ref<Error | null>(null);\n\n  watchEffect(async () => {\n    loading.value = true;\n    error.value = null;\n\n    try {\n      const urlValue = typeof url === 'string' ? url : url.value;\n      const res = await fetch(urlValue);\n      if (!res.ok) throw new Error(`HTTP ${res.status}`);\n      data.value = await res.json();\n    } catch (e) {\n      error.value = e instanceof Error ? e : new Error(String(e));\n    } finally {\n      loading.value = false;\n    }\n  });\n\n  return { data, loading, error };\n}\n```\n\n</example>\n\n### Provide/Inject Pattern\n\n<example>\n\n```ts\n// context/theme.ts\nimport { provide, inject, ref, type InjectionKey, type Ref } from 'vue';\n\ntype Theme = 'light' | 'dark';\nconst ThemeKey: InjectionKey<{\n  theme: Ref<Theme>;\n  toggle: () => void;\n}> = Symbol('theme');\n\nexport function provideTheme() {\n  const theme = ref<Theme>('light');\n  const toggle = () => {\n    theme.value = theme.value === 'light' ? 'dark' : 'light';\n  };\n  provide(ThemeKey, { theme, toggle });\n}\n\nexport function useTheme() {\n  const context = inject(ThemeKey);\n  if (!context) throw new Error('useTheme requires ThemeProvider');\n  return context;\n}\n```\n\n</example>\n\n### v-model with Components\n\n<example>\n\n```vue\n<script setup lang=\"ts\">\nconst model = defineModel<string>({ required: true });\n\n// Or with options\nconst count = defineModel<number>('count', { default: 0 });\n</script>\n\n<template>\n  <input v-model=\"model\" />\n</template>\n```\n\n</example>\n\n### Async Components\n\n<example>\n\n```ts\nimport { defineAsyncComponent } from 'vue';\n\nconst AsyncModal = defineAsyncComponent({\n  loader: () => import('./Modal.vue'),\n  loadingComponent: LoadingSpinner,\n  delay: 200,\n  errorComponent: ErrorDisplay,\n});\n```\n\n</example>\n\n</workflow>\n\n## Best Practices\n\n- Use `<script setup>` for cleaner syntax\n- Prefer Composition API over Options API\n- Use TypeScript with `defineProps<T>()` and `defineEmits<T>()`\n- Extract reusable logic into composables\n- Use `shallowRef` for large objects that don't need deep reactivity\n- Avoid mutating props directly\n\n## References Index\n\n- **[Litestar-Vite Integration](references/litestar_vite.md)** — Backend integration with Litestar-Vite plugin.\n\n## Deployment\n\n### Build Production\n\nVue applications are built into static assets using Vite.\n\n```bash\nvite build\n```\n\n### Strategy\n\nDeploy to static runners or reverse proxies. For Inertia apps, bundle assets inside the backend build directory for joint deployment.\n\n---\n\n## CI/CD Actions\n\n<example>\n\nExample GitHub Actions workflow for building:\n\n```yaml\nname: Vue CI\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup Node\n        uses: actions/setup-node@v4\n        with:\n          node-version: '22'\n          cache: 'npm'\n\n      - run: npm ci\n      - run: npm run build\n```\n\n</example>\n\n## Official References\n\n- <https://vuejs.org/guide/introduction.html>\n- <https://vuejs.org/guide/typescript/overview.html>\n- <https://vuejs.org/guide/components/v-model.html>\n- <https://github.com/vuejs/core/releases>\n- <https://vite.dev/guide/>\n- <https://inertiajs.com/docs/v2/installation/client-side-setup>\n\n## Shared Styleguide Baseline\n\n- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.\n- [General Principles](https://github.com/cofin/flow/blob/main/templates/styleguides/general.md)\n- [Vue](https://github.com/cofin/flow/blob/main/templates/styleguides/frameworks/vue.md)\n- [TypeScript](https://github.com/cofin/flow/blob/main/templates/styleguides/languages/typescript.md)\n- Keep this skill focused on tool-specific workflows, edge cases, and integration details.\n\n<guardrails>\n## Guardrails\n\n- **Always use `<script setup>` with TypeScript** -- This is the modern standard for Vue 3; provides better IDE support and less boilerplate.\n- **Never mutate props directly** -- Props are read-only; use `emit` to notify the parent of changes or use `computed` with a setter.\n- **Prefer Composables for shared logic** -- Avoid Mixins or global state; extract logic into reusable `use*` functions to keep components focused on UI.\n- **Use `defineProps` and `defineEmits` macros** -- These are compiler macros; do not import them. Use the type-based declaration for best DX.\n- **Avoid direct DOM manipulation** -- Use `ref` for DOM elements only when necessary; prefer Vue's declarative directives (`v-bind`, `v-if`, `v-for`).\n</guardrails>\n\n<validation>\n## Validation Checkpoint\n\n- [ ] Component uses `<script setup lang=\"ts\">`\n- [ ] Props and Emits are defined using type-based declarations (`defineProps<T>()`)\n- [ ] No direct mutations of props are present\n- [ ] Reusable logic is extracted into a composable if it exceeds 30-40 lines\n- [ ] `v-for` elements have a unique and stable `:key`\n- [ ] No direct DOM manipulation (e.g., `document.querySelector`) is used where Vue directives suffice\n</validation>","tags":["vue","flow","cofin","agent-skills","ai-agents","beads","claude-code","codex","cursor","developer-tools","gemini-cli","opencode"],"capabilities":["skill","source-cofin","skill-vue","topic-agent-skills","topic-ai-agents","topic-beads","topic-claude-code","topic-codex","topic-cursor","topic-developer-tools","topic-gemini-cli","topic-opencode","topic-plugin","topic-slash-commands","topic-spec-driven-development"],"categories":["flow"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/cofin/flow/vue","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add cofin/flow","source_repo":"https://github.com/cofin/flow","install_from":"skills.sh"}},"qualityScore":"0.455","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 11 github stars · SKILL.md body (6,005 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:07:40.517Z","embedding":null,"createdAt":"2026-04-23T13:04:02.825Z","updatedAt":"2026-05-18T19:07:40.517Z","lastSeenAt":"2026-05-18T19:07:40.517Z","tsv":"'/modal.vue':193 '200':197 '3':11 'api':14 'async':67,181 'asyncmod':189 'await':82,93 'best':200 'catch':95 'click':26 'compon':12,179,182 'compos':30 'composables/usefetch.ts':32 'composit':13 'const':46,56,60,73,80,131,143,147,161,188 'context':162,166,174 'context/theme.ts':116 'count':16 'dark':130,152 'data':47,110 'data.value':92 'defineasynccompon':185,190 'delay':196 'e':96,98,101,105 'edit':4 'error':61,63,89,100,103,112,169 'error.value':70,97 'errorcompon':198 'errordisplay':199 'export':40,140,158 'fals':108 'fetch':83 'file':8 'final':106 'function':41,141,159 'handleselect':27 'http':90 'import':33,117,184,192 'inject':119,163 'injectionkey':122,133 'instanceof':99 'item':21,23,28 'item.id':25 'item.name':29 'key':24 'li':17 'light':129,146,151,153 'load':57,111 'loader':191 'loading.value':68,107 'loadingcompon':194 'loadingspinn':195 'model':177 'new':88,102,168 'null':50,51,55,64,65,71 'pattern':114 'practic':201 'project':6 'provid':118,154 'provide/inject':113 'providethem':142 'ref':34,37,44,48,53,58,62,120,124,135,145 'requir':171 'res':81 'res.json':94 'res.ok':86 'res.status':91 'return':109,173 'skill' 'skill-vue' 'source-cofin' 'string':45,77,104 'symbol':138 'theme':128,134,139,144,156 'theme.value':149,150 'themekey':132,155,164 'themeprovid':172 'throw':87,167 'titl':15 'toggl':136,148,157 'topic-agent-skills' 'topic-ai-agents' 'topic-beads' 'topic-claude-code' 'topic-codex' 'topic-cursor' 'topic-developer-tools' 'topic-gemini-cli' 'topic-opencode' 'topic-plugin' 'topic-slash-commands' 'topic-spec-driven-development' 'tri':72 'true':59,69 'ts':31,115,183 'type':36,121,123,127 'typeof':75 'url':43,76,78 'url.value':79 'urlvalu':74,84 'use':2,202 'usefetch':42 'usethem':160,170 'v':19,176 'v-for':18 'v-model':175 'void':137 'vue':1,5,7,10,39,126,180,187 'vue.config.js':9 'watcheffect':35,66","prices":[{"id":"764b09d6-3c5b-4bd3-ac67-12a539eacc14","listingId":"0958def4-b421-4287-a629-b9d4213fae60","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"cofin","category":"flow","install_from":"skills.sh"},"createdAt":"2026-04-23T13:04:02.825Z"}],"sources":[{"listingId":"0958def4-b421-4287-a629-b9d4213fae60","source":"github","sourceId":"cofin/flow/vue","sourceUrl":"https://github.com/cofin/flow/tree/main/skills/vue","isPrimary":false,"firstSeenAt":"2026-04-23T13:04:02.825Z","lastSeenAt":"2026-05-18T19:07:40.517Z"}],"details":{"listingId":"0958def4-b421-4287-a629-b9d4213fae60","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"cofin","slug":"vue","github":{"repo":"cofin/flow","stars":11,"topics":["agent-skills","ai-agents","beads","claude-code","codex","context-driven-development","cursor","developer-tools","gemini-cli","opencode","plugin","slash-commands","spec-driven-development","subagents","tdd","workflow"],"license":"apache-2.0","html_url":"https://github.com/cofin/flow","pushed_at":"2026-04-27T19:07:26Z","description":"Context-Driven Development toolkit for AI agents — spec-first planning, TDD workflow, and Beads integration.","skill_md_sha":"40136e0e7f1c967a926d691f011577392933f9e4","skill_md_path":"skills/vue/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/cofin/flow/tree/main/skills/vue"},"layout":"multi","source":"github","category":"flow","frontmatter":{"name":"vue","description":"Use when editing Vue projects, .vue files, vue.config.js, Vue 3 components, Composition API, <script setup>, SFC state, deployment workflows, or Vue CI configuration."},"skills_sh_url":"https://skills.sh/cofin/flow/vue"},"updatedAt":"2026-05-18T19:07:40.517Z"}}