@jgiox/goodvibes 1.2.0 → 1.4.0

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
@@ -4,7 +4,8 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
- import { intro, outro, note, tasks } from "@clack/prompts";
7
+ import { readdirSync } from "fs";
8
+ import { intro, outro, note, tasks, cancel } from "@clack/prompts";
8
9
 
9
10
  // src/steps/copy-templates.ts
10
11
  import { copy } from "fs-extra";
@@ -104,26 +105,46 @@ async function copyTemplates(templateDir, destDir, dryRun, minimal, projectType
104
105
  const selectedVariant = `ci-${projectType}.yml`;
105
106
  if (dryRun) {
106
107
  const all = await listTemplateFiles(templateDir);
107
- return all.filter((p) => !ciVariants.some((v) => p.endsWith(v) && v !== selectedVariant));
108
+ return { written: all.filter((p) => !ciVariants.some((v) => p.endsWith(v) && v !== selectedVariant)), skipped: [] };
108
109
  }
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;
110
+ const existingBefore = /* @__PURE__ */ new Set();
111
+ if (existsSync(destDir)) {
112
+ const beforeFiles = await walkDir(destDir, destDir).catch(() => []);
113
+ for (const f of beforeFiles) existingBefore.add(f);
114
+ }
115
+ const skippedFiles = [];
116
+ const destCiYml = join(destDir, ".github", "workflows", "ci.yml");
117
+ try {
118
+ await copy(templateDir, destDir, {
119
+ overwrite: false,
120
+ errorOnExist: false,
121
+ filter: (src) => {
122
+ if (src.endsWith("CLAUDE.md")) return false;
123
+ const rel = relative(templateDir, src);
124
+ if (minimal && (rel.startsWith(".github") || rel.startsWith("docs"))) return false;
125
+ if (rel.includes("..")) return false;
126
+ if (src.endsWith(selectedVariant) && existsSync(destCiYml)) return false;
127
+ for (const variant of ciVariants) {
128
+ if (src.endsWith(variant) && variant !== selectedVariant) return false;
129
+ }
130
+ return true;
118
131
  }
119
- return true;
120
- }
121
- });
132
+ });
133
+ } catch (e) {
134
+ const err = e;
135
+ const hint = err.code === "EACCES" || err.code === "EPERM" ? "Check directory permissions." : "Check available disk space.";
136
+ err.message = `Cannot copy template files: ${err.message}. ${hint}`;
137
+ throw err;
138
+ }
122
139
  if (!minimal) {
123
140
  const variantPath = join(destDir, ".github", "workflows", selectedVariant);
124
141
  const ciPath = join(destDir, ".github", "workflows", "ci.yml");
125
142
  if (existsSync(variantPath)) {
126
- await rename(variantPath, ciPath);
143
+ if (existsSync(ciPath)) {
144
+ skippedFiles.push(".github/workflows/ci.yml");
145
+ } else {
146
+ await rename(variantPath, ciPath);
147
+ }
127
148
  }
128
149
  }
129
150
  const claudeSrc = join(templateDir, "CLAUDE.md");
@@ -131,7 +152,11 @@ async function copyTemplates(templateDir, destDir, dryRun, minimal, projectType
131
152
  const templateContent = await readFile2(claudeSrc, "utf-8");
132
153
  await mergeClaude(claudeDest, templateContent);
133
154
  const destFiles = await walkDir(destDir, destDir);
134
- return destFiles.sort();
155
+ const allDestFiles = destFiles.sort();
156
+ const written = allDestFiles.filter((f) => !existingBefore.has(f));
157
+ const writtenWithClaude = written.includes("CLAUDE.md") ? written : ["CLAUDE.md", ...written];
158
+ const skipped = [...allDestFiles.filter((f) => existingBefore.has(f) && f !== "CLAUDE.md"), ...skippedFiles];
159
+ return { written: writtenWithClaude.sort(), skipped: skipped.sort() };
135
160
  }
136
161
 
137
162
  // src/steps/install-headroom.ts
