Help us improve
Share bugs, ideas, or general feedback.
From pedantic-coder
Enforces boolean naming rules: prefixes like is/has/can/should, positive phrasing, ensuring names read as yes/no questions for variables, functions, flags, and toggles.
npx claudepluginhub oborchers/fractional-cto --plugin pedantic-coderHow this skill is triggered — by the user, by Claude, or both
Slash command
/pedantic-coder:boolean-namingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Every boolean variable, field, parameter, and return value must read as a question that has exactly two answers: yes or no. If you read the name out loud and it does not form a grammatical yes/no question, the name is wrong. Not "could be better" — wrong.
Choosing meaningful, pronounceable names that reveal intent for functions, variables, classes, and modules.
Enforces precise naming for variables, functions, classes, files, and identifiers. Bans vague names like data/temp/result/info/handle/manager; promotes semantic accuracy and domain-specific terms via specificity ladder.
Suggests improved names for variables, functions, classes, files, DB tables, and API endpoints using language-specific conventions like camelCase or snake_case.
Share bugs, ideas, or general feedback.
Every boolean variable, field, parameter, and return value must read as a question that has exactly two answers: yes or no. If you read the name out loud and it does not form a grammatical yes/no question, the name is wrong. Not "could be better" — wrong.
active is not a question. isActive is. permission is not a question. hasPermission is. retry is not a question. shouldRetry is. This is the entire rule. Everything below is application of it.
Every boolean gets a prefix. No exceptions.
| Prefix | Meaning | Examples |
|---|---|---|
is | State of being — the subject currently exhibits this quality | isActive, isVisible, isAuthenticated, isEmpty, isValid |
has | Possession or existence — the subject owns or contains something | hasPermission, hasChildren, hasError, hasSubscription |
can | Capability or permission — the subject is allowed or able to do this | canEdit, canDelete, canAccessAdmin, canRetry |
should | Recommendation or conditional — logic recommends this action | shouldRetry, shouldCache, shouldNotify, shouldRedirect |
was / did | Past tense — something already happened | wasProcessed, didSucceed, wasModified, didExpire |
The prefix is not optional. A boolean without a prefix forces the reader to guess whether enabled is a boolean, a string, a function, or an adjective modifying something else. The prefix eliminates all ambiguity in a single glance.
Name booleans in the positive. Always. The logic can negate; the name must not.
BAD — negative names create double negatives:
isNotReady → if (!isNotReady) — unreadable
isDisabled → if (!isDisabled) — "not disabled" means "enabled"
isInvalid → if (!isInvalid) — triple cognitive load
hasNoPermission → if (!hasNoPermission) — brain melts
isNotFound → if (isNotFound) — why not just check the positive?
GOOD — positive names, inverted in logic when needed:
isReady → if (!isReady) — clear: "not ready"
isEnabled → if (!isEnabled) — clear: "not enabled"
isValid → if (!isValid) — clear: "not valid"
hasPermission → if (!hasPermission) — clear: "no permission"
isFound → if (!isFound) — clear: "not found"
The reason is mechanical: if (!isDisabled) requires the reader to evaluate a negation of a negation. if (isEnabled) or if (!isEnabled) each require evaluating one thing. This is not pedantry — studies on code comprehension consistently show negative boolean names increase error rates in conditionals.
Functions that return booleans follow the same prefix rules. The function name IS the question; the return value IS the answer.
# GOOD — the function name is the question
def is_even(number: int) -> bool: ...
def has_access(user: User, resource: Resource) -> bool: ...
def can_proceed(workflow: Workflow) -> bool: ...
def should_retry(error: Exception, attempt: int) -> bool: ...
# BAD — the function name is not a question
def check_even(number: int) -> bool: ... # "check" is a verb, not a question
def validate_access(user, resource) -> bool: ... # "validate" implies side effects
def get_status() -> bool: ... # "get" implies returning data, not answering
def verify(token: str) -> bool: ... # verify what? no subject, no question
// GOOD
function isEven(n: number): boolean { ... }
function hasAccess(user: User, resource: Resource): boolean { ... }
function canProceed(workflow: Workflow): boolean { ... }
// BAD
function checkEven(n: number): boolean { ... }
function getAccess(user: User): boolean { ... }
function processValid(data: unknown): boolean { ... }
// GOOD — Go convention: Is, Has, Can prefix on exported functions
func IsEven(n int) bool { ... }
func HasAccess(user *User, resource *Resource) bool { ... }
func CanProceed(wf *Workflow) bool { ... }
// BAD
func CheckEven(n int) bool { ... }
func GetStatus() bool { ... }
func Validate(token string) bool { ... }
The prefix always comes first. The prefix IS the first word. Not the second, not somewhere in the middle.
GOOD:
isUserAuthenticated
hasValidSubscription
canEditDocument
shouldRefreshToken
wasPaymentProcessed
BAD:
authenticatedUser → is this a User object? a string? a boolean?
userIsAuthenticated → prefix buried after the subject
validSubscription → no prefix at all
documentCanEdit → inverted order
paymentWasProcessed → prefix is not first
These names are never acceptable for booleans:
| Banned Name | Why | Fix |
|---|---|---|
flag | Says nothing about what it controls | Name the specific condition: isDebugMode, shouldLogVerbose |
status | Is it a boolean? A string? An enum? An object? | Name the specific state: isActive, isPending, isApproved |
toggle | Describes the action, not the state | Name the state being toggled: isExpanded, isVisible |
check | Describes the action, not the result | Name what is being checked: isValid, hasErrors |
state | Maximally vague | Name the specific state: isLoading, isConnected |
active / enabled / visible | Missing prefix — ambiguous type | isActive, isEnabled, isVisible |
b, f, ok | Single-letter booleans | Spell it out. Even in a 3-line scope. |
The only exception for single-letter booleans: loop variables in tiny, obvious scopes where the boolean is consumed on the next line. Even then, prefer a name.
| Context | BAD | GOOD | Why |
|---|---|---|---|
| User login state | loggedIn | isLoggedIn | Missing prefix |
| Feature toggle | darkMode | isDarkModeEnabled | Ambiguous type without prefix |
| Permission check | admin | isAdmin or hasAdminRole | admin could be a string, object, or ID |
| Error state | error | hasError | error is typically the error object itself |
| Loading state | loading | isLoading | Missing prefix |
| Empty collection | empty | isEmpty | Missing prefix |
| Negated state | isNotValid | isValid (negate in logic) | Negative name |
| Past event | processed | wasProcessed | Missing temporal prefix |
| Config flag | flag | isFeatureEnabled | flag means nothing |
| Function | validate() | isValid() | Verb implies action, not question |
Working implementations in examples/:
examples/boolean-patterns.md — Multi-language examples (Python, TypeScript, Go) showing bad-to-good boolean naming transformations for variables, function predicates, class properties, and function parameters.When naming or reviewing boolean identifiers:
is, has, can, should, was, or diduserIsActive, only isUserActiveisNot, isUn, isIn, hasNo prefixesif (!isValid) not if (isInvalid)flag, status, toggle, check, state, or a bare adjectivesetVisible(isVisible: true)isActive, no other file uses active for the same concept