code review
npx skills add https://github.com/adobe/helix-website --skill Code Review
Skill 文档
Code Review
Review code for AEM Edge Delivery Services (EDS) projects following established coding standards, performance requirements, and best practices.
When to Use This Skill
This skill supports two modes of operation:
Mode 1: Self-Review (End of Development)
Use this mode when you’ve finished writing code and want to review it before committing or opening a PR. This is the recommended workflow integration point.
When to invoke:
- After completing implementation in the content-driven-development workflow (between Step 5 and Step 6)
- Before running
git addandgit commit - When you want to catch issues early, before they reach PR review
How to invoke:
- Automatically: CDD workflow invokes this skill after implementation
- Manually:
/code-review(reviews uncommitted changes in working directory)
What it does:
- Reviews all modified/new files in working directory
- Checks code quality, patterns, and best practices
- Validates against EDS standards
- Identifies issues to fix before committing
- Captures visual screenshots for validation
Mode 2: PR Review
Use this mode to review an existing pull request (your own or someone else’s).
When to invoke:
- Reviewing a PR before merge
- Automated review via GitHub Actions workflow
- Manual review of a specific PR
How to invoke:
- Manually:
/code-review <PR-number>or/code-review <PR-URL> - Automated: Via GitHub workflow on
pull_requestevent
What it does:
- Fetches PR diff and changed files
- Validates PR structure (preview URLs, description)
- Reviews code quality
- Posts review comment with findings and screenshots
- Provides actionable fixes via GitHub suggestions or commits
- Explains reasoning for each fix with references to review feedback
Review Workflow
Step 1: Identify Review Mode and Gather Context
For Self-Review (no PR number provided):
# See what files have been modified
git status
# See the actual changes
git diff
# For staged changes
git diff --staged
Understand the scope:
- What files were modified?
- What type of change is this? (new block, bug fix, feature, styling, refactor)
- What is the test content URL? (from CDD workflow)
For PR Review (PR number provided):
# Get PR details
gh pr view <PR-number> --json title,body,author,baseRefName,headRefName,files,additions,deletions
# Get changed files
gh pr diff <PR-number>
# Get PR comments and reviews
gh api repos/{owner}/{repo}/pulls/<PR-number>/comments
gh api repos/{owner}/{repo}/pulls/<PR-number>/reviews
Understand the scope:
- What type of change is this? (new block, bug fix, feature, styling, refactor)
- What files are modified?
- Is there a related GitHub issue?
- Are there test/preview URLs provided?
Step 2: Validate Structure (PR Review Mode Only)
Skip this step for Self-Review mode.
Required elements for PRs (MUST HAVE):
| Element | Requirement | Check |
|---|---|---|
| Preview URLs | Before/After URLs showing the change | Required |
| Description | Clear explanation of what changed and why | Required |
| Scope alignment | Changes match PR title and description | Required |
| Issue reference | Link to GitHub issue (if applicable) | Recommended |
Preview URL format:
- Before:
https://main--{repo}--{owner}.aem.page/{path} - After:
https://{branch}--{repo}--{owner}.aem.page/{path}
Flag if missing:
- Missing preview URLs (blocks automated PSI checks)
- Vague or missing description
- Scope creep (changes unrelated to stated purpose)
- Missing issue reference for bug fixes
Step 3: Code Quality Review
3.1 JavaScript Review
Linting & Style:
- Code passes ESLint (airbnb-base configuration)
- No
eslint-disablecomments without justification - No global
eslint-disabledirectives - ES6+ features used appropriately
-
.jsextensions included in imports
Architecture:
- No frameworks in critical rendering path (LCP/TBT impact)
- Third-party libraries loaded via
loadScript()in blocks, nothead.html - Consider
IntersectionObserverfor heavy libraries -
aem.jsis NOT modified (submit upstream PRs for improvements) - No build steps introduced without team consensus
Code Patterns:
- Existing DOM elements re-used, not recreated
- Block selectors scoped appropriately
- No hardcoded values that should be configurable
- Console statements cleaned up (no debug logs)
- Proper error handling where needed
Common Issues to Flag:
// BAD: CSS in JavaScript
element.style.backgroundColor = 'blue';
// GOOD: Use CSS classes
element.classList.add('highlighted');
// BAD: Hardcoded configuration
const temperature = 0.7;
// GOOD: Use config or constants
const { temperature } = CONFIG;
// BAD: Global eslint-disable
/* eslint-disable */
// GOOD: Specific, justified disables
/* eslint-disable-next-line no-console -- intentional debug output */
3.2 CSS Review
Linting & Style:
- Code passes Stylelint (standard configuration)
- No
!importantunless absolutely necessary (with justification) - Property order maintained (don’t reorder in functional PRs)
Scoping & Selectors:
- All selectors scoped to block:
.{block-name} .selectorormain .{block-name} - Private classes/variables prefixed with block name
- Simple, readable selectors (add classes rather than complex selectors)
- ARIA attributes used for styling when appropriate (
[aria-expanded="true"])
Responsive Design:
- Mobile-first approach (base styles for mobile, media queries for larger)
- Standard breakpoints used:
600px,900px,1200px(allmin-width) - No mixing of
min-widthandmax-widthqueries - Layout works across all viewports
Frameworks & Preprocessors:
- No CSS preprocessors (Sass, Less, PostCSS) without team consensus
- No CSS frameworks (Tailwind, etc.) without team consensus
- Native CSS features used (supported by evergreen browsers)
Common Issues to Flag:
/* BAD: Unscoped selector */
.title { color: red; }
/* GOOD: Scoped to block */
main .my-block .title { color: red; }
/* BAD: !important abuse */
.button { color: white !important; }
/* GOOD: Increase specificity instead */
main .my-block .button { color: white; }
/* BAD: Mixed breakpoint directions */
@media (max-width: 600px) { }
@media (min-width: 900px) { }
/* GOOD: Consistent mobile-first */
@media (min-width: 600px) { }
@media (min-width: 900px) { }
/* BAD: CSS in JS patterns */
element.innerHTML = '<style>.foo { color: red; }</style>';
/* GOOD: Use external CSS files */
3.3 HTML Review
- Semantic HTML5 elements used appropriately
- Proper heading hierarchy maintained
- Accessibility attributes present (ARIA labels, alt text)
- No inline styles or scripts in
head.html - Marketing tech NOT in
<head>(performance impact)
Step 4: Performance Review
Critical Requirements:
- Lighthouse scores green (ideally 100) for mobile AND desktop
- No third-party libraries in critical path (
head.html) - No layout shifts introduced (CLS impact)
- Images optimized and lazy-loaded appropriately
Performance Checklist:
- Heavy operations use
IntersectionObserveror delayed loading - No synchronous operations blocking render
- Bundle size reasonable (no minification unless measurable Lighthouse gain)
- Fonts loaded efficiently
Preview URL Verification: If preview URLs provided, check:
- PageSpeed Insights scores
- Core Web Vitals (LCP, CLS, INP)
- Mobile and desktop performance
Step 5: Visual Validation with Screenshots
Purpose: Capture screenshots of the preview URL to validate visual appearance. For self-review, this confirms your changes look correct before committing. For PR review, this provides visual evidence in the review comment.
When to capture screenshots:
- Always capture at least one screenshot of the primary changed page/component
- For responsive changes, capture mobile (375px), tablet (768px), and desktop (1200px)
- For visual changes (styling, layout), capture before AND after for comparison
- For block changes, capture the specific block area
How to capture screenshots:
Option 1: Playwright (Recommended for automation)
// capture-screenshots.js
import { chromium } from 'playwright';
async function captureScreenshots(afterUrl, outputDir = './screenshots') {
const browser = await chromium.launch();
const page = await browser.newPage();
// Desktop screenshot
await page.setViewportSize({ width: 1200, height: 800 });
await page.goto(afterUrl, { waitUntil: 'networkidle' });
await page.waitForTimeout(1000); // Wait for animations
await page.screenshot({
path: `${outputDir}/desktop.png`,
fullPage: true
});
// Tablet screenshot
await page.setViewportSize({ width: 768, height: 1024 });
await page.screenshot({
path: `${outputDir}/tablet.png`,
fullPage: true
});
// Mobile screenshot
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({
path: `${outputDir}/mobile.png`,
fullPage: true
});
// Optional: Capture specific block/element
const block = page.locator('.my-block');
if (await block.count() > 0) {
await block.screenshot({ path: `${outputDir}/block.png` });
}
await browser.close();
return {
desktop: `${outputDir}/desktop.png`,
tablet: `${outputDir}/tablet.png`,
mobile: `${outputDir}/mobile.png`
};
}
// Usage
captureScreenshots('https://branch--repo--owner.aem.page/path');
Option 2: Using MCP Browser Tools
If you have MCP browser or Playwright tools available:
- Navigate to the After preview URL
- Take screenshots at different viewport sizes
- Optionally take element-specific screenshots of changed blocks
Option 3: Manual capture with guidance
Instruct the reviewer or PR author to:
- Open the After preview URL
- Use browser DevTools to set viewport sizes
- Take screenshots and attach to PR
Uploading screenshots to GitHub:
# Upload screenshot as PR comment with image
# First, upload to a hosting service or use GitHub's image upload
# Option A: Embed in PR comment (drag & drop in GitHub UI)
gh pr comment <PR-number> --body "## Visual Preview
### Desktop (1200px)

