From 63821fabd49e2b019d8a7dee8f052c440db51579 Mon Sep 17 00:00:00 2001 From: Joris Neuteboom Date: Wed, 21 Oct 2026 10:36:11 +0200 Subject: [PATCH] chore(ai-tool-config): tighten Claude Code rules on checks, public config and v-html - global.md: run `pnpm run typecheck` (wired by essentials as `nuxi typecheck`, and run in CI) next to lint and tests, and never get checks green by suppressing them. - security.md: nothing secret under `runtimeConfig.public`; never render user-controlled content with `v-html` (no sanitizer ships and `xssValidator` is off). ai-tool-config 1.2.1. --- CHANGELOG.md | 5 +++++ packages/preset-nuxt4/src/features/ai-tool-config.ts | 2 +- .../ai-tool-config/claude-code/.claude/rules/global.md | 2 +- .../ai-tool-config/claude-code/.claude/rules/security.md | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10120f3e..03cd6066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +- The Claude Code rules now ask for `pnpm run typecheck` next to lint and tests, + and rule out getting checks green by suppressing them (`@ts-ignore`, `as any`, + `eslint-disable`, skipped tests, `--no-verify`). `security.md` adds that nothing + secret goes under `runtimeConfig.public` and that user content is never rendered + with `v-html`. Existing projects get this via `battlestack pull`. - The generated Dockerfile pins the latest `node:24-alpine` image. - The project name recorded in `.battlestack/manifest.json` now always wins over the directory name. Before, any project command in a clone, CI checkout or diff --git a/packages/preset-nuxt4/src/features/ai-tool-config.ts b/packages/preset-nuxt4/src/features/ai-tool-config.ts index 58916243..d50b0ebf 100644 --- a/packages/preset-nuxt4/src/features/ai-tool-config.ts +++ b/packages/preset-nuxt4/src/features/ai-tool-config.ts @@ -16,7 +16,7 @@ const SUPPORTED: AiTool[] = ['claude-code', 'gemini-cli', 'cursor', 'codex'] /** AI coding tool rules + MCP server scaffolding. Selection via `state.aiTool` (default: `claude-code`). */ export const aiToolConfigFeature: Feature = { id: 'shared:ai-tool-config', - version: '1.2.0', + version: '1.2.1', label: 'AI coding tool config', stage: STAGE.AI_TOOL_CONFIG, diff --git a/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/global.md b/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/global.md index 1ba9a4e2..7b599fc2 100644 --- a/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/global.md +++ b/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/global.md @@ -1,7 +1,7 @@ ## Project Conventions - Default package manager is **pnpm**. `bun`, `npm`, `yarn` also work; match the project's `packageManager` field. Use `pnpm add`, `pnpm dlx`, `pnpm run`. -- Always run `pnpm run lint` and `pnpm test` before considering work complete. +- Always run `pnpm run lint`, `pnpm run typecheck` and `pnpm test` before considering work complete. Fix the cause of a failure; never get green with `@ts-ignore`, `as any`, `eslint-disable`, a skipped or deleted test, or `git commit --no-verify`. - The workflows in `.claude/skills/` only load when invoked, so reach for them yourself: `task-arbiter` before a task, `brainstorming` before a new feature, `test-driven-development` while coding, `systematic-debugging` for a bug, `verification-before-completion` before calling it done. ## Pending upstream merges: `.battlestack/pull/` diff --git a/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/security.md b/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/security.md index 4257732d..8cf69120 100644 --- a/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/security.md +++ b/packages/preset-nuxt4/templates/ai-tool-config/claude-code/.claude/rules/security.md @@ -55,6 +55,7 @@ const body = await readValidatedBody(event, schema.parse) - Secrets in `.env`; never hardcode API keys, passwords, or tokens - `.env` is in `.gitignore`; `.env.example` is committed (with placeholder values) - Use `useRuntimeConfig()` in server routes for Nuxt env access +- Nothing secret goes under `runtimeConfig.public`: it is serialized into every page - AI gateway key, admin password, session secret: all from `.env` ## Headers and Cookies @@ -69,4 +70,5 @@ const body = await readValidatedBody(event, schema.parse) - Don't log passwords or sensitive data (seed script is silent) - Don't disable ESLint security rules - Don't use unsafe code execution patterns +- Don't render user-controlled content with `v-html`; `{{ }}` escapes it, `v-html` does not, and nothing on the server strips HTML - Don't store sessions in localStorage; use httpOnly cookies