Skip to content

feat: add design-review Claude Code skill - #884

Open
ravisuhag wants to merge 1 commit into
mainfrom
feat/design-review-skill
Open

feat: add design-review Claude Code skill#884
ravisuhag wants to merge 1 commit into
mainfrom
feat/design-review-skill

Conversation

@ravisuhag

@ravisuhag ravisuhag commented Aug 8, 2026

Copy link
Copy Markdown
Member

Summary

Adds a design-review skill to .claude/skills/ so anyone working on this repo with Claude Code can run a structured design review — of a PR, of their own branch before opening a PR, or of an existing module.

This is not a code-quality review (that's /review). It reviews the design:

  • Verify claims against code — every number in a description gets checked on the real branch; the gap between what's used internally and what's exported is usually where the design question lives.
  • Interrogate the API surface — who needs each export, what's the maintenance contract, and where's the cliff for the user who needs one more thing than the curated set provides.
  • The value question — what does this layer add over the underlying dependency, stated honestly.
  • Right-size the machinery — extra build steps, generated files, and custom tooling have to earn their keep at the actual scale of the problem.
  • Roadmap stress-test — a simplification that blocks a known future direction is not a simplification.
  • Deliverables per mode — a single evolving PR comment (reviewer), fixes plus PR-description material (author), or a ranked report (audit).

Test plan

  • Skill appears in Claude Code's skill list when working in this repo
  • /design-review on an open PR walks the phases and drafts a comment for approval

@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview Aug 8, 2026 6:46am

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a design-review skill definition. The skill specifies a nine-phase process for architecture, API, quantitative claim, machinery sizing, roadmap, ripple-effect, and outcome reviews. It supports reviewer, author, and audit modes. It defines required inputs, validation commands, API analysis questions, mode-specific deliverables, review-comment workflows, and memory-recording requirements.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding the design-review Claude Code skill.
Description check ✅ Passed The description directly explains the new design-review skill, its review modes, focus areas, and test plan.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

pnpm add https://pkg.pr.new/raystack/apsara/@raystack/apsara@884

commit: c8d0af6

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/skills/design-review/SKILL.md:
- Around line 72-74: In the design-review guidance text, update the phrase
“gitignored generated files” to “generated files ignored by Git,” preserving the
surrounding wording and meaning.
- Around line 33-34: Update the audit guidance in the design-review skill to
begin entry-point discovery from repository metadata and language-specific entry
points, supporting Python, Rust, Go, Java, and other module layouts. Make
package.json exports and barrel files conditional examples rather than universal
starting points, while preserving the existing README check where appropriate.
- Around line 29-32: Define a mode-specific TARGET_REF in Phase 1: use the
fetched pr-<n> ref for reviewer mode and resolve the repository’s default branch
for author mode instead of assuming main. Update all Phase 2 git show and git
grep commands to use TARGET_REF consistently, including the related lines 41–45.
- Around line 85-87: Update the typing compatibility guidance near the “narrow
types can widen” rule to qualify it for public types: explicitly state that
adding a member to a public union requires checking exhaustive consumers and
language-specific input/output variance rules, without implying that narrowing
can later occur.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ba794b4-dfe7-4573-9034-334fc2a36471

📥 Commits

Reviewing files that changed from the base of the PR and between d527aa4 and 85e8cb1.

📒 Files selected for processing (1)
  • .claude/skills/design-review/SKILL.md

Comment on lines +29 to +32
- Reviewer: `gh pr view <n> --json title,body,files,additions,deletions`
and `git fetch origin pull/<n>/head:pr-<n>`.
- Author: diff against the merge base
(`git diff $(git merge-base HEAD main)...HEAD`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Bind validation to the ref selected in Phase 1.

Reviewer mode fetches pr-<n>, while author mode assumes a branch named main. Phase 2 then refers to the “target ref” without defining it. A reviewer can inspect the wrong revision. Define TARGET_REF for each mode and use it in every git show and git grep command. Resolve the repository default branch instead of hardcoding main.

Also applies to: 41-45

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/design-review/SKILL.md around lines 29 - 32, Define a
mode-specific TARGET_REF in Phase 1: use the fetched pr-<n> ref for reviewer
mode and resolve the repository’s default branch for author mode instead of
assuming main. Update all Phase 2 git show and git grep commands to use
TARGET_REF consistently, including the related lines 41–45.

Comment on lines +33 to +34
- Audit: start from the entry points — `package.json` `exports`, the
barrel files, the README.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make audit entry-point discovery language-agnostic.

Audit mode hardcodes package.json and barrel files. This does not work reliably for Python, Rust, Go, or Java modules. Start with repository metadata and language-specific entry points when present. Treat package.json and barrel files as conditional examples.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/design-review/SKILL.md around lines 33 - 34, Update the audit
guidance in the design-review skill to begin entry-point discovery from
repository metadata and language-specific entry points, supporting Python, Rust,
Go, Java, and other module layouts. Make package.json exports and barrel files
conditional examples rather than universal starting points, while preserving the
existing README check where appropriate.

Comment thread .claude/skills/design-review/SKILL.md Outdated
Comment on lines +72 to +74
Does implementation complexity match problem size? Codegen, build
hooks, custom CI checks, and gitignored generated files earn their
keep at scale N; ask what N actually is here. A committed file that

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use standard wording for Git-ignored files.

Change gitignored generated files to generated files ignored by Git. This addresses the spelling warning and improves clarity.

🧰 Tools
🪛 LanguageTool

[grammar] ~73-~73: Ensure spelling is correct
Context: ...gen, build hooks, custom CI checks, and gitignored generated files earn their keep at scal...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/design-review/SKILL.md around lines 72 - 74, In the
design-review guidance text, update the phrase “gitignored generated files” to
“generated files ignored by Git,” preserving the surrounding wording and
meaning.

Source: Linters/SAST tools

Comment on lines +85 to +87
free" from the same mechanism. Typing rule: narrow types can widen
later without breaking; wide types can never narrow back. When unsure,
ship narrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== file context =="
sed -n '1,140p' .claude/skills/design-review/SKILL.md

echo
echo "== search for typing/compatibility rules in repo =="
rg -n "narrow|wide|compatibility|public type|type.*rule|union|switch|exhaustive" .claude/skills/design-review/SKILL.md .cl

Repository: raystack/apsara

Length of output: 6479


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== search public typing guidance repo-wide =="
rg -n -i "narrow types can widen|wide types can never|typing rule|type compatibility|unstable|compatibility|exhaustive|discriminated union" .

echo
echo "== repo files under .claude =="
find .claude -maxdepth 4 -type f 2>/dev/null | sort

Repository: raystack/apsara

Length of output: 4100


🌐 Web query:

TypeScript discriminant union exhaustiveness adding new union member breaks switch consumers

💡 Result:

It is intended behavior for TypeScript to flag an error when a new member is added to a union type that is used in a switch statement, provided you have implemented an exhaustive check pattern [1][2][3]. This is a powerful feature that turns potential runtime bugs—such as unhandled cases—into compile-time errors [2][4][5]. The standard approach to enforce this is to leverage the never type in the default clause of your switch statement [1][6][5]. Because TypeScript narrows the type of the union to only those members not yet handled in the preceding case blocks, if you have covered every member, the type in the default block will be never [2][3][4]. There are two primary ways to implement this: 1. Exhaustive Assignment: Assign the switch value to a variable typed as never [7][2][5]. typescript function handle(u: MyUnion) { switch (u.kind) { case 'A': /* ... */ break; case 'B': /* ... */ break; default: const _exhaustiveCheck: never = u; // Error here if new union member is not handled return _exhaustiveCheck; } } 2. Exhaustive Assertion Function: Pass the switch value to a function that accepts only never [1][6][5]. typescript function assertNever(x: never): never { throw new Error("Unexpected object: " + x); } function handle(u: MyUnion) { switch (u.kind) { case 'A': /* ... */ break; case 'B': /* ... */ break; default: return assertNever(u); // Error here if new union member is not handled } } When you add a new member to the union, TypeScript's control flow analysis will no longer resolve the type in the default case to never (it will include the new member) [1][3]. Since the new member is not assignable to never, the compiler will immediately highlight the default clause as an error, identifying the missing case [1][2][8]. Additionally, you can use the @typescript-eslint/switch-exhaustiveness-check rule to enforce this pattern via linting [6][9].

Citations:


🌐 Web query:

TypeScript return position contravariance function parameter input position variant

💡 Result:

In TypeScript, function types exhibit different variance behaviors based on the position of the type parameters [1][2]. Function parameter (input) positions are contravariant, while return type (output) positions are covariant [3][2]. 1. Contravariance in Input Positions Function parameters are contravariant, meaning a function type (A) => void is assignable to (B) => void if B is a subtype of A (or conversely, if the parameter type A is a supertype of B) [4][5][2]. This is because a function that accepts a broader type (e.g., Animal) is safer than one that requires a narrower type (e.g., Dog). If you expect a function that can handle a Dog, you can safely provide a function that handles any Animal, as it will know how to process a Dog if one is passed to it [5][2]. 2. Covariance in Return Positions Return types are covariant, meaning a function type => B is assignable to => A if B is a subtype of A [2]. This is intuitive: if a consumer expects a function to return an Animal, providing a function that returns a Dog is safe because a Dog is an Animal [2]. 3. Strict Function Types Historically, TypeScript treated function parameters bivariantly for flexibility, but the introduction of the --strictFunctionTypes compiler flag (now enabled by default in --strict mode) enforces strict contravariance for function parameters [6][7]. Methods and constructors are a notable exception to this rule and are still checked bivariantly to ensure generic classes and interfaces, like Array, remain usable [6][7]. 4. Variance Annotations Since TypeScript 4.7, developers can use optional variance annotations (in, out) on generic type parameters to explicitly control or document variance [8][9]. - out T: Indicates the type parameter is covariant (used in output positions) [8][9]. - in T: Indicates the type parameter is contravariant (used in input positions) [8][9]. - in out T: Indicates the type parameter is invariant [8]. These annotations do not change structural behavior but can assist the compiler in checking and verifying variance in complex generic types [10][9].

Citations:


🌐 Web query:

TypeScript API type widening narrow widening breaking change public union member

💡 Result:

In TypeScript, concerns about "widening," "narrowing," and "public" members in the context of union types often relate to how the compiler maintains or loses type safety during exported destructuring or object manipulation. A notable issue involving exported discriminated unions was the loss of narrowed types when variables were destructured and exported [1]. Specifically, when variables were extracted from a discriminated union object and exported, the type information—which should have been narrowed based on the discriminant—was lost, causing the variables to revert to their un-narrowed, wider union types [1]. This was addressed and resolved in recent versions of TypeScript (e.g., via PR #59673) to ensure that exported destructured variables preserve their narrowed types [2][1]. Regarding the broader context of breaking changes and public API surface, tools that perform automated semantic versioning checks often categorize these behaviors differently [3][4]: 1. Narrowing of a return type or parameter is generally classified as a breaking change because it may restrict the inputs or outputs that consumers are expecting to handle [5][3][4]. 2. Widening of a return type or parameter (e.g., adding a new member to a union) is typically classified as a non-breaking (additive) change, as it allows existing consumers to continue working while accepting a broader range of values [5][3][4]. 3. The visibility of members in union types is also a historical area of interest; for example, it has been noted that union types may allow public access to members that are private in one of the constituent types [6]. This behavior is a fundamental aspect of how TypeScript resolves property access across diverse types in a union [6]. Finally, "widening" contexts—such as let variables, function returns, or object literals—can cause literal types to revert to their primitive supertypes (e.g., 'A' | 'B' widening to string) [7]. While this is generally by design, it can sometimes manifest as unexpected behavior in generic type inference [8][7].

Citations:


🌐 Web query:

TypeScript TypeScript API surface adding union member breaking type narrowing widening API compatibility

💡 Result:

Adding a new member to a union type in TypeScript is generally considered a breaking change when that union is used in a way that relies on exhaustiveness checking or specific narrowing logic [1][2]. While adding a new property to an object type is often non-breaking, modifying a union type changes the set of possible states a value can inhabit [1][3]. Breakage typically occurs in the following areas: Exhaustiveness Checking: If you use a switch statement or other narrowing pattern to handle all members of a union (often using a 'never' type in a default branch to ensure completeness), adding a new union member will cause the 'never' check to fail because the new member is unhandled [1]. This is a common and intentional safety feature to force developers to update their code when the API's contract changes [1]. Narrowing Logic: TypeScript's control flow analysis relies on narrowing the union based on discriminant properties or other type guards [1]. Adding a new member can alter how TypeScript performs this narrowing, sometimes leading to unexpected behavior if the new member overlaps with existing ones or if the narrowing logic is not exhaustive [4][5]. Type Inference and Widening: In generic contexts, adding members to a union can impact type inference [6][7]. TypeScript sometimes performs "widening" (e.g., converting a literal type to its primitive supertype) [8]. Changes to union members can affect the candidate set for type inference, potentially leading to a more general (widened) type being inferred than was previously the case, which might cause downstream type errors [6][7][8]. API Compatibility: From the perspective of library authors, changing a union type is considered a breaking change because it forces consuming code to handle the new member [2]. Strategies such as using interface merging, module augmentation, or providing optional properties are sometimes used to manage these changes without forcing an immediate break for all users [9]. For more information, see the official TypeScript documentation on Narrowing [1] and guidelines on semantic versioning for TypeScript types [2][3][10].

Citations:


Qualify the typing compatibility rule for public types.

Do not state that narrowing can happen back. Add a concrete exception: widening a public union by adding a member must be checked against exhaustive consumers and language-specific input/output variance rules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/design-review/SKILL.md around lines 85 - 87, Update the
typing compatibility guidance near the “narrow types can widen” rule to qualify
it for public types: explicitly state that adding a member to a public union
requires checking exhaustive consumers and language-specific input/output
variance rules, without implying that narrowing can later occur.

A Claude Code skill for reviewing designs rather than code quality:
API surface, maintenance contracts, whether the machinery fits the
size of the problem. Works in three modes — reviewing a PR, self-
reviewing a branch before opening a PR, and auditing an existing
module.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant