Skip to content

/coding-effectively

ALWAYS use this skill when writing or refactoring code. Includes context-dependent sub-skills to empower different coding styles across languages and runtimes.

shell
$ npx -y skills add ed3dai/ed3d-plugins --skill coding-effectively --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/coding-effectively
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

ALWAYS use this skill when writing or refactoring code. Includes context-dependent sub-skills to empower different coding styles across languages and runtimes.

SKILL.md

coding-effectively.SKILL.md
name: coding-effectively
description: ALWAYS use this skill when writing or refactoring code. Includes context-dependent sub-skills to empower different coding styles across languages and runtimes.
user-invocable: false

Coding Effectively

Required Sub-Skills

**ALWAYS REQUIRED:**

  • `howto-functional-vs-imperative` - Separate pure logic from side effects
  • `defense-in-depth` - Validate at every layer data passes through

**CONDITIONAL:** Use these sub-skills when applicable:

  • `howto-code-in-typescript` - TypeScript code
  • `howto-code-in-rust` - Rust code
  • `howto-develop-with-postgres` - PostgreSQL database code
  • `programming-in-react` - React frontend code
  • `writing-good-tests` - Writing or reviewing tests
  • `property-based-testing` - Tests for serialization, validation, normalization, pure functions

Property-Driven Design

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:**

  • "What about deleted/deactivated entities?"
  • "Case-sensitive or not?"
  • "Stable sort or not? Tie-breaking rules?"
  • "Which algorithm? Configurable?"

Surface these during design, not during debugging.

Core Engineering Principles

Correctness Over Convenience

Model the full error space. No shortcuts.

  • Handle all edge cases: race conditions, timing issues, partial failures
  • Use the type system to encode correctness constraints
  • Prefer compile-time guarantees over runtime checks where possible
  • When uncertain, explore and iterate rather than assume

**Don't:**

  • Simplify error handling to save time
  • Ignore edge cases because "they probably won't happen"
  • Use `any` or equivalent to bypass type checking

Error Handling Philosophy

**Two-tier model:**

1. **User-facing errors**: Semantic exit codes, rich diagnostics, actionable messages 2. **Internal errors**: Programming errors that may panic or use internal types

**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.

Pragmatic Incrementalism

  • Prefer specific, composable logic over abstract frameworks
  • Evolve design incrementally rather than perfect upfront architecture
  • Don't build for hypothetical future requirements
  • Document design decisions and trade-offs when making non-obvious choices

**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.

File Organization

Descriptive File Names Over Catch-All Files

Name files by what they contain, not by generic categories.

**Don't create:**

  • `utils.ts` - Becomes a dumping ground for unrelated functions
  • `helpers.ts` - Same problem
  • `common.ts` - What isn't common?
  • `misc.ts` - Actively unhelpful

**Do create:**

  • `string-formatting.ts` - String manipulation utilities
  • `date-arithmetic.ts` - Date calculations
  • `api-error-handling.ts` - API error utilities
  • `user-validation.ts` - User input validation

**Why this matters:**

  • Discoverability: Developers find code by scanning file names
  • Cohesion: Related code stays together
  • Prevents bloat: Hard to add unrelated code to `string-formatting.ts`
  • Import clarity: `import { formatDate } from './date-arithmetic'` is self-documenting

**When you're tempted to create utils.ts:** Stop. Ask what the functions have in common. Name the file after that commonality.

Module Organization

  • Keep module boundaries strict with restricted visibility
  • Platform-specific code in separate files: `unix.ts`, `windows.ts`, `posix.ts`
  • Use conditional compilation or runtime checks for platform branching
  • Test helpers in dedicated modules/files, not mixed with production code

Cross-Platform Principles

Use OS-Native Logic

Don't emulate Unix on Windows or vice versa. Use each platform's native patterns.

**Bad:** Trying to make Windows paths behave like Unix paths everywhere.

**Good:** Accept platform differences, handle them explicitly.

// Platform-specific behavior
if (process.platform === 'win32') {
  // Windows-native approach
} else {
  // POSIX approach
}

Platform-Specific Files

When platform differences are significant, use separate files:

process-spawn.ts        // Shared interface and logic
process-spawn-unix.ts   // Unix-specific implementation
process-spawn-windows.ts // Windows-specific implementation

Document Platform Differences

When behavior differs by platform, document it in comments:

// On Windows, this returns CRLF line endings.
// On Unix, this returns LF line endings.
// Callers should normalize if consistent output is needed.
function readTextFile(path: string): string { ... }

Test on All Target Platforms

Don't assume Unix behavior works on Windows. Test explicitly:

  • CI should run on all supported platforms
  • Platform-specific code paths need platform-specific tests
  • Document which pla
Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withed3d-plugins

This is my collection of plugins that I use on a day-to-day basis for getting stuff done with Claude Code. Most of these are development-oriented in some way or another, but also often end up being useful for other things.

Get the whole plugin, auto-invoked