### Mobile (375px)

"
# Option B: Use GitHub's attachment API (for automation)
# Screenshots can be uploaded as part of the comment body
Screenshot checklist:
- Primary page/component captured at desktop width
- Mobile viewport captured (if responsive changes)
- Specific block/component captured (if block changes)
- Before/After comparison (if significant visual changes)
- No sensitive data visible in screenshots
- Screenshots uploaded and embedded in PR comment
Visual issues to look for:
- Layout breaks or misalignment
- Text overflow or truncation
- Image sizing or aspect ratio issues
- Color/contrast problems (especially in dark mode)
- Missing or broken icons
- Responsive layout issues at breakpoints
- Unexpected visual differences from main branch
Step 6: Content & Authoring Review
Content Model (if applicable):
- Content structure author-friendly
- Backward compatibility maintained with existing content
- No breaking changes requiring content migration
- New content features only available after preview/publish
Static Resources:
- No binaries/static assets committed (unless code-referenced)
- User-facing strings sourced from content (placeholders, spreadsheets)
- No hardcoded literals that should be translatable
Step 7: Security Review
- No sensitive data committed (API keys, passwords, secrets)
- No XSS vulnerabilities (unsafe innerHTML, unsanitized user input)
- No SQL injection or command injection vectors
- CSP headers appropriate for tool pages
- External links have
rel="noopener noreferrer"
Step 8: Generate Review Summary
Output depends on the review mode:
For Self-Review Mode (End of Development)
Report findings directly to continue the development workflow:
## Code Review Summary
### Files Reviewed
- `blocks/my-block/my-block.js` (new)
- `blocks/my-block/my-block.css` (new)
### Visual Validation

