Skip to content

Next.js Web Persona#839

Open
willwashburn wants to merge 4 commits into
mainfrom
persona
Open

Next.js Web Persona#839
willwashburn wants to merge 4 commits into
mainfrom
persona

Conversation

@willwashburn
Copy link
Copy Markdown
Member

This pull request introduces a new persona configuration for the Next.js web application by adding the nextjs-web-steward persona. This persona defines responsibilities, required skills, workflows, and quality standards for maintaining and improving the Next.js app, with a focus on aligning work with product goals, SEO, and performance.

@willwashburn willwashburn requested a review from khaliqgant as a code owner May 10, 2026 23:12
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 10, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new nextjs-web-steward persona JSON and modifies the Relayfile page: introduces SiteNav/SiteFooter wiring, passes GitHubStarsBadge as navActions, updates hero styles and RootLayout body classes, and hardens the FadeIn reveal logic.

Changes

Next.js Web Steward Persona Setup

Layer / File(s) Summary
Persona Configuration
.agentworkforce/workforce/personas/nextjs-web-steward.json
New persona configuration defines nextjs-web-steward with id, intent, tags, description, skills, optional inputs.TASK_DESCRIPTION, harness/model/systemPrompt, harnessSettings, mount.ignoredPatterns, and embedded agentsMdContent.

Relayfile Page & Components

Layer / File(s) Summary
Nav and footer wiring
web/app/file/RelayfileContent.tsx, web/app/file/page.tsx
RelayfileContent gains an optional navActions?: ReactNode, renders SiteNav and SiteFooter; page.tsx imports GitHubStarsBadge and passes it as navActions.
Styles and root layout
web/app/file/relayfile.module.css, web/app/layout.tsx
Relayfile hero spacing, padding, headline clamp, and CTAs spacing adjusted; RootLayout <body> now includes font variable classes and suppressHydrationWarning.
FadeIn reveal behavior
web/components/FadeIn.tsx
FadeIn defaults to visible, adds animate state, robust IntersectionObserver with threshold/rootMargin, initial-in-viewport check, timeout fallback, and updated inline style logic for transform/transition when animating.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • AgentWorkforce/relay#851: Modifies the Relayfile page and overlaps edits to web/app/file/RelayfileContent.tsx.
  • AgentWorkforce/relay#817: Adds persona-related publishing/validation infra relevant to new persona JSON artifacts.
  • AgentWorkforce/relay#818: Persona loader/spawner changes that validate/translate persona harness/model fields (related to harness/model usage).

Suggested reviewers

  • khaliqgant

Poem

🐰 A steward hops in with JSON bright,

Tasks and skills arranged just right,
Nav and footer join the scene,
Fonts and fades kept snappy and clean,
A little rabbit cheer for deploy tonight!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the persona's purpose and focus but lacks the required 'Test Plan' section from the repository template, making the description incomplete. Add a 'Test Plan' section documenting how the new persona was tested or validated, including whether manual testing or other verification steps were completed.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Next.js Web Persona' is clear and directly reflects the main change—adding a new persona configuration for Next.js web stewardship.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch persona

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

web/app/file/relayfile.module.css

Parsing error: Declaration or statement expected.


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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 @.agentworkforce/workforce/personas/nextjs-web-steward.json:
- Around line 16-32: The listed persona skill sources use mutable branch refs;
update each URL under the ids nextjs-app-router-fundamentals,
nextjs-server-client-components, lighthouse-ci-integrator, and seo-audit by
replacing "tree/main" with a pinned commit SHA (e.g., "tree/<commit-sha>") for
that repository, fetching the stable commit SHA from the remote repo and
substituting it into the "source" string so each skill points to an immutable
commit reference instead of the main branch.
🪄 Autofix (Beta)

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: 957ae8ee-f53a-4f4e-a24a-3e3557857639

📥 Commits

Reviewing files that changed from the base of the PR and between bffd6b2 and 850fd9d.

📒 Files selected for processing (1)
  • .agentworkforce/workforce/personas/nextjs-web-steward.json

