Help us improve
Share bugs, ideas, or general feedback.
From clinicaltrialsgov-mcp-server
Post-session code review that analyzes git diff to simplify and consolidate changed code, modernize syntax, and catch efficiency issues. Use after a working session or when asked to clean up or reduce slop.
npx claudepluginhub cyanheads/cyanheads --plugin clinicaltrialsgov-mcp-serverHow this skill is triggered — by the user, by Claude, or both
Slash command
/clinicaltrialsgov-mcp-server:code-simplifierThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Post-session cleanup pass. Reviews what changed, understands how it fits the existing codebase, and makes targeted improvements — modernizing syntax, removing unnecessary complexity, consolidating duplicated logic, catching efficiency issues. Prioritizes codebase cohesion over local perfection.
Post-session code review that analyzes git diff to simplify and consolidate changed code, modernize syntax, and catch efficiency issues. Use after a working session or when asked to clean up or reduce slop.
Reviews git diff after a working session to simplify, consolidate, and modernize changed code, aligning it with the existing codebase. Activates on cleanup/simplify requests.
Reviews a diff for code reuse, quality, and clarity issues, then optionally applies high-confidence, behavior-preserving fixes using parallel sub-agents.
Share bugs, ideas, or general feedback.
Post-session cleanup pass. Reviews what changed, understands how it fits the existing codebase, and makes targeted improvements — modernizing syntax, removing unnecessary complexity, consolidating duplicated logic, catching efficiency issues. Prioritizes codebase cohesion over local perfection.
Every change must earn its keep. A simplification that doesn't meaningfully improve clarity, correctness, or cohesion is noise. Don't refactor for refactoring's sake. Don't create new files, abstractions, or utilities unless they solve a demonstrated problem. If the existing code works and is readable, leave it alone. The goal is a cohesive codebase, not a pristine one.
Run git diff (or git diff HEAD if changes are staged) to see what changed. If there are no git changes, review the most recently modified files from the current session.
Don't review changes in isolation. Before any modifications:
src/utils/ for project utilities, src/errors/ for error handling, and node_modules/@cyanheads/mcp-ts-core/ for framework exports.Evaluate the changes across these dimensions. Not every dimension applies to every diff — skip what's irrelevant.
import from '@cyanheads/mcp-ts-core/utils' over hand-rolled equivalents — pagination helpers, schema builders, retry primitives, and OTel attribute constants are framework-provided.ATTR_* constants in @cyanheads/mcp-ts-core/utils should replace raw OTel attribute keys.Promise.all / Promise.allSettled.McpError, validationError, notFound, httpErrorFromResponse) over raw throw new Error(). Tool handlers should throw — the framework catches, classifies, and instruments.InvalidParams only for malformed JSON-RPC params shape. ValidationError for domain validation. NotFound for missing entities. Don't conflate them.ctx.log, ctx.state, ctx.elicit — don't reach for global loggers or request-scoped storage directly. The ctx pattern carries tenant scope and OTel context..describe(). Zod 4 requires z.record(z.string(), z.string()) not z.record(z.string()). Use .optional() rather than .nullish() unless null is semantically distinct from absent.readOnlyHint, idempotentHint, openWorldHint should reflect reality. A read-only tool with readOnlyHint: false gives clients the wrong picture.exactOptionalPropertyTypes boundaries — If a downstream type insists on the field being present-or-not-present (not present-as-undefined), use a mapped widening type at the boundary. The pattern is documented in the framework.format() ↔ structuredContent parity — Different MCP clients forward different surfaces. Tests should assert both surfaces carry equivalent data.When done, briefly summarize what was fixed or confirm the code was already clean.
The tables below cover TypeScript and Python. For other languages, apply analogous principles: prefer modern idioms, reduce nesting, eliminate dead code, follow project conventions.
| Before | After | Why |
|---|---|---|
const x: Foo = { ... } as Foo | const x = { ... } satisfies Foo | Type-checked without assertion |
let resource = acquire(); try { ... } finally { release(resource) } | using resource = acquire() | Explicit resource disposal (TS 5.2+) |
if (x !== null && x !== undefined) | if (x != null) | Idiomatic null/undefined check |
arr.filter(x => x !== null) as T[] | arr.filter((x): x is T => x != null) | Type-safe filtering, no cast |
export { foo } from './foo/index.js' | Direct imports at call sites | Avoid barrel re-exports inside the package; barrel exports are for public APIs only |
async function f() { const a = await x(); const b = await y(); } | const [a, b] = await Promise.all([x(), y()]) | Parallel when independent |
obj.x !== undefined ? obj.x : fallback | obj.x ?? fallback | Nullish coalescing |
if (a) { if (b) { if (c) { ... } } } | Guard clauses with early returns | Reduce nesting |
try { risky() } catch (e: any) { ... } | try { risky() } catch (e: unknown) { ... } | Type-safe error handling |
enum Status { A, B, C } | const Status = { A: 'A', B: 'B', C: 'C' } as const | Prefer const objects for numeric enums; string enums are acceptable |
function f(a: string, b: string, c: string, d?: string) | function f(opts: FnOptions) | Options object when >3 params |
throw new Error('Bad input') (in a tool handler) | throw validationError('Bad input', { field: 'x' }) | Use framework error factories so the framework can classify and instrument |
const ATTR_KEY = 'mcp.tool.name' | import { ATTR_MCP_TOOL_NAME } from '@cyanheads/mcp-ts-core/utils' | Use framework attribute constants |
| Before | After | Why |
|---|---|---|
Optional[str] | str | None | Modern union syntax (3.10+) |
List[str], Dict[str, int] | list[str], dict[str, int] | Built-in generics (3.9+) |
if x == 0: ... elif x == 1: ... elif x == 2: ... | match x: case 0: ... case 1: ... | Structural pattern matching (3.10+) |
class Config: def __init__(self, a, b, c): self.a = a ... | @dataclass class Config: a: str; b: int; c: float | Less boilerplate, built-in eq/repr |
results = []; for item in items: results.append(transform(item)) | results = [transform(item) for item in items] | Idiomatic comprehension |
f = open('x'); try: ... finally: f.close() | with open('x') as f: ... | Context manager for resources |
line = f.readline(); while line: process(line); line = f.readline() | while (line := f.readline()): process(line) | Walrus operator where it reduces duplication |
"Hello " + name + "!" | f"Hello {name}!" | f-string over concatenation |
except Exception as e: pass | except SpecificError as e: log(e) | Catch specific, never bare except/pass |
from module import * | from module import specific_name | Explicit imports only |
TypeAlias = Union[A, B, C] | type ABC = A | B | C | type statement (3.12+) |
Sequential await for independent I/O | await asyncio.gather(a(), b()) | Parallel when independent |
Leave code alone when:
data to result isn't worth the churn.as cast or # type: ignore exists because of a genuine type system limitation — verify before removing.