Use when designing solutions, adding features, or refactoring by applying KISS, YAGNI, and Principle of Least Astonishment to write simple, predictable code.
Applies KISS, YAGNI, and POLA principles to write simple, predictable code. Claude uses this when designing solutions, adding features, or refactoring to avoid over-engineering and ensure code behaves as expected.
/plugin marketplace add TheBushidoCollective/han/plugin install jutsu-scratch@hanThis skill is limited to using the following tools:
Write code that is simple, necessary, and unsurprising.
# COMPLEX - Over-engineered
defmodule PaymentCalculator do
use GenServer
def start_link(_), do: GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
def calculate(items), do: GenServer.call(__MODULE__, {:calculate, items})
def handle_call({:calculate, items}, _from, state) do
result = Enum.reduce(items, Money.new(:USD, 0), &Money.add(&2, &1.price))
{:reply, result, state}
end
end
# SIMPLE - Just a function
defmodule PaymentCalculator do
def calculate(items) do
Enum.reduce(items, Money.new(:USD, 0), &Money.add(&2, &1.price))
end
end
# Use GenServer only when you need state/concurrency
# COMPLEX - Unnecessary abstraction
defmodule UserQuery do
defmacro by_status(status) do
quote do
from u in User, where: u.status == ^unquote(status)
end
end
end
# SIMPLE - Direct query
def active_users do
from u in User, where: u.status == "active"
end
def inactive_users do
from u in User, where: u.status == "inactive"
end
# Macros only when you need metaprogramming
// COMPLEX - Over-abstraction
class UserDataManager {
private dataSource: DataSource;
private cache: Cache;
private transformer: DataTransformer;
async getUser(id: string): Promise<User> {
const cached = await this.cache.get(id);
if (cached) return this.transformer.transform(cached);
const raw = await this.dataSource.fetch(id);
await this.cache.set(id, raw);
return this.transformer.transform(raw);
}
}
// SIMPLE - Direct approach
async function getUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// Add cache/transform only when performance demands it
// COMPLEX - Clever but confusing
const isValid = (x: number) => !!(x >= 0 && x <= 100);
const process = (items: number[]) =>
items.filter(isValid).reduce((a, b) => a + b, 0);
// SIMPLE - Clear intent
function calculateTotal(scores: number[]): number {
const validScores = scores.filter(score => score >= 0 && score <= 100);
return validScores.reduce((sum, score) => sum + score, 0);
}
# YAGNI VIOLATION - Premature abstraction
defmodule NotificationService do
def send(notification, opts \\ []) do
provider = opts[:provider] || :default
priority = opts[:priority] || :normal
retry_strategy = opts[:retry_strategy] || :exponential
callback = opts[:callback]
# Complex routing logic for features we don't use yet
end
end
# GOOD - Build what you need now
defmodule NotificationService do
def send_email(to, subject, body) do
Email.send(to, subject, body)
end
# Add SMS when we actually need it
# Add priorities when we have the requirement
# Add retries when we see failures
end
# YAGNI VIOLATION - Unused flexibility
defmodule User do
schema "users" do
field :email, :string
field :settings, :map # "For future configuration"
field :metadata, :map # "For anything we might need"
field :flags, {:array, :string} # "For feature flags"
# None of these are used yet!
end
end
# GOOD - Add fields when needed
defmodule User do
schema "users" do
field :email, :string
# Add fields when requirements emerge
end
end
// YAGNI VIOLATION - Premature generalization
interface DataFetcher<T, P extends object = object> {
fetch(params: P): Promise<T>;
cache?(params: P): Promise<void>;
invalidate?(key: string): Promise<void>;
prefetch?(params: P[]): Promise<void>;
// We don't use cache, invalidate, or prefetch yet!
}
// GOOD - Start simple
interface DataFetcher<T> {
fetch(params: object): Promise<T>;
// Add methods when we need caching
}
// YAGNI VIOLATION - Configurable everything
interface ButtonProps {
onClick: () => void;
variant?: 'primary' | 'secondary' | 'tertiary' | 'ghost' | 'outline';
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
shape?: 'rounded' | 'square' | 'pill';
shadow?: 'none' | 'sm' | 'md' | 'lg';
animation?: 'fade' | 'slide' | 'bounce';
// Design only uses 2 variants and 1 size!
}
// GOOD - Implement what designs require
interface ButtonProps {
onClick: () => void;
variant?: 'primary' | 'secondary'; // Only what we use
// Add options when design requires them
}
# ASTONISHING - Updates AND returns different thing
def update_user(user, attrs) do
Repo.update!(User.changeset(user, attrs))
UserCache.invalidate(user.id) # Side effect!
:ok # Returns :ok instead of updated user!?
end
# EXPECTED - Clear behavior
def update_user(user, attrs) do
Repo.update(User.changeset(user, attrs))
# Caller handles cache invalidation explicitly
end
# ASTONISHING - Function name lies
def get_user(id) do
case Repo.get(User, id) do
nil ->
attrs = %{id: id, email: "#{id}@example.com"}
Repo.insert!(User.changeset(attrs)) # Created user in a getter!
user -> user
end
end
# EXPECTED - Name matches behavior
def get_or_create_user(id) do
case Repo.get(User, id) do
nil -> create_default_user(id)
user -> user
end
end
// ASTONISHING - Function mutates input
function processTask(gig: Task): Task {
gig.status = 'processed'; // Mutates input!
gig.processedAt = new Date();
return gig;
}
// EXPECTED - Pure function
function processTask(gig: Task): Task {
return {
...gig,
status: 'processed',
processedAt: new Date(),
};
}
// ASTONISHING - Inconsistent return types
async function getUser(id: string): Promise<User | null | undefined> {
// Returns null sometimes, undefined other times, no pattern
}
// EXPECTED - Consistent return
async function getUser(id: string): Promise<User | null> {
// Always null when not found
}
// ASTONISHING - Breaking conventions
interface Props {
onPress?: () => void; // React convention: onX
clickHandler?: () => void; // Different convention in same interface!
onTapGesture?: () => void; // Yet another name for same thing!
}
// EXPECTED - Consistent conventions
interface Props {
onPress?: () => void;
onLongPress?: () => void;
onDoublePress?: () => void;
}
{:ok, result} or {:error, reason} (consistent)onPress not onClick (platform convention)createTask, updateTask, deleteTasksolid-principles: Simple implementations of SOLID patternsboy-scout-rule: Simplify when improving codetest-driven-development: Simple code is easier to testelixir-code-quality-enforcer: Credo flags complexitytypescript-code-quality-enforcer: Linting enforces consistency"Simplicity is the ultimate sophistication." - Leonardo da Vinci
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.