Comment on lines +16 to +32
"source": "https://github.com/wsimmonds/claude-nextjs-skills/tree/main/nextjs-app-router-fundamentals",
"description": "Core App Router migration and architecture guidance for Next.js 13+ projects."
},
{
"id": "nextjs-server-client-components",
"source": "https://github.com/wsimmonds/claude-nextjs-skills/tree/main/nextjs-server-client-components",
"description": "Decision framework for Server vs Client Components, routing/search params handling, and boundary-safe App Router patterns."
},
{
"id": "lighthouse-ci-integrator",
"source": "https://github.com/Dexploarer/hyper-forge/tree/main/.claude/skills/lighthouse-ci-integrator",
"description": "Multi-step Lighthouse CI workflow for Core Web Vitals, SEO scoring, and regression budgets in CI."
},
{
"id": "seo-audit",
"source": "https://github.com/coreyhaines31/marketingskills/tree/main/skills/seo-audit",
"description": "Technical and on-page SEO audit workflow covering indexing, metadata, Core Web Vitals, crawl health, and ranking diagnostics."
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify mutable refs and basic URL reachability for skill sources.

set -euo pipefail

FILE="$(fd -p 'nextjs-web-steward.json' | head -n1)"
echo "Reviewing file: $FILE"

echo "---- Sources found ----"
jq -r '.skills[].source' "$FILE"

echo "---- Mutable refs (tree/main) ----"
jq -r '.skills[].source' "$FILE" | rg -n '/tree/main/' || true

echo "---- HTTP status checks ----"
while IFS= read -r url; do
  code="$(curl -s -o /dev/null -w '%{http_code}' "$url")"
  echo "$code $url"
done < <(jq -r '.skills[].source' "$FILE")

Repository: AgentWorkforce/relay

Length of output: 182


🏁 Script executed:

find . -name "*nextjs-web-steward*" -type f 2>/dev/null

Repository: AgentWorkforce/relay

Length of output: 125


🏁 Script executed:

cat ./.agentworkforce/workforce/personas/nextjs-web-steward.json

Repository: AgentWorkforce/relay

Length of output: 5926


Pin external skill sources to immutable commit references

All four skill sources use mutable branch references (/tree/main/), which creates non-deterministic persona behavior and weakens reproducibility guarantees:

  • Line 16: claude-nextjs-skills/tree/main/nextjs-app-router-fundamentals
  • Line 21: claude-nextjs-skills/tree/main/nextjs-server-client-components
  • Line 26: hyper-forge/tree/main/.claude/skills/lighthouse-ci-integrator
  • Line 31: marketingskills/tree/main/skills/seo-audit

Replace each tree/main with a pinned commit SHA (e.g., tree/abc1234d) to ensure skill content remains stable over time.

🤖 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 @.agentworkforce/workforce/personas/nextjs-web-steward.json around lines 16 -
32, The listed persona skill sources use mutable branch refs; update each URL
under the ids nextjs-app-router-fundamentals, nextjs-server-client-components,
lighthouse-ci-integrator, and seo-audit by replacing "tree/main" with a pinned
commit SHA (e.g., "tree/<commit-sha>") for that repository, fetching the stable
commit SHA from the remote repo and substituting it into the "source" string so
each skill points to an immutable commit reference instead of the main branch.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

"best": {
"harness": "codex",
"model": "openai-codex/gpt-5.3-codex",
"systemPrompt": "",
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.

🔴 Empty systemPrompt in all three tiers will leave persona without behavioral instructions

All three tiers (best, best-value, minimum) set "systemPrompt": "". Every existing persona in packages/personas/personas/ provides a substantive system prompt, and the persona validator (packages/personas/scripts/validate-personas.mjs:94-96) explicitly requires systemPrompt to be a non-empty string via isNonEmptyString() (which checks value.trim().length > 0). When a harness loads this persona, the agent will receive no system-level instructions, making it behave as a generic assistant rather than a Next.js web steward.

The `agentsMdContent` field is not a substitute

The file includes agentsMd and agentsMdContent fields with detailed instructions, possibly intended as the system prompt. However, these fields are not part of the documented persona schema (packages/personas/README.md:73-88), are not referenced anywhere in the codebase (confirmed via search), and no code reads them. The detailed behavioral instructions in agentsMdContent should be moved into each tier's systemPrompt field (tailored per tier as other personas do).

Prompt for agents
All three tiers in the persona (best at line 41, best-value at line 50, minimum at line 59) have empty systemPrompt fields. Every other persona in packages/personas/personas/ provides per-tier system prompts that instruct the agent on its role, style, and constraints.

The file contains an agentsMdContent field with detailed Next.js Web Steward instructions, but this field is not part of the recognized persona schema and is not read by any code in the repo.

To fix: populate each tier's systemPrompt with appropriate behavioral instructions derived from the agentsMdContent. Follow the pattern of existing personas like relay-orchestrator.json, where each tier gets a tailored prompt (best tier gets the most detailed, minimum tier gets the most concise). Then consider removing the agentsMd and agentsMdContent fields unless they serve a purpose in the AgentWorkforce framework that is not yet reflected in this repo's code.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 850fd9deb2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"best": {
"harness": "codex",
"model": "openai-codex/gpt-5.3-codex",
"systemPrompt": "",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Provide non-empty systemPrompt for this tier

This tier sets systemPrompt to an empty string, which makes the persona unloadable in Relay: loadPersona treats empty prompts as missing and throws (packages/sdk/src/personas.ts, if (!systemPrompt) ...). Because all three tiers here use "systemPrompt": "", selecting nextjs-web-steward fails at runtime instead of spawning an agent, and agentsMdContent does not compensate for this in the SDK path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
web/components/FadeIn.tsx (2)

43-60: ⚡ Quick win

Cancel the fallback timer after a real intersection.

Once Line 45 fires, the timeout started at Line 56 is still pending and will schedule a redundant setVisible(true) for every revealed instance. Clearing it in the observer callback avoids needless updates on pages with many FadeIns.

Suggested change
-    const observer = new IntersectionObserver(
+    let fallbackTimer: number | undefined;
+    const observer = new IntersectionObserver(
       ([entry]) => {
         if (entry.isIntersecting) {
           reveal();
+          if (fallbackTimer !== undefined) {
+            window.clearTimeout(fallbackTimer);
+          }
           observer.unobserve(el);
         }
       },
       { threshold: 0.01, rootMargin: '0px 0px -8% 0px' }
     );
@@
-    const fallbackTimer = window.setTimeout(reveal, 1500);
+    fallbackTimer = window.setTimeout(reveal, 1500);
🤖 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 `@web/components/FadeIn.tsx` around lines 43 - 60, The IntersectionObserver
callback reveals the element via reveal() but doesn't clear the fallbackTimer,
so the fallback timeout still fires; update the observer callback (the function
passed to new IntersectionObserver that calls reveal() and
observer.unobserve(el)) to also call window.clearTimeout(fallbackTimer) (or
clearTimeout) after reveal() to cancel the pending fallback; ensure
fallbackTimer (created with window.setTimeout) remains in scope for the callback
so clearing it prevents the redundant setVisible(true) call.

30-41: ⚡ Quick win

Honor prefers-reduced-motion before hiding offscreen content.

Line 31 enables animation for every hydrated client, and Line 41 then hides below-the-fold content until the observer or timeout fires. Users who request reduced motion will still get the fade/slide behavior here. Please short-circuit to reveal() when reduced motion is enabled.

Suggested change
     // Only animate when JS is active; content remains visible if hydration fails.
+    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
+      reveal();
+      return;
+    }
     setAnimate(true);
🤖 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 `@web/components/FadeIn.tsx` around lines 30 - 41, The component currently
enables animations unconditionally (calls setAnimate(true)) and then hides
offscreen content (setVisible(false)), which ignores users'
prefers-reduced-motion setting; update FadeIn so that before calling
setAnimate(true) you detect the media query
(window.matchMedia('(prefers-reduced-motion: reduce)').matches) and if it
returns true immediately call reveal() (the existing reveal function) and
return, skipping setAnimate and setVisible logic so reduced-motion users never
get the hide/fade/slide behavior.
🤖 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.

Nitpick comments:
In `@web/components/FadeIn.tsx`:
- Around line 43-60: The IntersectionObserver callback reveals the element via
reveal() but doesn't clear the fallbackTimer, so the fallback timeout still
fires; update the observer callback (the function passed to new
IntersectionObserver that calls reveal() and observer.unobserve(el)) to also
call window.clearTimeout(fallbackTimer) (or clearTimeout) after reveal() to
cancel the pending fallback; ensure fallbackTimer (created with
window.setTimeout) remains in scope for the callback so clearing it prevents the
redundant setVisible(true) call.
- Around line 30-41: The component currently enables animations unconditionally
(calls setAnimate(true)) and then hides offscreen content (setVisible(false)),
which ignores users' prefers-reduced-motion setting; update FadeIn so that
before calling setAnimate(true) you detect the media query
(window.matchMedia('(prefers-reduced-motion: reduce)').matches) and if it
returns true immediately call reveal() (the existing reveal function) and
return, skipping setAnimate and setVisible logic so reduced-motion users never
get the hide/fade/slide behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: eec71c8c-7f1e-420e-bd58-3248dd1788af

📥 Commits

Reviewing files that changed from the base of the PR and between 850fd9d and 83ecfbc.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • .agentworkforce/workforce/personas/nextjs-web-steward.json
  • web/app/file/RelayfileContent.tsx
  • web/app/file/page.tsx
  • web/app/file/relayfile.module.css
  • web/app/layout.tsx
  • web/components/FadeIn.tsx
✅ Files skipped from review due to trivial changes (1)
  • web/app/layout.tsx

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.

2 participants