â
Layout renders correctly across viewports
â
No console errors
â
Responsive behavior verified
### Issues Found
#### Must Fix Before Committing
- [ ] `blocks/my-block/my-block.js:45` - Remove console.log debug statement
- [ ] `blocks/my-block/my-block.css:12` - Selector `.title` needs block scoping
#### Recommendations
- [ ] Consider using `loadScript()` for the external library
### Ready to Commit?
- [ ] All "Must Fix" issues resolved
- [ ] Linting passes: `npm run lint`
- [ ] Visual validation complete
After self-review: Fix any issues found, then proceed with committing and opening a PR.
For PR Review Mode
Structure the review comment for GitHub:
## PR Review Summary
### Overview
[Brief summary of the PR and its purpose]
### Preview URLs Validated
- [ ] Before: [URL]
- [ ] After: [URL]
### Visual Preview
#### Desktop (1200px)

#### Mobile (375px)

<details>
<summary>Additional Screenshots</summary>
#### Tablet (768px)

#### Block Detail

</details>
### Visual Assessment
- [ ] Layout renders correctly across viewports
- [ ] No visual regressions from main branch
- [ ] Colors and typography consistent
- [ ] Images and icons display properly
### Checklist Results
#### Must Fix (Blocking)
- [ ] [Critical issue with file:line reference]
#### Should Fix (High Priority)
- [ ] [Important issue with file:line reference]
#### Consider (Suggestions)
- [ ] [Nice-to-have improvement]
### Detailed Findings
#### [Category: e.g., JavaScript, CSS, Performance]
**File:** `path/to/file.js:123`
**Issue:** [Description of the issue]
**Suggestion:** [How to fix it]
Step 9: Provide Actionable Fixes (PR Review Mode Only)
Skip this step for Self-Review mode – in self-review, you fix issues directly in your working directory.
After identifying issues in a PR review, provide actionable fixes to make it easier for the PR author to address them. The goal is to provide one-click fixes whenever possible.
Quick Reference
PRIMARY METHOD: GitHub Suggestions (use for ~70-80% of fixable issues)
- One-click acceptance by PR author
- Proper git attribution
- Works for changes < 20 lines
- Native GitHub UI integration
SECONDARY: Guidance Comments (~20-30% of issues)
- For subjective or architectural issues
- When multiple approaches exist
- “Consider” level suggestions
RARE: Fix Commits (avoid unless necessary)
- Only when suggestions won’t work
- Multi-file complex refactors
- Changes requiring extensive testing
Decision Tree: When to Use Which Approach
| Approach | When to Use | Examples |
|---|---|---|
| GitHub Suggestions (PRIMARY) | Any change that can be expressed as a code replacement | Remove console.log, fix typos, add comments, refactor selectors, update functions, add error handling |
| Fix Commits (SECONDARY) | Changes that need testing, span many files, or are too large for suggestions | Complex multi-file refactors, security fixes requiring validation, changes >20 lines |
| Guidance Only (FALLBACK) | Architectural changes, subjective improvements, or when multiple approaches exist | “Consider using IntersectionObserver”, design pattern suggestions, performance optimizations |
IMPORTANT: Always prefer GitHub Suggestions when possible – they provide the best user experience with one-click acceptance and proper git attribution.
Approach 1: GitHub Inline Suggestions (PRIMARY APPROACH – Recommended)
Use GitHub’s native suggestion feature for most fixes. This provides the best user experience with one-click acceptance and proper git attribution.
When to use:
- â ANY change that can be expressed as a line replacement
- â Single-line to multi-line changes (up to ~20 lines works well)
- â Clear, actionable fixes with known solutions
- â Independent changes that can be applied separately
- â Changes that don’t require extensive testing before commit
When NOT to use:
- â Changes requiring testing/validation before commit
- â Very large changes (>20 lines become unwieldy in GitHub UI)
- â Changes spanning many files (better as fix commits)
- â Subjective/architectural suggestions with multiple valid approaches
Benefits:
- ð One-click acceptance by PR author
- â Proper co-author attribution in git history
- ð¯ Batch multiple suggestions into single commit
- ð± Works in GitHub mobile app
- â¡ Zero copy/paste errors
- ð Clear before/after diff in GitHub UI
How to create suggestions:
GitHub suggestions are created using the Pull Request Reviews API with a special markdown syntax in the comment body:
```suggestion
// The corrected code here
```
Complete workflow with examples:
# Step 1: Get PR information
PR_NUMBER=196
OWNER="adobe"
REPO="helix-tools-website"
# Get the current HEAD commit SHA (required for review API)
COMMIT_SHA=$(gh api repos/$OWNER/$REPO/pulls/$PR_NUMBER --jq '.head.sha')
# Step 2: Analyze the diff to find line positions
# IMPORTANT: Use 'position' in the diff, NOT 'line' in the original file
# Position is the line number in the unified diff output starting from the first diff hunk
# Get the diff to understand positions
gh pr diff $PR_NUMBER --repo $OWNER/$REPO > /tmp/pr-$PR_NUMBER.diff
# Step 3: Create review JSON with suggestions
# Each comment needs:
# - path: file path relative to repo root
# - position: line number IN THE DIFF (not in the file!)
# - body: description + ```suggestion block
cat > /tmp/review-suggestions.json <<JSON
{
"commit_id": "$COMMIT_SHA",
"event": "COMMENT",
"comments": [
{
"path": "tools/page-status/diff.js",
"position": 58,
"body": "**Fix: Add XSS Safety Documentation** (BLOCKING)\\n\\nAdd a comment to document that this HTML injection is safe:\\n\\n\`\`\`suggestion\\n const previewBodyHtml = previewDom.querySelector('body').innerHTML;\\n\\n // XSS Safe: previewBodyHtml is sanitized by mdToDocDom from trusted admin API\\n const newPageHtml = \\\`\\n\`\`\`\\n\\nThis addresses the security concern by making it clear that XSS has been considered."
},
{
"path": "tools/page-status/diff.js",
"position": 6,
"body": "**Fix: Improve Error Handling Pattern**\\n\\nAdd an \\\`ok\\\` flag for more consistent error handling:\\n\\n\`\`\`suggestion\\n * @returns {Promise<{content: string|null, status: number, ok: boolean}>} Content, status, and success flag\\n\`\`\`"
},
{
"path": "tools/page-status/diff.js",
"position": 12,
"body": "**Fix: Return consistent result object**\\n\\n\`\`\`suggestion\\n return { content: null, status: res.status, ok: false };\\n\`\`\`"
},
{
"path": "tools/page-status/diff.js",
"position": 16,
"body": "**Fix: Include ok flag in success case**\\n\\n\`\`\`suggestion\\n return { content, status: res.status, ok: true };\\n\`\`\`"
},
{
"path": "tools/page-status/diff.css",
"position": 41,
"body": "**Fix: Remove stylelint-disable by refactoring selector**\\n\\nUse \\\`.diff-new-page\\\` as intermediate selector to avoid specificity conflict:\\n\\n\`\`\`suggestion\\n.page-diff .diff-new-page .doc-diff-side-header {\\n padding: var(--spacing-s) var(--spacing-m);\\n\`\`\`"
}
]
}
JSON
# Step 4: Submit the review with all suggestions at once
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews \
--input /tmp/review-suggestions.json
# Step 5: Add a friendly summary comment
gh pr comment $PR_NUMBER --repo $OWNER/$REPO --body "$(cat <<'EOF'
## ⨠One-Click Fix Suggestions Added!
I've added **GitHub Suggestions** that you can apply with a single click!
### How to Apply
1. Go to the **Files changed** tab
2. Find the inline comments with suggestions
3. Click **"Commit suggestion"** to apply individually
4. Or click **"Add suggestion to batch"** on multiple, then **"Commit suggestions"** to batch
### What's Included
- â
[BLOCKING] XSS safety documentation
- â
Error handling improvements
- â
CSS selector refactoring (removes linter disables)
After applying, run \`npm run lint\` to verify all checks pass!
EOF
)"
echo "â
Review with suggestions posted successfully!"
echo "View at: https://github.com/$OWNER/$REPO/pull/$PR_NUMBER"
Key points:
- Use
position(diff position) NOTline(file line number) – This is critical! - The
positionis the line number in the unified diff output, counting from the first@@hunk marker - Multiple suggestions in one review enables batch application
- Each suggestion creates a properly attributed co-authored commit when accepted
- Escape special characters in JSON (quotes, backticks, newlines)
- Always include context in the body before the suggestion block
How to determine the correct position value:
The position is the line number in the unified diff, NOT the line number in the file. Here’s how to find it:
-
Get the diff:
gh pr diff <PR-number> > pr.diff -
Open the diff and count lines from the top, including:
- File headers (
--- a/fileand+++ b/file) - Hunk headers (
@@ -old,lines +new,lines @@) - Context lines (no prefix or space prefix)
- Removed lines (- prefix)
- Added lines (+ prefix)
- File headers (
-
The position is the line number of the ADDED line you want to comment on
Example from actual diff:
--- a/tools/page-status/diff.js
+++ b/tools/page-status/diff.js
async function fetchContent(url) {
const res = await fetch(url);
- if (!res.ok) throw new Error(`Failed to fetch ${url}: ${res.status}`);
- return res.text();
+ if (!res.ok) {
+ return { content: null, status: res.status }; â Position 12 (counting from top)
+ }
Best practices for suggestions:
- Keep suggestions focused and atomic (one fix per suggestion)
- Always include context – explain WHY the change is needed before the suggestion block
- Test the suggestion mentally or locally before posting
- Only suggest changes you’re confident are correct
- Include surrounding lines for context (GitHub shows ~3 lines of context)
- Use
positionin the diff, notlinein the file (critical!) - Batch related suggestions in one review for easier application
- Add a friendly summary comment explaining how to apply
- Format suggestion body with markdown (bold headers, inline code)
- Escape special characters properly in JSON (quotes, backticks, backslashes)
Approach 2: Fix Commits (For Complex or Multi-File Fixes)
For more complex fixes, create commits directly on the PR branch. This is especially useful when:
- Fixes span multiple files
- Changes need to be tested together
- Refactoring is required
- You want to demonstrate the fix working
Prerequisites:
- Ensure you have write access to the repository or the PR is from a fork you can access
- Verify the PR author has enabled maintainer edits (usually default for same-org PRs)
Workflow:
# 1. Get PR branch information
PR_INFO=$(gh pr view <PR-number> --json headRefName,headRepository,headRepositoryOwner)
BRANCH=$(echo $PR_INFO | jq -r '.headRefName')
REPO_OWNER=$(echo $PR_INFO | jq -r '.headRepositoryOwner.login')
# 2. Fetch the PR branch
git fetch origin pull/<PR-number>/head:pr-<PR-number>
# 3. Check out the PR branch
git checkout pr-<PR-number>
# 4. Make fixes based on review findings
# Example: Fix CSS linter issues by refactoring selectors
# 5. Test your fixes
npm run lint
# Run any relevant tests
# 6. Commit with detailed reasoning
git commit -m "$(cat <<'EOF'
fix: refactor CSS selectors to eliminate linter disables
Refactored CSS selectors in diff.css to resolve specificity conflicts
without using stylelint-disable comments. Changes:
- Increased specificity using .diff-new-page parent selector
- Reordered rules to prevent descending specificity issues
- Maintains same visual appearance and functionality
Addresses code review feedback: https://github.com/{owner}/{repo}/pull/<PR-number>#issuecomment-XXXXX
EOF
)"
# 7. Push to the PR branch
git push origin pr-<PR-number>:$BRANCH
# 8. Add comment to PR explaining what you fixed
gh pr comment <PR-number> --body "$(cat <<'EOF'
## Fixes Applied
I've pushed commits to address some of the review findings:
### Commit 1: Refactor CSS selectors
- â
Eliminated all `stylelint-disable` comments
- â
Resolved specificity conflicts properly
- â
Maintained visual appearance
### Commit 2: Standardize error handling
- â
Updated fetchContent to return consistent result objects
- â
Updated all callers to use new pattern
- â
Added JSDoc for clarity
### Still Need Action From You:
- [ ] **[BLOCKING]** Add XSS safety comment (see suggestion in review)
- [ ] Consider extracting renderDiffPanel helper (optional)
All linting passes now. Please review the commits and address the remaining item.
EOF
)"
Commit message format for fixes:
fix: <short description>
<Detailed explanation of what was fixed and why>
Changes:
- <specific change 1>
- <specific change 2>
Addresses review feedback: <link to review comment>
Approach 3: Hybrid Approach (RECOMMENDED FOR MOST PRs)
For the majority of PRs, use this hybrid strategy:
- GitHub suggestions for all fixable issues (primary method)
- Guidance/comments for subjective or architectural issues
- Fix commits only for very complex multi-file refactors
Typical workflow:
# 1. Post comprehensive review comment with summary (from Step 8)
gh pr comment <PR-number> --repo {owner}/{repo} --body "<detailed review summary>"
# 2. Submit a review with GitHub suggestions for ALL fixable issues
# (Create JSON as shown in Approach 1 with all suggestions)
gh api POST repos/{owner}/{repo}/pulls/<PR-number>/reviews \
--input /tmp/review-suggestions.json
# 3. Add a friendly summary about the suggestions
gh pr comment <PR-number> --repo {owner}/{repo} --body "$(cat <<'EOF'
## ⨠One-Click Suggestions Added!
I've added GitHub Suggestions for the fixable issues:
- â
[BLOCKING] Security documentation
- â
Error handling improvements
- â
CSS selector refactoring
Go to **Files changed** tab and click **"Commit suggestion"** to apply!
EOF
)"
# 4. For subjective/architectural issues, add guidance comments separately
# (Only if needed - most issues should have suggestions)
Real-world example distribution:
For a typical PR with 10 issues:
- GitHub suggestions: 7-8 issues (concrete fixes)
- Guidance comments: 2-3 issues (architectural, subjective, or “consider” level)
- Fix commits: 0-1 (only if critically needed)
This approach provides:
- â Maximum ease of use (one-click fixes)
- â Clear distinction between concrete fixes and suggestions
- â Reduced review cycles
- â Better PR author experience
Real-World Example
PR #196: Support unpublished pages in diff tool
Issues identified in review:
- XSS safety documentation needed (BLOCKING)
- Four CSS stylelint-disable comments (should fix)
- Inconsistent error handling (should fix)
- CSS variable fallback inconsistency (optional)
Action taken:
# Created two reviews with 9 total GitHub Suggestions
# - 4 suggestions for diff.js (XSS comment, error handling)
# - 5 suggestions for diff.css (selector refactoring)
# Posted friendly summary comment explaining one-click application
# Result: PR author can fix all issues in ~30 seconds vs 5-10 minutes of manual work
View the actual implementation:
- JavaScript suggestions: https://github.com/adobe/helix-tools-website/pull/196#pullrequestreview-3747855930
- CSS suggestions: https://github.com/adobe/helix-tools-website/pull/196#pullrequestreview-3747857266
- Summary comment: https://github.com/adobe/helix-tools-website/pull/196#issuecomment-3843945119
Time saved:
- Traditional review: Author spends 5-10 minutes copying code, editing files, testing
- With suggestions: Author spends 30 seconds clicking “Commit suggestions”
- Time savings: 90%+ reduction in fix application time
Guidelines for Choosing Approach
Use GitHub Suggestions when: (DEFAULT – use this ~70-80% of the time)
- â You know the exact fix needed
- â Change is < 20 lines (works well in GitHub UI)
- â Fix is objective and unambiguous
- â Can be applied without extensive testing
- â Independent of other changes
- â Examples: Add comments, remove debug code, fix typos, refactor selectors, update error handling, add JSDoc, fix linting issues
Use Fix Commits when: (RARE – use only when suggestions won’t work)
- â Changes span many files (>5 files)
- â Complex refactoring requiring testing
- â Changes are interdependent and must be tested together
- â Security fixes that need immediate attention and validation
- â You’re already working on the PR branch for other reasons
- â Examples: Large refactors, multi-file renames, complex security patches
Use Guidance Only when: (~20-30% of issues)
- â Architectural decisions needed
- â Multiple valid approaches exist
- â Requires domain knowledge or context from PR author
- â Subjective improvements (“Consider”, “Think about”)
- â Performance optimizations with trade-offs
- â Examples: “Consider using IntersectionObserver”, “You might want to extract this to a util”, “Have you thought about caching?”
Decision flowchart:
Issue identified
â
Do I know the exact fix? ââNOâââ Use Guidance
â YES
Is it < 20 lines? ââNOâââ Use Fix Commit or Guidance
â YES
Use GitHub Suggestion â
(BEST OPTION)
Quality Standards for Fixes
Before posting suggestions or commits:
- Verify correctness: Test locally or mentally verify the fix is correct
- Check scope: Ensure your fix doesn’t introduce new issues
- Maintain style: Match existing code style and patterns
- Run linters: Ensure fixes don’t break linting
- Be respectful: Frame fixes as helpful suggestions, not criticism
- Link context: Reference the review comment explaining WHY
Don’t:
- Don’t fix issues outside the PR scope
- Don’t change code style unrelated to the issue
- Don’t add features or enhancements
- Don’t push commits without explaining what you fixed
- Don’t fix subjective issues without discussion
Troubleshooting GitHub Suggestions
Common issues and solutions:
| Problem | Cause | Solution |
|---|---|---|
| “Validation Failed: line could not be resolved” | Used line instead of position |
Use position (diff line number) not line (file line number) |
| Suggestion doesn’t appear inline | Wrong position value | Count lines in the diff carefully, including headers |
| Can’t apply suggestion | Merge conflict or branch updated | Author needs to update branch first |
| Suggestion formatting broken | Unescaped JSON characters | Escape quotes, backticks, newlines in JSON |
| “Invalid commit_id” | Used old commit SHA | Get current HEAD SHA before creating review |
How to verify your review before posting:
# 1. Validate JSON syntax
cat /tmp/review-suggestions.json | jq . > /dev/null && echo "â
Valid JSON"
# 2. Check position values against diff
gh pr diff <PR-number> > pr.diff
# Manually verify each position value in your JSON matches an added line
# 3. Test with one suggestion first
# Before posting 10 suggestions, test with 1 to ensure positions are correct
Success Criteria
A good fix provision should:
- Use GitHub Suggestions as the primary method (for ~70-80% of fixable issues)
- Make it easy for the author to address issues (one-click accept)
- Provide working, tested code (not untested suggestions)
- Explain the reasoning behind each fix in the comment body
- Reference the original review feedback from Step 8
- Be respectful and collaborative in tone
- Focus only on issues identified in the review
- Not introduce new issues or regressions
- Include a friendly summary comment explaining how to apply suggestions
- Use proper
positionvalues (diff lines, not file lines) - Batch related suggestions in one review for efficient application
Quick Start Template
Copy this template to quickly create a review with GitHub Suggestions:
#!/bin/bash
# Quick script to create GitHub Suggestions for PR review
PR_NUMBER=YOUR_PR_NUMBER
OWNER="adobe"
REPO="helix-tools-website"
# Get commit SHA
COMMIT_SHA=$(gh api repos/$OWNER/$REPO/pulls/$PR_NUMBER --jq '.head.sha')
echo "â
PR Head SHA: $COMMIT_SHA"
# Create review JSON
cat > /tmp/review-$PR_NUMBER.json <<JSON
{
"commit_id": "$COMMIT_SHA",
"event": "COMMENT",
"comments": [
{
"path": "path/to/file.js",
"position": DIFF_LINE_NUMBER,
"body": "**Fix: Issue Title**\\n\\nExplanation of the issue.\\n\\n\`\`\`suggestion\\nYour fixed code here\\n\`\`\`\\n\\nReasoning for the fix."
}
]
}
JSON
# Submit review
gh api POST repos/$OWNER/$REPO/pulls/$PR_NUMBER/reviews \
--input /tmp/review-$PR_NUMBER.json
# Add summary comment
gh pr comment $PR_NUMBER --repo $OWNER/$REPO --body "⨠GitHub Suggestions added! Go to **Files changed** tab and click **Commit suggestion** to apply."
echo "â
Review posted! View at: https://github.com/$OWNER/$REPO/pull/$PR_NUMBER"
To use:
- Set
PR_NUMBER,OWNER,REPO - Replace the comments array with your actual suggestions
- Run the script
Review Priority Levels
Must Fix (Blocking)
Issues that MUST be resolved before merge:
- Missing preview URLs
- Linting failures
- Security vulnerabilities
- Breaking existing functionality
- Performance regressions (Lighthouse score drop)
- Accessibility violations
- Modifications to
aem.js
Should Fix (High Priority)
Issues that SHOULD be resolved:
!importantusage without justification- Unscoped CSS selectors
- Hardcoded values that should be configurable
- Missing error handling
- Console statements left in code
- CSS in JavaScript
Consider (Suggestions)
Improvements to consider:
- Code organization
- Naming conventions
- Documentation
- Additional test coverage
- Modern API usage opportunities
Common Review Patterns
Based on actual PR reviews, watch for these patterns:
CSS Issues
- “No CSS in JS, please” – Inline styles should use CSS classes
- “Use proper CSS” – Avoid style manipulation in JavaScript
- “Do we need the
!important?” – Strong preference against!important - “Solvable with more CSS specificity” – Increase specificity instead of
!important
JavaScript Issues
- “Why is it hardcoded here?” – Configuration should be externalized
- “No global eslint-disable directives” – Specific, justified disables only
- “Clean up console messages” – Remove debug logging
- “Use proper feature (e.g., decorateIcons, loadScript)” – Leverage existing utilities
Architecture Issues
- “Use existing patterns” – Check if similar functionality exists
- “Consider IntersectionObserver” – For lazy loading
- “Extract and align design tokens” – Use CSS custom properties
Content Issues
- “Check the type in content config” – Validate against expected schema
- “Is this feature needed?” – Question value vs complexity
Review Response Templates
Approval
## Approved
Preview URLs verified and changes look good.
### Visual Preview

<details>
<summary>Mobile View</summary>

</details>
**Verified:**
- [x] Code quality and linting
- [x] Performance (Lighthouse scores)
- [x] Visual appearance (screenshots captured)
- [x] Responsive behavior
- [x] Accessibility basics
[Any additional notes]
Request Changes
## Changes Requested
### Blocking Issues
[List with file:line references]
### Suggestions
[List of recommendations]
Please address the blocking issues before merge.
Comment
## Review Notes
[Non-blocking observations and questions]
Integration with GitHub Workflow
When triggered via GitHub Actions, the skill should:
- Receive: PR number, repository info, event context
- Execute: Full review workflow above
- Output:
- Review comment on the PR
- Appropriate review status (approve/request-changes/comment)
- Summary posted as PR comment
GitHub Actions integration points:
pull_requestevent triggersgh pr reviewfor posting reviewsgh pr commentfor detailed feedback
Resources
EDS-Specific Resources
- EDS Development Guidelines: https://www.aem.live/docs/dev-collab-and-good-practices
- Performance Best Practices: https://www.aem.live/developer/keeping-it-100
- Block Development: https://www.aem.live/developer/block-collection
- David’s Model: https://www.aem.live/docs/davidsmodel
GitHub Code Review Resources
- GitHub Suggestions Documentation: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/incorporating-feedback-in-your-pull-request
- Pull Request Reviews API: https://docs.github.com/en/rest/pulls/reviews
- Review Comments API: https://docs.github.com/en/rest/pulls/comments
- Creating Review Comments: https://docs.github.com/en/rest/pulls/comments#create-a-review-comment-for-a-pull-request
Success Criteria
For Self-Review Mode
A complete self-review should:
- Review all modified/new files
- Check code against all quality criteria
- Run linting and fix issues
- Capture visual screenshots of test content
- Verify responsive behavior across viewports
- Identify issues to fix before committing
- Confirm code is ready for commit and PR
For PR Review Mode
A complete PR review should:
- Validate all PR structure requirements (preview URLs, description)
- Check code against all quality criteria
- Verify performance requirements
- Capture and include visual screenshots
- Assess visual appearance for regressions
- Assess content/authoring impact
- Identify security concerns
- Provide actionable feedback with specific references
- Include screenshots in PR review comment
- Provide GitHub Suggestions for all fixable issues (primary method – ~70-80% of issues)
- Submit suggestions as a single review for batch application
- Include a friendly summary comment explaining how to apply suggestions
- Explain reasoning for each fix in the suggestion comment body
- Use guidance comments only for subjective/architectural issues
- Use fix commits only when suggestions won’t work (rare)
- Use appropriate review status (approve/request-changes/comment)
Integration with Content-Driven Development
This skill integrates with the content-driven-development workflow:
CDD Workflow:
Step 1: Start dev server
Step 2: Analyze & plan
Step 3: Design content model
Step 4: Identify/create test content
Step 5: Implement (building-blocks skill)
âââ testing-blocks skill (browser testing)
âââ **code-review skill (self-review)** â Invoke here
Step 6: Lint & test
Step 7: Final validation
Step 8: Ship it (commit & PR)
Recommended invocation point: After implementation and testing-blocks skill complete, before final linting and committing.
What this catches before PR:
- Code quality issues
- EDS pattern violations
- Security concerns
- Performance problems
- Visual regressions
Benefits of self-review:
- Catch issues early (cheaper to fix)
- Cleaner PRs with fewer review cycles
- Learn from immediate feedback
- Consistent code quality