@jgiox/goodvibes 1.2.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
+ import { createRequire as createRequire2 } from "module";
4
5
  import { Command } from "commander";
5
6
 
6
7
  // src/commands/init.ts
7
- import { intro, outro, note, tasks } from "@clack/prompts";
8
+ import { readdirSync } from "fs";
9
+ import { intro, outro, note, tasks, cancel } from "@clack/prompts";
8
10
 
9
11
  // src/steps/copy-templates.ts
10
12
  import { copy } from "fs-extra";
11
13
  import { readFile as readFile2, rename } from "fs/promises";
12
14
  import { readdir } from "fs/promises";
13
15
  import { existsSync } from "fs";
14
- import { join, relative } from "path";
16
+ import { join, relative, sep } from "path";
15
17
  import { fileURLToPath } from "url";
16
18
 
17
19
  // src/utils/sentinel-merge.ts
@@ -104,26 +106,51 @@ async function copyTemplates(templateDir, destDir, dryRun, minimal, projectType
104
106
  const selectedVariant = `ci-${projectType}.yml`;
105
107
  if (dryRun) {
106
108
  const all = await listTemplateFiles(templateDir);
107
- return all.filter((p) => !ciVariants.some((v) => p.endsWith(v) && v !== selectedVariant));
109
+ return { written: all.filter((p) => !ciVariants.some((v) => p.endsWith(v) && v !== selectedVariant)), skipped: [] };
108
110
  }
109
- await copy(templateDir, destDir, {
110
- overwrite: false,
111
- errorOnExist: false,
112
- filter: (src) => {
113
- if (src.endsWith("CLAUDE.md")) return false;
114
- if (minimal && src.includes(".github/workflows")) return false;
115
- if (relative(templateDir, src).includes("..")) return false;
116
- for (const variant of ciVariants) {
117
- if (src.endsWith(variant) && variant !== selectedVariant) return false;
111
+ const existingBefore = /* @__PURE__ */ new Set();
112
+ if (existsSync(destDir)) {
113
+ const beforeFiles = await walkDir(destDir, destDir).catch(() => []);
114
+ for (const f of beforeFiles) existingBefore.add(f);
115
+ }
116
+ const skippedFiles = [];
117
+ const destCiYml = join(destDir, ".github", "workflows", "ci.yml");
118
+ const workflowPrefix = join(".github", "workflows") + sep;
119
+ const destHasWorkflows = [...existingBefore].some(
120
+ (f) => f.startsWith(workflowPrefix) && f.endsWith(".yml")
121
+ );
122
+ try {
123
+ await copy(templateDir, destDir, {
124
+ overwrite: false,
125
+ errorOnExist: false,
126
+ filter: (src) => {
127
+ if (src.endsWith("CLAUDE.md")) return false;
128
+ const rel = relative(templateDir, src);
129
+ if (minimal && (rel.startsWith(".github") || rel.startsWith("docs"))) return false;
130
+ if (rel.includes("..")) return false;
131
+ if (src.endsWith(selectedVariant) && existsSync(destCiYml)) return false;
132
+ for (const variant of ciVariants) {
133
+ if (src.endsWith(variant) && variant !== selectedVariant) return false;
134
+ }
135
+ if (destHasWorkflows && rel.startsWith(workflowPrefix) && src.endsWith(".yml")) return false;
136
+ return true;
118
137
  }
119
- return true;
120
- }
121
- });
138
+ });
139
+ } catch (e) {
140
+ const err = e;
141
+ const hint = err.code === "EACCES" || err.code === "EPERM" ? "Check directory permissions." : "Check available disk space.";
142
+ err.message = `Cannot copy template files: ${err.message}. ${hint}`;
143
+ throw err;
144
+ }
122
145
  if (!minimal) {
123
146
  const variantPath = join(destDir, ".github", "workflows", selectedVariant);
124
147
  const ciPath = join(destDir, ".github", "workflows", "ci.yml");
125
148
  if (existsSync(variantPath)) {
126
- await rename(variantPath, ciPath);
149
+ if (existsSync(ciPath)) {
150
+ skippedFiles.push(".github/workflows/ci.yml");
151
+ } else {
152
+ await rename(variantPath, ciPath);
153
+ }
127
154
  }
128
155
  }
129
156
  const claudeSrc = join(templateDir, "CLAUDE.md");
@@ -131,7 +158,11 @@ async function copyTemplates(templateDir, destDir, dryRun, minimal, projectType
131
158
  const templateContent = await readFile2(claudeSrc, "utf-8");
132
159
  await mergeClaude(claudeDest, templateContent);
133
160
  const destFiles = await walkDir(destDir, destDir);
134
- return destFiles.sort();
161
+ const allDestFiles = destFiles.sort();
162
+ const written = allDestFiles.filter((f) => !existingBefore.has(f));
163
+ const writtenWithClaude = written.includes("CLAUDE.md") ? written : ["CLAUDE.md", ...written];
164
+ const skipped = [...allDestFiles.filter((f) => existingBefore.has(f) && f !== "CLAUDE.md"), ...skippedFiles];
165
+ return { written: writtenWithClaude.sort(), skipped: skipped.sort() };
135
166
  }
136
167
 
137
168
  // src/steps/install-headroom.ts
@@ -173,6 +204,16 @@ async function installHeadroom(log) {
173
204
  log("Python 3.10+ not found \u2014 skipping headroom install. Install Python 3.10+ and run `goodvibes init` again.");
174
205
  return;
175
206
  }
207
+ log("headroom compresses AI context to save tokens \u2014 this keeps your costs down and sessions faster.");
208
+ try {
209
+ await execa2("headroom", ["--version"]);
210
+ log("headroom already installed \u2014 skipping");
211
+ return;
212
+ } catch (e) {
213
+ if (e.code !== "ENOENT") {
214
+ log(`headroom probe failed: ${e.message?.split("\n")[0] ?? "unknown"}`);
215
+ }
216
+ }
176
217
  log("Note: headroom will download its compression model on first use \u2014 this may take 1\u20133 minutes on a slow connection.");
177
218
  const installers = [
178
219
  { cmd: "uv", args: ["tool", "install", "headroom-ai[all]"] },
@@ -262,15 +303,24 @@ function registerInitCommand(program2) {
262
303
  const cwd = process.cwd();
263
304
  const projectType = detectProjectType(cwd);
264
305
  const templateDir = resolveTemplatesDir();
306
+ const ciVariants = ["ci-node.yml", "ci-python.yml", "ci-both.yml"];
307
+ const selectedVariant = `ci-${projectType}.yml`;
265
308
  intro("goodvibes init");
309
+ const existingEntries = readdirSync(cwd).filter((e) => e !== ".git" && e !== ".DS_Store");
310
+ if (existingEntries.length > 0) {
311
+ note("Existing files will not be overwritten.", "Non-empty project detected");
312
+ }
266
313
  if (dryRun) {
267
- const files = await listTemplateFiles(templateDir);
314
+ const allFiles = await listTemplateFiles(templateDir);
315
+ const files = minimal ? allFiles.filter((f) => !f.startsWith(".github") && !f.startsWith("docs")) : allFiles.filter((f) => !ciVariants.some((v) => f.endsWith(v) && v !== selectedVariant));
268
316
  note(files.map((f) => ` Would write: ${f}`).join("\n"), "Dry run \u2014 no files written");
269
317
  note(
270
318
  [
271
- "1. Open this project in Claude Code",
272
- "2. In Claude Code CLI: /plugin marketplace add DietrichGebert/ponytail",
273
- "3. Start coding \u2014 CLAUDE.md rules are already active"
319
+ "1. Open this project in your AI coding tool",
320
+ "2. Claude Code users: /plugin marketplace add DietrichGebert/ponytail",
321
+ " Other IDEs (Cursor, Windsurf, Kiro, Antigravity, etc.): rules already active",
322
+ "3. Start coding \u2014 CLAUDE.md rules are already active",
323
+ ...minimal ? ["4. Run without --minimal to also add CI workflows and docs."] : []
274
324
  ].join("\n"),
275
325
  "Next steps"
276
326
  );
@@ -278,13 +328,15 @@ function registerInitCommand(program2) {
278
328
  return;
279
329
  }
280
330
  const createdFiles = [];
331
+ const skippedFiles = [];
281
332
  const taskList = [
282
333
  {
283
334
  title: "Copying template files",
284
335
  task: async (message) => {
285
- const files = await copyTemplates(templateDir, cwd, false, minimal, projectType);
286
- createdFiles.push(...files);
287
- return `Copied ${files.length} files`;
336
+ const { written, skipped } = await copyTemplates(templateDir, cwd, false, minimal, projectType);
337
+ createdFiles.push(...written);
338
+ skippedFiles.push(...skipped);
339
+ return `Copied ${written.length} files`;
288
340
  }
289
341
  }
290
342
  ];
@@ -306,14 +358,34 @@ function registerInitCommand(program2) {
306
358
  }
307
359
  );
308
360
  }
309
- await tasks(taskList);
310
- note(createdFiles.join("\n"), "Files created");
361
+ try {
362
+ await tasks(taskList);
363
+ } catch (e) {
364
+ const err = e;
365
+ const msg = err.code === "EACCES" || err.code === "EPERM" ? `Cannot write files to ${cwd}.
366
+ Why: You do not have write permission here.
367
+ Fix: Make sure you are inside your project directory before running this command.
368
+ If permissions are the issue: chmod u+w ${cwd} (macOS/Linux) or check folder properties (Windows)` : `Setup failed: ${err.message ?? String(e)}`;
369
+ cancel(msg);
370
+ process.exit(1);
371
+ }
372
+ note(createdFiles.join("\n") || "(none)", `Files written (${createdFiles.length})`);
373
+ if (skippedFiles.length > 0) {
374
+ note(skippedFiles.join("\n"), `Files skipped (${skippedFiles.length})`);
375
+ }
311
376
  const nextSteps = [
312
- "1. Open this project in Claude Code",
313
- "2. In Claude Code CLI: /plugin marketplace add DietrichGebert/ponytail",
377
+ "1. Open this project in your AI coding tool",
378
+ "2. Claude Code users: /plugin marketplace add DietrichGebert/ponytail",
379
+ " Other IDEs (Cursor, Windsurf, Kiro, Antigravity, etc.): rules already active",
314
380
  "3. Start coding \u2014 CLAUDE.md rules are already active"
315
381
  ].join("\n");
316
382
  note(nextSteps, "Next steps");
383
+ if (minimal) {
384
+ note(
385
+ "CI workflows and docs were skipped.\nRun goodvibes init without --minimal to add them.",
386
+ "Skipped layers"
387
+ );
388
+ }
317
389
  outro("You're all set!");
318
390
  });
319
391
  }
