`tailwind_config_gen.py` overwrites an existing Tailwind config, and `sync-brand-to-tokens.cjs` writes a second token source (or crashes) next to an existing one
I ran two of the scripts that write into the user's project against a scratch project that already has its own Tailwind config and CSS custom-property tokens — the usual Vite/Next + shadcn layout. Neither script looks at what is already there. Both repros take under a minute from a shell.
Setup
nextlevelbuilder/ui-ux-pro-max-skill@7f69fed(currentmain; identical to the 2.13.0 plugin install)- Claude Code (desktop app, zsh), macOS 15.7.7, Python 3.13.5, Node v26.0.0
<skills>below =.claude/skillsof that checkout (the same files ship undercli/assets/skills/)
1. ui-styling/scripts/tailwind_config_gen.py silently overwrites tailwind.config.ts
mkdir demo && cd demo
printf '// existing project config\nexport default { theme: { extend: { colors: { progress: "var(--progress)" } } } }\n' > tailwind.config.ts
python3 <skills>/ui-styling/scripts/tailwind_config_gen.py --colors brand:blue
# Configuration written to …/demo/tailwind.config.ts (exit 0)
grep -c progress tailwind.config.ts # 1 before, 0 after
The command is the example from ui-styling/SKILL.md L228. TypeScript is the default (L389), _default_output_path() resolves to tailwind.config.ts in the working directory (L47), and write_config() calls write_text (L277) with no existence check — no prompt, no backup, no warning. The existing test_write_config* tests only write into an empty tmp_path, so nothing covers this case.
The repo already has the pattern that would close it: shadcn_add.py refuses to reinstall without --overwrite, and #324 added --force to protect existing skill files in the CLI. Refusing when the target exists unless --force is passed (or printing to stdout) would do it here.
2. brand/scripts/sync-brand-to-tokens.cjs ignores the project's existing token source
Scratch project: docs/brand-guidelines.md copied from brand/templates/brand-guidelines-starter.md, tokens already defined in src/index.css (:root { --primary: …; --foreground: … }) and mapped in tailwind.config.js.
a) No assets/ directory (the default for Vite and Next projects):
Extracted colors:
Primary: primary (#2563EB)
Error: ENOENT: no such file or directory, open '…/assets/design-tokens.json'
Exit 1. fs.writeFileSync(tokensPath, …) (L231) runs without creating the directory; design-system/scripts/generate-tokens.cjs already does mkdir -p for its own output.
b) With an empty assets/: exit 0, ✨ Brand sync complete!, and the script writes assets/design-tokens.json plus assets/design-tokens.css (30 --primitive-color-* variables). src/index.css is untouched and nothing imports the new file, so the project now has two token sources and only the old one is read. The only existence check is for the script's own JSON (L216). inject-brand-context.cjs likewise reads only docs/brand-guidelines.md and never mentions the token source the project actually uses.
A detection step before writing would close both: look for an existing token source (custom properties on :root in the project's CSS entry, theme colours in a Tailwind config, a tokens file the build references) and stop with a message naming it, unless an explicit output path or --force is given — plus mkdir -p for the target directory.
Related, but distinct
#246 / #275 (plugin-name injection in the same Tailwind generator) and #283 (execSync in sync-brand-to-tokens.cjs) changed these files for security reasons. Neither covers what gets overwritten, or what gets written next to an existing source.
Source: nextlevelbuilder/ui-ux-pro-max-skill