agentsclimarketplace

Coding principles

Skill felixhennequin-gif/claude-code-config-template/cli/template-files/claude/skills/core/coding-principles

Production-ready AI config template for Claude Code. CLAUDE.md, agents, skills, hooks, routines, and commands — based on analysis of 55+ open-source repos (Supabase, Bitwarden, Vercel, Cloudflare, OpenAI).

Install
npx -y skills add felixhennequin-gif/claude-code-config-template --skill coding-principles

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Core behavioral rules for any coding task — think before coding, simplicity first, surgical changes, goal-driven execution. Activates on every feature, fix, refactor, or code edit, regardless of stack.

SKILL.md

6.2 KB, as published. Nobody here has run it

Coding principles

Four rules that apply to every code change, regardless of stack. Each rule has a concrete test — if you can't answer the test honestly, you're violating the rule.

1. Think before coding

  • State assumptions explicitly. If the request is ambiguous, name the ambiguity and ask — don't pick silently.
  • Surface tradeoffs (performance vs. simplicity, safety vs. velocity) before implementing, not after.

Test: Could the user point at your diff and say "I didn't ask for that interpretation"? If yes, you assumed instead of asking.

Request: "format the user". "Format" is ambiguous — it could mean a display name for UI, a URL slug for routing, a serialized object for the API, or something else. The right move is to ask the user which one they want before writing code. If the answer is "display name" and you must proceed without a reply, disambiguate in the function name — not in a comment block.

// BAD — silent assumption baked into a generic name
function formatUser(user) {
  return `${user.firstName} ${user.lastName}`;
}

// GOOD — the name itself tells the caller which "format" this is.
// No comment needed; the ambiguity is resolved by the identifier.
function formatUserDisplayName(user) {
  return `${user.firstName} ${user.lastName}`;
}

2. Simplicity first

  • Write the minimum code that solves the stated problem.
  • No speculative flexibility, no abstractions for single-use code, no error handling for scenarios that can't happen.
  • If 200 lines could be 50, rewrite it.

Test: Would a senior engineer reviewing this say it's overcomplicated? If yes, simplify before shipping.

// BAD — factory + class for a one-liner problem
class StringTruncator {
  constructor(options = {}) {
    this.suffix = options.suffix ?? '…';
  }
  truncate(str, n) {
    return str.length <= n ? str : str.slice(0, n) + this.suffix;
  }
}
const truncator = new StringTruncator();

// GOOD — solves the problem, nothing more
function truncate(str, n) {
  return str.length <= n ? str : str.slice(0, n) + '…';
}

3. Surgical changes

  • Touch only what the task requires. Don't "improve" adjacent code, comments, imports, or formatting on the way past.
  • Match the existing style, even if you'd do it differently.
  • Remove only the imports/variables your own changes orphaned. Pre-existing dead code: mention it, don't delete it unless asked.

Test: Can every changed line be traced back to a concrete user requirement? If not, revert the line.

// BAD — fixes the bug but also reformats imports, renames a variable,
// and adds a comment that wasn't asked for
- import { validate } from './utils'
+ import { validate, sanitize } from './utils'
  
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
+ // Email validation regex
+ const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/

- export function isValidEmail(email) {
-   return emailRegex.test(email)
+ export function isValidEmail(email) {
+   return EMAIL_REGEX.test(email.trim())  // added .trim()
  }

// GOOD — one line changed, exactly what was asked
  export function isValidEmail(email) {
-   return emailRegex.test(email)
+   return emailRegex.test(email.trim())
  }

4. Goal-driven execution

Transform imperative tasks into verifiable goals before starting:

Instead of...Transform to...
"Add validation""Write tests for invalid input, then make them pass"
"Fix the bug""Write a failing test that reproduces it, then make it green"
"Refactor X""Run the test suite before and after — must stay green"
"Make it faster""Define the baseline metric and the target, then measure"

Test: If the user walked away and came back, could they tell whether the task is done by running a single command? If not, sharpen the success criterion first.

// BAD — imperative, no success criterion
"Add pagination to GET /items"

// GOOD — verifiable goal
"GET /items?page=2 returns items 21–40, page 3 returns 41–60.
Write a test that fails for both cases, then make it pass."

Anti-patterns

Concrete behaviors that violate the rules above. Each one is a real failure mode seen in practice, not a hypothetical.

  • Silent disambiguation. Picking one interpretation of an ambiguous request and implementing it without surfacing the choice. "Format the user" → implementing formatUser() as display-name without asking whether the caller wanted a slug, a CSV row, or an API payload. The diff looks fine; the caller rewrites it.

  • Defensive scaffolding for impossible states. Wrapping internal code in try/catch, adding null checks, or validating types that the function signature already guarantees. This bloats the diff, hides real errors, and teaches readers that the "can't happen" case might actually happen.

  • Speculative flexibility. Adding a config object, a strategy pattern, or a second parameter "in case we need it later" when the current task has exactly one caller. Three call sites with slightly different needs is the moment to abstract — not one.

  • Drive-by cleanup. Fixing a one-line bug and also renaming variables, reformatting imports, bumping a comment, or "improving" an unrelated helper on the way past. Every extra hunk makes the diff harder to review and the bisect harder to read.

  • Imperative task acceptance. Starting work on "add validation" or "fix the bug" without first rewriting it as a verifiable goal with a pass/fail check. Without a success criterion, "done" becomes a feeling, and the loop closes only when the user notices it's still broken.

  • Error handling for UX at the wrong layer. Catching an exception in a deep utility so the caller "doesn't have to worry about it" — then logging and returning null. The caller now has a silent failure instead of a loud one, and the bug surfaces three layers up with no stack trace.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.