@@ -360,13 +432,6 @@ async function detectInstalledVersion(cwd) {
360
432
  const content = await readFile3(claudePath, "utf-8");
361
433
  return extractVersion(content);
362
434
  }
363
- async function detectBundledVersion(templateDir) {
364
- if (!templateDir) return null;
365
- const claudeSrc = join3(templateDir, "CLAUDE.md");
366
- if (!await pathExists2(claudeSrc)) return null;
367
- const content = await readFile3(claudeSrc, "utf-8");
368
- return extractVersion(content);
369
- }
370
435
  async function computeChanges(templateDir, destDir, projectType) {
371
436
  const allFiles = await listTemplateFiles(templateDir) ?? [];
372
437
  const managedFiles = allFiles.filter(
@@ -423,7 +488,7 @@ async function upgradeTemplates(templateDir, destDir, projectType) {
423
488
  return allDest.filter((f) => f.startsWith(".claude/skills/") || f.startsWith(".github/workflows/") || f === "CLAUDE.md").sort();
424
489
  }
425
490
  function registerUpgradeCommand(program2) {
426
- program2.command("upgrade").description("Update goodvibes-managed files to the latest version").option("--dry-run", "Preview what would change without writing").action(async (options) => {
491
+ program2.command("upgrade").alias("update").description("Update goodvibes-managed files to the latest version").option("--dry-run", "Preview what would change without writing").action(async (options) => {
427
492
  const dryRun = options.dryRun ?? false;
428
493
  const cwd = process.cwd();
429
494
  intro2("goodvibes upgrade");
@@ -446,7 +511,7 @@ function registerUpgradeCommand(program2) {
446
511
  const templateDir = resolveTemplatesDir();
447
512
  const projectType = detectProjectType(cwd);
448
513
  const installedVersion = await detectInstalledVersion(cwd);
449
- const bundledVersion = await detectBundledVersion(templateDir);
514
+ const bundledVersion = getInstalledVersion();
450
515
  if (installedVersion && bundledVersion && versionGte(installedVersion, bundledVersion)) {
451
516
  outro2(`Already up to date (v${installedVersion})`);
452
517
  return;
@@ -473,6 +538,90 @@ function registerUpgradeCommand(program2) {
473
538
  });
474
539
  }
475
540
 
541
+ // src/commands/doctor.ts
542
+ import { note as note3, outro as outro3 } from "@clack/prompts";
543
+ import { existsSync as existsSync4, readFileSync } from "fs";
544
+ import { join as join4 } from "path";
545
+ import { execa as execa5 } from "execa";
546
+ var SENTINEL_START2 = "<!-- goodvibes:start -->";
547
+ var SENTINEL_END2 = "<!-- goodvibes:end -->";
548
+ async function checkHeadroom() {
549
+ try {
550
+ await execa5("headroom", ["--version"]);
551
+ return { label: "headroom on PATH", pass: true };
552
+ } catch (e) {
553
+ if (e.code === "ENOENT") {
554
+ return {
555
+ label: "headroom on PATH",
556
+ pass: false,
557
+ remedy: 'Run: uv tool install "headroom-ai[all]" (or re-run goodvibes init)'
558
+ };
559
+ }
560
+ throw e;
561
+ }
562
+ }
563
+ async function checkGit() {
564
+ const keys = ["user.name", "user.email"];
565
+ const results = [];
566
+ for (const key of keys) {
567
+ try {
568
+ const { stdout } = await execa5("git", ["config", key]);
569
+ results.push({
570
+ label: `git ${key}`,
571
+ pass: stdout.trim().length > 0,
572
+ remedy: stdout.trim().length > 0 ? void 0 : `Run: git config --global ${key} "Your Value"`
573
+ });
574
+ } catch {
575
+ results.push({
576
+ label: `git ${key}`,
577
+ pass: false,
578
+ remedy: `Run: git config --global ${key} "Your Value"`
579
+ });
580
+ }
581
+ }
582
+ return results;
583
+ }
584
+ function checkClaudeMd(cwd) {
585
+ const present = existsSync4(join4(cwd, "CLAUDE.md"));
586
+ return {
587
+ label: "CLAUDE.md present",
588
+ pass: present,
589
+ remedy: present ? void 0 : "Run: goodvibes init"
590
+ };
591
+ }
592
+ function checkSentinel(cwd) {
593
+ const path = join4(cwd, "CLAUDE.md");
594
+ if (!existsSync4(path)) {
595
+ return { label: "goodvibes sentinel block", pass: false, remedy: "Run: goodvibes init" };
596
+ }
597
+ const content = readFileSync(path, "utf-8");
598
+ const ok = content.includes(SENTINEL_START2) && content.includes(SENTINEL_END2);
599
+ return {
600
+ label: "goodvibes sentinel block",
601
+ pass: ok,
602
+ remedy: ok ? void 0 : "Run: goodvibes init (will merge sentinel block)"
603
+ };
604
+ }
605
+ function registerDoctorCommand(program2) {
606
+ program2.command("doctor").description("Check goodvibes setup is complete").action(async () => {
607
+ const cwd = process.cwd();
608
+ const headroomResult = await checkHeadroom();
609
+ const gitResults = await checkGit();
610
+ const claudeMdResult = checkClaudeMd(cwd);
611
+ const sentinelResult = checkSentinel(cwd);
612
+ const all = [headroomResult, ...gitResults, claudeMdResult, sentinelResult];
613
+ const lines = all.map((r) => `${r.pass ? "\u2713" : "\u2717"} ${r.label}`);
614
+ note3(lines.join("\n"), "goodvibes doctor");
615
+ const failures = all.filter((r) => !r.pass);
616
+ if (failures.length > 0) {
617
+ const remediation = failures.filter((r) => r.remedy).map((r) => r.remedy).join("\n");
618
+ note3(remediation, "How to fix");
619
+ process.exit(1);
620
+ }
621
+ outro3("All checks passed.");
622
+ });
623
+ }
624
+
476
625
  // src/index.ts
477
626
  var [major] = process.version.replace("v", "").split(".").map(Number);
478
627
  if (major < 20) {
@@ -484,8 +633,11 @@ Install the latest LTS from https://nodejs.org
484
633
  );
485
634
  process.exit(1);
486
635
  }
636
+ var _require2 = createRequire2(import.meta.url);
637
+ var _pkg = _require2("../package.json");
487
638
  var program = new Command();
488
- program.name("goodvibes").version("1.0.0").description("One-command bootstrap for vibe coding projects");
639
+ program.name("goodvibes").version(_pkg.version).description("One-command bootstrap for vibe coding projects");
489
640
  registerInitCommand(program);
490
641
  registerUpgradeCommand(program);
642
+ registerDoctorCommand(program);
491
643
  await program.parseAsync(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgiox/goodvibes",
3
- "version": "1.2.0",
3
+ "version": "1.6.1",
4
4
  "description": "One-command bootstrap for vibe coding projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,7 +24,10 @@
24
24
  "claude",
25
25
  "llm",
26
26
  "starter-kit",
27
- "cli"
27
+ "cli",
28
+ "ai-coding",
29
+ "claude-code",
30
+ "copilot"
28
31
  ],
29
32
  "publishConfig": {
30
33
  "access": "public"
@@ -37,7 +40,7 @@
37
40
  "test:watch": "vitest"
38
41
  },
39
42
  "dependencies": {
40
- "commander": "^13",
43
+ "commander": "^15",
41
44
  "@clack/prompts": "^1",
42
45
  "fs-extra": "^11",
43
46
  "execa": "^9"
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,11 @@
1
+ Engineering Rules for this project (goodvibes).
2
+
3
+ Think before coding. State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
4
+
5
+ Simplicity first. Stop at the first option that works: Does this need to exist at all? Already in the codebase? Use it. Stdlib covers it? Use it. Can it be one line? One line. Only then write new code. No unrequested abstractions. No boilerplate for later. Deletion over addition.
6
+
7
+ Surgical changes. Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
8
+
9
+ Fail loud. No empty catch blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable and specific.
10
+
11
+ Security. Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege. Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -17,7 +17,14 @@ explicit on-demand audits.
17
17
 
18
18
  ## Setup
19
19
 
20
- Ponytail commands require the ponytail plugin. Install it in Claude Code:
20
+ > **Using Cursor, Windsurf, Kiro, Copilot, Antigravity, Amazon Q, Cline, Continue.dev, Devin Desktop, or another IDE?**
21
+ > The minimalism rules are already embedded in your project's IDE rule file
22
+ > (`.cursor/rules/goodvibes.mdc`, `GEMINI.md`, `.windsurfrules`, `.kiro/steering/goodvibes.md`, `AGENTS.md`, `.clinerules/goodvibes.md`, `.amazonq/rules/goodvibes.md`, `.continue/rules/goodvibes.md`, `.devin/rules/goodvibes.md`)
23
+ > and activate automatically — no plugin setup needed. The `/ponytail-review` and
24
+ > `/ponytail-audit` commands below are **Claude Code CLI terminal only** and are not
25
+ > available in other IDEs.
26
+
27
+ Ponytail commands require the ponytail plugin. Install it in **Claude Code CLI terminal**:
21
28
 
22
29
  ```
23
30
  /plugin marketplace add DietrichGebert/ponytail
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,28 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ ## Engineering Rules — goodvibes
6
+
7
+ ### Think before coding
8
+ State assumptions explicitly before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
9
+
10
+ ### Simplicity first
11
+ Stop at the first rung that holds:
12
+
13
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
14
+ 2. Already in this codebase? Reuse it.
15
+ 3. Stdlib does it? Use it.
16
+ 4. Native platform feature covers it? Use it.
17
+ 5. Already-installed dependency solves it? Use it.
18
+ 6. Can it be one line? One line.
19
+ 7. Only then: the minimum code that works.
20
+
21
+ ### Surgical changes
22
+ Keep diffs narrow. No opportunistic reformats. No renames unless required. Only remove what your change made unused.
23
+
24
+ ### Fail loud
25
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
26
+
27
+ ### Security
28
+ Validate input at the boundary. Keep secrets out of code and logs. Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove imports, variables, or functions that your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable and specific enough to debug.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code, commits, and logs. Apply least privilege for tokens and permissions.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets, unsafe dependency additions.
@@ -0,0 +1,28 @@
1
+ ---
2
+ inclusion: always
3
+ ---
4
+
5
+ ## Engineering Rules — goodvibes
6
+
7
+ ### Think before coding
8
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
9
+
10
+ ### Simplicity first
11
+ Stop at the first rung that holds:
12
+
13
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
14
+ 2. Already in this codebase? Reuse it.
15
+ 3. Stdlib does it? Use it.
16
+ 4. Native platform feature covers it? Use it.
17
+ 5. Already-installed dependency solves it? Use it.
18
+ 6. Can it be one line? One line.
19
+ 7. Only then: the minimum code that works.
20
+
21
+ ### Surgical changes
22
+ Keep diffs narrow. No opportunistic reformats. No renames unless required. Only remove what your change made unused.
23
+
24
+ ### Fail loud
25
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
26
+
27
+ ### Security
28
+ Validate input at the boundary. Keep secrets out of code and logs. Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -1,7 +1,7 @@
1
1
  # CLAUDE.md
2
2
 
3
3
  <!-- goodvibes:start -->
4
- # goodvibes: v1.2.0
4
+ # goodvibes: v1.6.1
5
5
 
6
6
  ## Engineering Rules
7
7
 
@@ -53,6 +53,13 @@ Rules: do not rewrite history. Additive entries only. Keep it short, factual, an
53
53
  **Push to GitHub after every completed task or end of session.**
54
54
  A commit that only exists locally is one machine failure away from being lost. Run `git push origin <branch>` after each commit, or at minimum before stopping for the day. Never leave completed work unpushed for more than one session.
55
55
 
56
+ ### Tools and environment
57
+ **IDE plugin commands are surface-specific.**
58
+ A slash command or plugin install that works in Claude Code terminal will not work in the
59
+ VS Code extension, Cursor, Windsurf, Kiro, or any other IDE. Before referencing a tool
60
+ command in shared docs, prompts, or instructions, confirm which surface it runs on. If it
61
+ only works in one place, say so explicitly — do not leave users to discover it silently fails.
62
+
56
63
  ## Ponytail — Minimalism Ruleset
57
64
 
58
65
  You are a lazy senior developer. Lazy means efficient, not careless. You have
@@ -0,0 +1,28 @@
1
+ ## Engineering Rules — goodvibes
2
+
3
+ ### Think before coding
4
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
5
+
6
+ ### Simplicity first
7
+ Stop at the first rung that holds:
8
+
9
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
10
+ 2. Already in this codebase? Reuse it.
11
+ 3. Stdlib does it? Use it.
12
+ 4. Native platform feature covers it? Use it.
13
+ 5. Already-installed dependency solves it? Use it.
14
+ 6. Can it be one line? One line.
15
+ 7. Only then: the minimum code that works.
16
+
17
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
18
+
19
+ ### Surgical changes
20
+ Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
21
+
22
+ ### Fail loud
23
+ No empty `catch` blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable.
24
+
25
+ ### Security
26
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
27
+
28
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
@@ -0,0 +1,31 @@
1
+ # Getting started with goodvibes
2
+
3
+ You ran `goodvibes init`. Here is what happens next.
4
+
5
+ ## What was set up
6
+
7
+ goodvibes wrote several files into your project: `CLAUDE.md` with engineering rules and the ponytail minimalism ruleset, AI rule files for your coding tool (Cursor, Windsurf, Kiro, GitHub Copilot, and others), CI workflows for automated quality checks, and docs templates including this one. Everything runs automatically — no configuration needed.
8
+
9
+ ## Your first change
10
+
11
+ 1. **Open your project in your AI coding tool.** Cursor, Windsurf, Kiro, and GitHub Copilot all pick up the goodvibes rules automatically. The AI will follow minimal-code and fail-loud principles from the first message.
12
+ 2. **Tell the AI what you want to build.** Describe the feature in plain language — the rules guide the AI to keep code simple and surgical.
13
+ 3. **Review the diff before you commit.** Check that the AI only changed what you asked. The rules encourage narrow diffs — if the change looks too large, ask the AI to trim it.
14
+ 4. **Run `git add . && git commit -m "feat: your change here"`.** This saves a checkpoint in your project history so you can always go back.
15
+ 5. **Run `git push`.** This sends your work to GitHub, where it is safe even if your machine breaks.
16
+
17
+ ## Check your setup
18
+
19
+ Run `goodvibes doctor` to verify everything is working. It checks that headroom is installed, your git identity is configured, and the goodvibes rules are in place.
20
+
21
+ ## Useful commands
22
+
23
+ | Command | What it does |
24
+ |---------|--------------|
25
+ | `goodvibes update` | Re-sync goodvibes files to the latest version |
26
+ | `goodvibes doctor` | Check that headroom, git, and rules are all working |
27
+ | `goodvibes upgrade --dry-run` | Preview what `goodvibes update` would change |
28
+
29
+ ## What is headroom?
30
+
31
+ headroom compresses the AI's memory of your project so you spend fewer tokens per session. It runs automatically in the background when Claude Code is active — you do not need to invoke it manually.
@@ -93,3 +93,21 @@ A maintainer will look at your PR and either approve it, request changes, or ask
93
93
  ---
94
94
 
95
95
  That is the full loop: clone → branch → commit → push → pull request. Every contribution, large or small, follows this same pattern.
96
+
97
+ ---
98
+
99
+ ## Troubleshooting IDE rules
100
+
101
+ **Cursor — rules appear inactive in agent mode**
102
+
103
+ Cursor 3.0.x has a known bug where `alwaysApply: true` rules are silently downgraded in agent mode. If your goodvibes rules seem to have no effect in Cursor:
104
+
105
+ 1. Open Settings (Cmd/Ctrl + ,) and search for "Rules".
106
+ 2. Verify that `goodvibes` is listed under "Always Active" rules.
107
+ 3. If it appears as "Requestable" instead, toggle it to "Always Active" manually.
108
+
109
+ This is an upstream Cursor issue — the `goodvibes.mdc` file format is correct.
110
+
111
+ **Using multiple AI coding tools?**
112
+
113
+ `goodvibes init` writes an `AGENTS.md` file at your project root. This is a cross-tool standard natively read by Zed, Aider, JetBrains Junie (IntelliJ, PyCharm, WebStorm), Jules, Amp, Codex CLI, and many others — without any extra setup. If you switch to a new AI coding tool, check whether it reads `AGENTS.md` before creating a separate rules file.
@@ -0,0 +1,40 @@
1
+ # Base44 — goodvibes setup
2
+
3
+ Base44 does not read files from your project. Instead, you paste your rules into the AI controls panel, and Base44 applies them to every AI interaction in that project.
4
+
5
+ ## Steps
6
+
7
+ 1. Go to [base44.com](https://base44.com) and sign in.
8
+ 2. Open your project.
9
+ 3. Find the **AI controls** panel — it is usually in the top-right corner or under project Settings.
10
+ 4. Click **Custom Instructions**.
11
+ 5. Paste the text below into the box.
12
+ 6. Click **Save**.
13
+
14
+ That is it. From now on, every AI action in this project follows the goodvibes engineering rules.
15
+
16
+ > If the steps above do not match what you see, look for **Custom Instructions** or **AI controls** in the project settings. The UI may change — the paste text stays the same.
17
+
18
+ > **Base44 Skills** is a separate feature for saving reusable instruction sets. goodvibes does not require it — pasting into Custom Instructions is enough.
19
+
20
+ ---
21
+
22
+ ## Paste this text
23
+
24
+ ```
25
+ Engineering Rules — goodvibes
26
+
27
+ Think before coding. State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
28
+
29
+ Simplicity first. Stop at the first option that works: Does this need to exist at all? Already in the codebase? Use it. Stdlib covers it? Use it. Can it be one line? One line. Only then write new code. No unrequested abstractions. No boilerplate for later. Deletion over addition.
30
+
31
+ Surgical changes. Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
32
+
33
+ Fail loud. No empty catch blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable and specific.
34
+
35
+ Security. Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege. Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Last verified: 2026-07-01
@@ -0,0 +1,22 @@
1
+ # Bolt.new — goodvibes setup
2
+
3
+ Bolt.new does not read project files for AI rules. You activate ponytail discipline by pasting the rules into the chat as a one-time instruction.
4
+
5
+ ## One-time setup
6
+
7
+ 1. Open your Bolt.new project.
8
+ 2. In the chat, paste: "Please follow these engineering rules for all code you write:" then copy the text from `CLAUDE.md` between `<!-- goodvibes:start -->` and `<!-- goodvibes:end -->`.
9
+ 3. Bolt.new will acknowledge and apply the rules for the rest of the session.
10
+ 4. Repeat this at the start of each new session, or save it as a pinned message if Bolt.new supports it.
11
+
12
+ ## Ponytail on Bolt.new
13
+
14
+ Once the rules are in the chat context, Bolt.new follows the ponytail minimalism rules: minimal code, surgical changes, fail loud. The AI will tell you when it is skipping something that is not needed yet.
15
+
16
+ ## Headroom
17
+
18
+ Headroom is not applicable inside Bolt.new — context is managed by the Bolt.new platform itself.
19
+
20
+ ---
21
+
22
+ ## Last verified: 2026-07-01
@@ -0,0 +1,38 @@
1
+ # ChatGPT Projects — goodvibes setup
2
+
3
+ ChatGPT does not read files from your project. Instead, you paste your rules directly into the project's custom instructions, and ChatGPT applies them to every conversation in that project.
4
+
5
+ ## Steps
6
+
7
+ 1. Go to [chatgpt.com](https://chatgpt.com) and sign in.
8
+ 2. Click **Projects** in the left sidebar. Create a new project or open an existing one.
9
+ 3. Click the project name at the top of the page. A panel opens on the right.
10
+ 4. Click **Project Instructions**.
11
+ 5. Paste the text below into the box.
12
+ 6. Click **Save**.
13
+
14
+ That is it. From now on, every conversation in this project follows the goodvibes engineering rules.
15
+
16
+ > If the steps above do not match what you see, look for **Project Instructions** or **Custom Instructions** in the project settings panel. The UI may change — the paste text stays the same.
17
+
18
+ ---
19
+
20
+ ## Paste this text
21
+
22
+ ```
23
+ Engineering Rules — goodvibes
24
+
25
+ Think before coding. State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
26
+
27
+ Simplicity first. Stop at the first option that works: Does this need to exist at all? Already in the codebase? Use it. Stdlib covers it? Use it. Can it be one line? One line. Only then write new code. No unrequested abstractions. No boilerplate for later. Deletion over addition.
28
+
29
+ Surgical changes. Keep diffs narrow. No opportunistic reformats. No renames unless the task requires it. Only remove what your change made unused.
30
+
31
+ Fail loud. No empty catch blocks. No silent retries. No returning fake success on real failure. Error messages must be actionable and specific.
32
+
33
+ Security. Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege. Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Last verified: 2026-07-01
@@ -0,0 +1,23 @@
1
+ # Cursor — goodvibes setup
2
+
3
+ goodvibes init wrote `.cursor/rules/goodvibes.mdc` into your project. This file activates the ponytail minimalism rules automatically when you open the project in Cursor.
4
+
5
+ ## Ponytail is already active
6
+
7
+ The rules enforce simplicity-first coding, fail-loud error handling, and surgical changes — no file you did not touch, no code you did not need. You do not need to paste anything. The rules are in `.cursor/rules/goodvibes.mdc` and Cursor loads them for every AI chat in this project.
8
+
9
+ ## Verify activation
10
+
11
+ Open Cursor. In the AI chat, ask: "What are your active rules?" You should see a reference to goodvibes or ponytail in the response.
12
+
13
+ ## If you use .cursorrules (legacy)
14
+
15
+ If your project has a `.cursorrules` file from before goodvibes, the `.cursor/rules/goodvibes.mdc` file is independent. Both will apply. You may want to merge them to avoid duplication.
16
+
17
+ ## Headroom (context compression)
18
+
19
+ Cursor does not use Claude Code's MCP protocol. If you want context compression, install headroom separately and use it via its CLI. See [headroom docs](https://headroom-docs.vercel.app/).
20
+
21
+ ---
22
+
23
+ ## Last verified: 2026-07-01
@@ -0,0 +1,19 @@
1
+ # Kiro — goodvibes setup
2
+
3
+ goodvibes init wrote `.kiro/steering/goodvibes.md` into your project. Kiro applies steering files automatically to all AI interactions in the project.
4
+
5
+ ## Ponytail is already active
6
+
7
+ The ponytail rules in `.kiro/steering/goodvibes.md` enforce simplicity-first coding, fail-loud error handling, and surgical changes. You do not need to paste anything or configure anything — the steering file is active as soon as you open the project in Kiro.
8
+
9
+ ## Verify activation
10
+
11
+ Open Kiro and check the steering files panel in your project settings. You should see `goodvibes.md` listed as an always-on steering file.
12
+
13
+ ## Headroom (context compression)
14
+
15
+ Kiro does not use Claude Code's MCP protocol. If you want context compression, install headroom separately and use it via its CLI. See [headroom docs](https://headroom-docs.vercel.app/).
16
+
17
+ ---
18
+
19
+ ## Last verified: 2026-07-01
@@ -0,0 +1,26 @@
1
+ # Replit Agent — goodvibes setup
2
+
3
+ Replit Agent does not read files from your project automatically. Instead, you provide the rules as a system prompt for the Agent.
4
+
5
+ ## One-time setup
6
+
7
+ 1. Open your Repl.
8
+ 2. Find **System prompt** or **AI instructions** in the Agent settings panel.
9
+ 3. Copy the text from `CLAUDE.md` — specifically the section between `<!-- goodvibes:start -->` and `<!-- goodvibes:end -->`.
10
+ 4. Paste into the system prompt field and click **Save**.
11
+
12
+ That is it. Replit Agent will follow the goodvibes rules for every task in this project.
13
+
14
+ > If you do not see a system prompt field, look for **Agent instructions** or **Custom rules** in the project settings.
15
+
16
+ ## Ponytail on Replit
17
+
18
+ Once the system prompt is set, Replit Agent follows the ponytail rules for every task: minimal code, no over-engineering, and explicit error handling. The AI will tell you if it is skipping something because it is not needed yet.
19
+
20
+ ## Headroom
21
+
22
+ Replit manages its own context. Headroom is not applicable inside Replit — skip the headroom install step if you are Replit-only.
23
+
24
+ ---
25
+
26
+ ## Last verified: 2026-07-01
@@ -0,0 +1,19 @@
1
+ # Windsurf — goodvibes setup
2
+
3
+ goodvibes init wrote `.windsurfrules` into your project. Windsurf reads this file automatically and applies the goodvibes engineering rules to every AI interaction.
4
+
5
+ ## Ponytail is already active
6
+
7
+ The rules in `.windsurfrules` enforce simplicity-first coding, fail-loud error handling, and surgical changes. You do not need to paste anything — Windsurf picks up the file on its own.
8
+
9
+ ## Verify activation
10
+
11
+ Open Windsurf. In the Cascade AI panel, ask: "What are your active rules?" You should see a reference to goodvibes or ponytail in the response.
12
+
13
+ ## Headroom (context compression)
14
+
15
+ Windsurf does not use Claude Code's MCP protocol. If you want context compression, install headroom separately and use it via its CLI. See [headroom docs](https://headroom-docs.vercel.app/).
16
+
17
+ ---
18
+
19
+ ## Last verified: 2026-07-01
@@ -0,0 +1,32 @@
1
+ # Engineering Rules — goodvibes
2
+ <!-- Replit Agent may regenerate this file. Commit it to git to preserve your edits. -->
3
+
4
+ ## Project Overview
5
+ This project uses goodvibes engineering rules. Apply them to every task.
6
+
7
+ ## Coding Style
8
+ State assumptions before implementing. Stop if an assumption is security-sensitive, schema-sensitive, or has multiple materially different interpretations.
9
+
10
+ ## Simplicity First
11
+ Stop at the first rung that holds:
12
+
13
+ 1. Does this need to exist at all? Speculative need → skip it. (YAGNI)
14
+ 2. Already in this codebase? Reuse it.
15
+ 3. Stdlib does it? Use it.
16
+ 4. Native platform feature covers it? Use it.
17
+ 5. Already-installed dependency solves it? Use it.
18
+ 6. Can it be one line? One line.
19
+ 7. Only then: the minimum code that works.
20
+
21
+ No unrequested abstractions. No boilerplate for later. Deletion over addition.
22
+
23
+ ## Surgical Changes
24
+ Keep diffs narrow. No opportunistic reformats. Only remove what your change made unused.
25
+
26
+ ## Fail Loud
27
+ No empty catch blocks. No silent retries. No fake success on real failure. Error messages must be actionable.
28
+
29
+ ## Security
30
+ Validate input at the boundary. Keep secrets out of code and logs. Apply least privilege.
31
+
32
+ Flag immediately: SQL injection, XSS, command injection, path traversal, broken auth, leaked secrets.