code-quality/skills/vilt-standards/SKILL.md
Apply VILT stack coding standards when writing Vue, Laravel, or TypeScript code. Automatically enforces patterns for Composition API, Form Requests, Inertia navigation, and component hierarchy. Activates when creating or modifying Vue components, Laravel controllers, services, or models.
npx skillsauth add richardhowes/self-improvement-code-quality-plugin vilt-coding-standardsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Apply these standards when writing code in ResRequest projects.
Always use <script setup lang="ts">:
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useForm } from '@inertiajs/vue3'
import { Button } from '@/components/ui/button'
interface Props {
items: Item[]
}
const props = defineProps<Props>()
</script>
Define interfaces for all props and emits:
interface Props {
user: User
isEditing?: boolean
}
interface Emits {
(e: 'saved', user: User): void
(e: 'cancelled'): void
}
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
Never use Options API. Always use Composition API:
// CORRECT: Composition API
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
// WRONG: Options API
export default {
data() {
return { count: 0 }
},
computed: {
doubleCount() { return this.count * 2 }
}
}
Always use useForm() from Inertia for forms:
import { useForm } from '@inertiajs/vue3'
const form = useForm({
name: '',
email: '',
})
function submit() {
form.post(route('users.store'), {
preserveScroll: true,
onSuccess: () => form.reset(),
})
}
Always use Form Request classes:
// CORRECT: Form Request
public function store(CreateUserRequest $request): RedirectResponse
{
User::create($request->validated());
return redirect()->back();
}
// WRONG: Inline validation
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([...]);
}
Use Resources for API/Inertia responses:
public function index(): Response
{
return Inertia::render('Users/Index', [
'users' => UserResource::collection(User::all()),
]);
}
Handle errors first, success case last:
public function store(CreateUserRequest $request): RedirectResponse
{
if (! $request->user()->canCreateUsers()) {
abort(403);
}
if (User::where('email', $request->email)->exists()) {
return redirect()->back()->withErrors(['email' => 'Email already exists']);
}
// Happy path last
User::create($request->validated());
return redirect()->route('users.index');
}
Always authorize before action:
public function destroy(User $user): RedirectResponse
{
$this->authorize('delete', $user);
$user->delete();
return redirect()->route('users.index');
}
Use typed properties, not docblocks:
class UserService
{
public function __construct(
private UserRepository $repository,
private EmailService $emailService,
) {}
}
Always specify return types including void:
public function createUser(array $data): User
{
return User::create($data);
}
public function sendNotification(User $user): void
{
// ...
}
Use typed casts array:
protected $casts = [
'is_active' => 'boolean',
'metadata' => 'array',
'published_at' => 'datetime',
];
Type hint relationships:
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
public function profile(): HasOne
{
return $this->hasOne(Profile::class);
}
Never use any. Use proper types or unknown:
// WRONG
function process(data: any) { }
// CORRECT
function process(data: unknown) { }
function process(data: Record<string, string>) { }
Prefer interfaces for object shapes:
// CORRECT
interface User {
id: number
name: string
}
// Less preferred (but OK for unions/intersections)
type UserId = number | string
Never commit:
console.log(), console.debug()dd(), dump(), ray()debugger statementsWrite self-documenting code. Only comment WHY, not WHAT:
// WRONG: Comment explains what code does
// Get the user
$user = User::find($id);
// CORRECT: Comment explains why
// Using findOrFail would throw before we can show custom error
$user = User::find($id);
if (! $user) {
return $this->userNotFoundResponse($id);
}
All user-facing strings must use translations:
<!-- Vue -->
<Button>{{ $t('common.save') }}</Button>
// Laravel
return redirect()->back()->with('success', __('users.created'));
testing
Self-improving meta-skill that learns from user corrections and updates the TARGET PROJECT's skill files. Only runs when user explicitly says "reflect". Commits all skill updates to Git.
documentation
Enforce Inertia.js patterns in Vue components. Prevents axios usage, ensures proper form handling, and guides navigation patterns. Activates when working with data fetching, form submissions, or page navigation in Vue components.
documentation
Guide component selection in ResRequest Vue projects. Ensures correct usage of ShadCN-Vue vs custom components, proper imports, and design system compliance. Activates when creating or modifying Vue components.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.