with one click
coding-effectively
// Always use this skill when writing or refactoring code. Covers general code design, error handling, file organization, and code style patterns.
// Always use this skill when writing or refactoring code. Covers general code design, error handling, file organization, and code style patterns.
You MUST use this before any creative work — creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements, and design before implementation; uses plannotator for structured option/spec review and hands off to writing-plans for execution decomposition.
Use when you have a spec or requirements for a multi-step task, before touching code. Decomposes the spec into bite-sized TDD tasks; emits a beans hierarchy (epic / feature / task) when the beans CLI is available, otherwise a markdown plan.
Challenges AI-generated plans, code, designs, and decisions before you commit. Pairs with any other skill as a review layer. Uses pre-mortem analysis, inversion thinking, and Socratic questioning to find what AI missed — blind spots, hidden assumptions, failure modes, and optimistic shortcuts. The skill that asks 'are you sure about that?' so you don't have to.
Request a code review from the user via plannotator. Use at the end of an implementation task, or when the user asks for a review cycle. Collects structured annotations, then addresses each item.
Use when completing development phases or branches to identify and update CLAUDE.md or AGENTS.md files that may have become stale - analyzes what changed, determines affected contracts and documentation, and coordinates updates
Use when creating or updating CLAUDE.md files for projects or subdirectories - covers top-level vs domain-level organization, capturing architectural intent and contracts, and mandatory freshness dates
| name | coding-effectively |
| description | Always use this skill when writing or refactoring code. Covers general code design, error handling, file organization, and code style patterns. |
| cc:user-invocable | false |
Model the full error space. No shortcuts.
Errors should never be swallowed. When handling errors there are multiple options:
But you should never swallow errors unhandled.
Two-tier model:
Error message format: Lowercase sentence fragments for "failed to {message}".
Good: failed to connect to database: connection refused
Bad: Failed to Connect to Database: Connection Refused
Good: invalid configuration: missing required field 'apiKey'
Bad: Invalid Configuration: Missing Required Field 'apiKey'
Lowercase fragments compose naturally: "operation failed: " + error.message reads correctly.
The rule of three applies to abstraction: Don't abstract until you've seen the pattern three times. Three similar lines of code is better than a premature abstraction.
Name files by what they contain, not by generic categories.
Don't create:
utils.ts - Becomes a dumping ground for unrelated functionshelpers.ts - Same problemcommon.ts - What isn't common?misc.ts - Actively unhelpfulDo create:
string-formatting.ts - String manipulation utilitiesdate-arithmetic.ts - Date calculationsapi-error-handling.ts - API error utilitiesuser-validation.ts - User input validationWhy this matters:
string-formatting.tsimport { formatDate } from './date-arithmetic' is self-documentingWhen you're tempted to create utils.ts: Stop. Ask what the functions have in common. Name the file after that commonality.
unix.ts, windows.ts, posix.tsSmall and focused functions promote cohesion and testability. If you find a function does more than one thing conceptually, or you are tempted to put 'And' in the name of the function: it does too much.
Always keep the happy path left-aligned, avoid deeply nested if-blocks. This harms readability and makes it harder to modify.
Don't:
const possibleValues = getPossibleValues();
const value = getSelected();
if (value !== null) {
if (possibleValues.contains(value)) {
return value;
}
return null;
}
return null;
Do:
const possibleValues = getPossibleValues();
const value = getSelected();
if (value === null) {
return null;
}
if (!possibleValues.contains(value)) {
return null;
}
return value;
When designing features, think about properties upfront. This surfaces design gaps early.
Discovery questions:
| Question | Property Type | Example |
|---|---|---|
| Does it have an inverse operation? | Roundtrip | decode(encode(x)) == x |
| Is applying it twice the same as once? | Idempotence | f(f(x)) == f(x) |
| What quantities are preserved? | Invariants | Length, sum, count unchanged |
| Is order of arguments irrelevant? | Commutativity | f(a, b) == f(b, a) |
| Can operations be regrouped? | Associativity | f(f(a,b), c) == f(a, f(b,c)) |
| Is there a neutral element? | Identity | f(x, 0) == x |
| Is there a reference implementation? | Oracle | new(x) == old(x) |
| Can output be easily verified? | Easy to verify | is_sorted(sort(x)) |
Common design questions these reveal:
Surface these during design, not during debugging.
Stop and refactor when you see:
utils or helpers fileas any) to bypass the type system