@@ -262,15 +287,24 @@ function registerInitCommand(program2) {
262
287
  const cwd = process.cwd();
263
288
  const projectType = detectProjectType(cwd);
264
289
  const templateDir = resolveTemplatesDir();
290
+ const ciVariants = ["ci-node.yml", "ci-python.yml", "ci-both.yml"];
291
+ const selectedVariant = `ci-${projectType}.yml`;
265
292
  intro("goodvibes init");
293
+ const existingEntries = readdirSync(cwd).filter((e) => e !== ".git" && e !== ".DS_Store");
294
+ if (existingEntries.length > 0) {
295
+ note("Existing files will not be overwritten.", "Non-empty project detected");
296
+ }
266
297
  if (dryRun) {
267
- const files = await listTemplateFiles(templateDir);
298
+ const allFiles = await listTemplateFiles(templateDir);
299
+ const files = minimal ? allFiles.filter((f) => !f.startsWith(".github") && !f.startsWith("docs")) : allFiles.filter((f) => !ciVariants.some((v) => f.endsWith(v) && v !== selectedVariant));
268
300
  note(files.map((f) => ` Would write: ${f}`).join("\n"), "Dry run \u2014 no files written");
269
301
  note(
270
302
  [
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"
303
+ "1. Open this project in your AI coding tool",
304
+ "2. Claude Code users: /plugin marketplace add DietrichGebert/ponytail",
305
+ " Other IDEs (Cursor, Windsurf, Kiro, Antigravity, etc.): rules already active",
306
+ "3. Start coding \u2014 CLAUDE.md rules are already active",
307
+ ...minimal ? ["4. Run without --minimal to also add CI workflows and docs."] : []
274
308
  ].join("\n"),
275
309
  "Next steps"
276
310
  );
@@ -278,13 +312,15 @@ function registerInitCommand(program2) {
278
312
  return;
279
313
  }
280
314
  const createdFiles = [];
315
+ const skippedFiles = [];
281
316
  const taskList = [
282
317
  {
283
318
  title: "Copying template files",
284
319
  task: async (message) => {
285
- const files = await copyTemplates(templateDir, cwd, false, minimal, projectType);
286
- createdFiles.push(...files);
287
- return `Copied ${files.length} files`;
320
+ const { written, skipped } = await copyTemplates(templateDir, cwd, false, minimal, projectType);
321
+ createdFiles.push(...written);
322
+ skippedFiles.push(...skipped);
323
+ return `Copied ${written.length} files`;
288
324
  }
289
325
  }
290
326
  ];
@@ -306,14 +342,34 @@ function registerInitCommand(program2) {
306
342
  }
307
343
  );
308
344
  }
309
- await tasks(taskList);
310
- note(createdFiles.join("\n"), "Files created");
345
+ try {
346
+ await tasks(taskList);
347
+ } catch (e) {
348
+ const err = e;
349
+ const msg = err.code === "EACCES" || err.code === "EPERM" ? `Cannot write files to ${cwd}.
350
+ Why: You do not have write permission here.
351
+ Fix: Make sure you are inside your project directory before running this command.
352
+ If permissions are the issue: chmod u+w ${cwd} (macOS/Linux) or check folder properties (Windows)` : `Setup failed: ${err.message ?? String(e)}`;
353
+ cancel(msg);
354
+ process.exit(1);
355
+ }
356
+ note(createdFiles.join("\n") || "(none)", `Files written (${createdFiles.length})`);
357
+ if (skippedFiles.length > 0) {
358
+ note(skippedFiles.join("\n"), `Files skipped (${skippedFiles.length})`);
359
+ }
311
360
  const nextSteps = [
312
- "1. Open this project in Claude Code",
313
- "2. In Claude Code CLI: /plugin marketplace add DietrichGebert/ponytail",
361
+ "1. Open this project in your AI coding tool",
362
+ "2. Claude Code users: /plugin marketplace add DietrichGebert/ponytail",
363
+ " Other IDEs (Cursor, Windsurf, Kiro, Antigravity, etc.): rules already active",
314
364
  "3. Start coding \u2014 CLAUDE.md rules are already active"
315
365
  ].join("\n");
316
366
  note(nextSteps, "Next steps");
367
+ if (minimal) {
368
+ note(
369
+ "CI workflows and docs were skipped.\nRun goodvibes init without --minimal to add them.",
370
+ "Skipped layers"
371
+ );
372
+ }
317
373
  outro("You're all set!");
318
374
  });
319
375
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgiox/goodvibes",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
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"
@@ -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.
@@ -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.3.0
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.
@@ -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.