Skip to content

Comments

feat: add seo category to template filters#142

Merged
rubenmarcus merged 8 commits intomainfrom
feat/seo-aeo-category
Feb 6, 2026
Merged

feat: add seo category to template filters#142
rubenmarcus merged 8 commits intomainfrom
feat/seo-aeo-category

Conversation

@rubenmarcus
Copy link
Member

@rubenmarcus rubenmarcus commented Feb 6, 2026

Summary

  • Adds seo to the --category filter option in the template command
  • Updates CLI help text, template command help text, and documentation
  • Companion to ralph-templates#1 which adds the AEO and SEO toolkit specs

Test plan

  • ralph-starter template list --category seo should show templates once ralph-templates PR is merged
  • ralph-starter template --help shows seo in category list

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added SEO template category for selection
    • Figma design-to-code generation and expanded fetch/build sources
    • Batch processing for multiple issues with per-issue flows
    • Activity Log resource to surface .ralph/activity.md content
    • Tools to list presets and fetch specs from external integrations
  • Documentation

    • Updated template help and docs to include the SEO category

rubenmarcus and others added 5 commits February 6, 2026 06:10
Read version dynamically from package.json instead of hardcoding '0.1.0'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ralph_list_presets tool to discover all 19 workflow presets by category
- Add ralph_fetch_spec tool to preview specs from GitHub, Linear, Notion, and
  Figma without running the full coding loop
- Improve all existing tool descriptions with detailed context for LLM clients
- ralph_fetch_spec supports Figma modes (spec, tokens, components, content, assets)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add figma_to_code prompt for Figma design-to-code workflow with framework
  and mode selection (spec, tokens, components, content)
- Add batch_issues prompt for processing multiple GitHub/Linear issues
  automatically with auto mode
- Update fetch_and_build prompt to include Figma as a source option
- Update fetch_and_build to use ralph_fetch_spec for preview before building

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add .ralph/activity.md as a readable MCP resource so Claude Desktop
and other MCP clients can access loop execution history, timing data,
and cost information.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 'seo' to the category filter options in CLI help text and docs,
matching the new SEO & AEO templates added to ralph-templates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

Adds "seo" to template categories and CLI help; introduces new MCP tools (ralph_list_presets, ralph_fetch_spec), two prompts (figma_to_code, batch_issues), expands fetch_and_build to accept Figma, adds Activity Log resource mapping, and replaces hard-coded version with a getPackageVersion() util.

Changes

Cohort / File(s) Summary
Template Category Addition
docs/docs/cli/template.md, src/cli.ts, src/commands/template.ts
Adds "seo" to template categories and updates CLI/help text.
MCP Tools & Handlers
src/mcp/tools.ts
Adds tools ralph_list_presets and ralph_fetch_spec with schemas and handlers; updates handleToolCall dispatch and tool metadata. Review input validation, external fetch error handling, JSON/string responses, and path handling for workspace writes/reads.
MCP Prompts
src/mcp/prompts.ts
Adds figma_to_code and batch_issues prompts; expands fetch_and_build to include figma as a source and updates prompt argument handling and generated messages. Verify argument validation and message construction logic.
MCP Resources (Activity Log)
src/mcp/resources.ts
Adds Activity Log resource ralph://project/activity mapped to .ralph/activity.md and implements reading it when present. Check path resolution, missing-file behavior, and content MIME.
Server & Version Utility
src/mcp/server.ts, src/utils/version.ts
Introduces getPackageVersion() util (walks up to find package.json, caches result, falls back to 0.1.0) and uses it in MCP server runtime/version. Inspect file I/O, caching, and fallback correctness.
CLI Version Integration
src/cli.ts
Replaces direct package.json reads with getPackageVersion() for CLI/version reporting. Ensure consistent error handling and no exposure of workspace files or sensitive data.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant CLI as CLI
participant MCP as MCP Server
participant Tools as Tools Dispatcher
participant Integr as Integrations (GitHub/Notion/Linear/Figma)
participant FS as Workspace FS

CLI->>MCP: invoke tool (e.g., ralph_fetch_spec / ralph_list_presets)
MCP->>Tools: handleToolCall(toolName, args)
Tools->>Tools: validate args against schema
alt ralph_list_presets
Tools->>FS: import presets (presets/index)
FS-->>Tools: presets JSON
Tools-->>MCP: return presets payload (text/JSON)
else ralph_fetch_spec
Tools->>Integr: fetchFromIntegration(source, identifier, options)
Integr-->>Tools: spec (string or object)
Tools->>FS: optionally read/write path in workspace
Tools-->>MCP: return spec payload (text)
end
MCP-->>CLI: relay tool result

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add seo category to template filters' directly matches the main change in the PR, which adds SEO to template category filtering across CLI and documentation.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/seo-aeo-category

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

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

✔️ Bundle Size Analysis

Metric Value
Base 1523.22 KB
PR 1542.88 KB
Diff 19.65 KB (1.00%)
Bundle breakdown
156K	dist/auth
28K	dist/automation
4.0K	dist/cli.d.ts
4.0K	dist/cli.d.ts.map
16K	dist/cli.js
12K	dist/cli.js.map
348K	dist/commands
28K	dist/config
4.0K	dist/index.d.ts
4.0K	dist/index.d.ts.map
4.0K	dist/index.js
4.0K	dist/index.js.map
536K	dist/integrations
56K	dist/llm
588K	dist/loop
172K	dist/mcp
32K	dist/presets
92K	dist/setup
392K	dist/sources
52K	dist/ui
20K	dist/utils
304K	dist/wizard

@cloudflare-workers-and-pages
Copy link

Deploying ralph-starter with  Cloudflare Pages  Cloudflare Pages

Latest commit: 66f3748
Status: ✅  Deploy successful!
Preview URL: https://6d13c497.ralph-starter.pages.dev
Branch Preview URL: https://feat-seo-aeo-category.ralph-starter.pages.dev

View logs

Copy link

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/mcp/resources.ts (1)

126-128: ⚠️ Potential issue | 🟠 Major

Path traversal vulnerability in specs resource handler — sanitize resolved path

The specs handler allows directory traversal attacks. A crafted URI like ralph://project/specs/../../IMPLEMENTATION_PLAN bypasses the intended specs directory boundary, enabling unauthorized access to any .md file in the project. This is a genuine OWASP A01:2021 control failure.

The issue occurs because resourcePath.replace('specs/', '') performs simple string replacement without path normalization, and path.join() resolves .. sequences. The existsSync() check doesn't prevent traversal — it only blocks reading non-existent files.

Implement the suggested guard to validate the resolved path stays within the specs directory:

🛡️ Suggested guard
       if (resourcePath.startsWith('specs/')) {
         const specName = resourcePath.replace('specs/', '');
         filePath = join(cwd, 'specs', `${specName}.md`);
+        const specsDir = join(cwd, 'specs');
+        if (!filePath.startsWith(specsDir)) {
+          throw new Error(`Invalid spec path: ${resourcePath}`);
+        }
       } else {
🤖 Fix all issues with AI agents
In `@src/mcp/prompts.ts`:
- Around line 252-281: The 'batch_issues' prompt incorrectly instructs the LLM
to "use ralph_fetch_spec to preview the available issues" but ralph_fetch_spec
returns a single spec by identifier; update the prompt text in the batch_issues
case in src/mcp/prompts.ts to either (a) reference an existing issue-listing
tool (if one exists) or (b) instruct the model to call a new issue-listing tool
(e.g., ralph_list_issues) instead of ralph_fetch_spec; ensure the prompt still
directs the model to provide identifiers for each issue before calling
ralph_fetch_spec and keep ralph_run/auto mode instructions (ralph_run)
unchanged.

In `@src/mcp/server.ts`:
- Around line 18-27: The getPackageVersion implementation in getPackageVersion
(src/mcp/server.ts) duplicates fragile path logic that differs from src/cli.ts;
extract a single shared resolver (e.g., create src/utils/version.ts with a
robust getPackageVersion that walks up parent directories from
dirname(fileURLToPath(import.meta.url)), attempts to read package.json
candidates, caches the found version, and returns a sensible default), then
replace the local getPackageVersion implementations in both server.ts and cli.ts
to import and use this shared function (or alternatively replace both usages
with a build-time/version constant), ensuring the new resolver handles multiple
dist-depths and avoids silent mismatches.

In `@src/mcp/tools.ts`:
- Around line 454-457: The category filter currently uses a substring match
(category.toLowerCase().includes(filterCategory)), which can produce unintended
matches; update the check in the loop over allCategories to perform a normalized
strict equality (e.g., compare category.toLowerCase() === filterCategory) or, if
fuzzy matching is intentional for MCP ergonomics, add a clear inline comment
above the condition documenting that deliberate substring matching is desired;
locate the check in the loop that iterates over Object.entries(allCategories)
where filterCategory is tested and change the logic or add the explanatory
comment accordingly.
- Around line 477-499: The ralph_fetch_spec schema requires parsed.path but
handleFetchSpec never uses it; update handleFetchSpec to include parsed.path in
the options passed to fetchFromIntegration (same pattern as
handleInit/handlePlan/handleRun/handleStatus) so working-directory context is
preserved: add options.path = parsed.path when present before calling
fetchFromIntegration(parsed.source, parsed.identifier, options) (or if you
decide path is truly unused, remove path from ralph_fetch_spec instead—choose
one consistent fix).

- Create src/utils/version.ts with a robust version resolver that walks
  up parent directories, handles multiple dist depths, and caches the result
- Replace duplicate getPackageVersion in cli.ts and mcp/server.ts with
  the shared import
- Fix handleFetchSpec not passing parsed.path to fetchFromIntegration,
  preserving working-directory context

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@src/cli.ts`:
- Around line 261-264: The --category option currently accepts any string (only
documented in the description) so typos silently pass; replace the
.option('--category <name>', ...) usage with Commander’s Option-based API: call
.addOption(new Option('--category <name>', 'Filter by category
(...)').choices(['web-dev','blockchain','devops','mobile','tools','seo'])) so
valid values are centralized and validated automatically; use the Option class,
.addOption, and .choices() for this change.

In `@src/mcp/tools.ts`:
- Around line 189-241: getTools() currently returns raw JSON Schema objects for
ralph_list_presets and ralph_fetch_spec that duplicate the shape defined in
toolSchemas (Zod), creating a maintenance risk; change getTools() to
derive/serialize the JSON Schema from the corresponding Zod schemas in
toolSchemas (e.g., using zod-to-json-schema or Zod's z.toJSONSchema()), so
ralph_list_presets and ralph_fetch_spec JSON schemas are generated from their
Zod definitions rather than kept inline.

In `@src/utils/version.ts`:
- Around line 26-36: The loop currently accepts the first package.json with any
version; change it to also validate pkg.name against the expected package name
before setting cachedVersion. Modify the candidates loop in the function that
uses variables candidates, pkg and cachedVersion so it checks both pkg.version
and pkg.name === expectedPackageName (where expectedPackageName is obtained from
a stable source — e.g., an imported project package.json constant or a
configured constant) and only then return cachedVersion; otherwise continue to
the next candidate.

- Fix batch_issues prompt: use ralph_run with auto mode instead of
  incorrectly referencing ralph_fetch_spec for listing issues
- Fix handleListPresets category filter: use strict equality instead of
  substring match to prevent unintended matches
- handleFetchSpec already passes path to fetchFromIntegration (linter fix)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@src/mcp/prompts.ts`:
- Around line 233-244: The prompt template uses args?.framework in two places
with inconsistent casing (lowercase 'react' at args?.framework || 'react' and
capitalized 'React' in the prose), so add a small normalization step (e.g.,
compute a variable like normalizedFramework and displayFramework) near where the
prompt is built that derives a default and a nicely capitalized display string
from args?.framework; then replace occurrences of args?.framework in the
template with normalizedFramework for technical identifiers and displayFramework
for prose (references: args?.framework, the prompt text string that includes
"Framework: ${...}" and "build the ${...} implementation", and the ralph_run
mention).

In `@src/mcp/tools.ts`:
- Around line 433-436: handleListPresets currently calls
toolSchemas.ralph_list_presets.parse(args) but args can be undefined per MCP
spec; guard for undefined and pass an empty object to the Zod parser instead of
undefined so optional fields validate correctly. Update handleListPresets to
treat undefined args as {} before calling toolSchemas.ralph_list_presets.parse,
keeping the rest of the function and return shape intact; reference the
ralph_list_presets.parse call in handleListPresets to locate the change.
- Around line 484-488: The runtime truthiness check on parsed.path is dropping
valid empty-string values and is inconsistent with sibling handlers; either
remove the guard and always assign options.path = parsed.path to match
handleInit/handlePlan/handleRun, or enforce non-empty at the schema
(toolSchemas.ralph_fetch_spec) by adding a .min(1) (or equivalent) so
parsed.path can safely be assumed non-empty—update the code around the options
construction (the parsed.path check) and/or the ralph_fetch_spec schema
accordingly.

- Normalize framework casing in figma_to_code prompt (consistent display name)
- Guard undefined args in handleListPresets with fallback to empty object
- Enforce non-empty path in ralph_fetch_spec schema (.min(1)) and always
  assign path to options instead of truthiness check

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@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: 5

🤖 Fix all issues with AI agents
In `@src/mcp/prompts.ts`:
- Around line 255-284: The batch_issues prompt interpolates user-controlled args
(source, project, label) directly into the LLM prompt in the case 'batch_issues'
return object, creating a prompt-injection surface; sanitize these values before
interpolation (e.g., strip newlines and control characters, enforce a safe
whitelist/regex such as alphanumerics, dashes, underscores, or truncate to a max
length) or escape them so injected newlines/instructions cannot be injected into
the prompt, and then use the sanitized variables instead of args.* when building
the prompt content (references: the 'batch_issues' case and the args variables
used in the template).
- Around line 225-253: The framework display logic inside the 'figma_to_code'
case normalizes by capitalizing the first char but misformats acronyms/compound
names (e.g., 'nextjs' -> 'Nextjs', 'html' -> 'Html'); replace the current
displayFramework calculation (based on framework.charAt...) with a small
display-name map keyed by framework (e.g., 'nextjs' -> 'Next.js', 'html' ->
'HTML', 'react' -> 'React') and fall back to a sensible default capitalization;
also replace the nested ternary used to produce the human-readable mode text
(the string built from args?.mode in the user content) with a lookup object
(modeLabel or similar) mapping modes like 'tokens' -> 'design tokens',
'components' -> 'component structure', 'content' -> 'text content and IA',
default -> 'the full design specification' to improve readability and make
future additions easy; update the template to reference these new display
variables (displayFramework and modeLabel) where currently framework.charAt...
and the nested ternary are used.

In `@src/mcp/tools.ts`:
- Around line 477-499: handleFetchSpec passes parsed.identifier directly into
fetchFromIntegration (with parsed.source) which may be used to perform outbound
requests; update the integration implementations called by fetchFromIntegration
to validate and restrict identifiers: normalize and parse the identifier,
enforce allowed schemes/hosts or an integration-specific allowlist, block
private/internal IP ranges and localhost, reject data/file URIs, and apply
per-source domain/path constraints based on parsed.source to prevent SSRF and
unintended internal access. Ensure each integration returns a clear error on
invalid identifiers and add unit tests covering malicious host/scheme cases.
- Around line 57-61: The Zod schema for the `identifier` field currently lacks a
minimum-length guard so empty strings pass validation; update the `identifier`
schema (the symbol `identifier` in the same schema block as `path`) to include
`.min(1)` like `path` does, so empty identifiers are rejected early and won’t be
forwarded to `fetchFromIntegration` causing downstream integration errors.
- Around line 208-241: The JSON Schema for inputSchema.properties.path (used by
ralph_fetch_spec) is missing minLength: 1 and therefore diverges from the Zod
schema that enforces .min(1); update inputSchema.properties.path to include
"minLength": 1 so the JSON Schema and the Zod validation in ralph_fetch_spec
stay consistent and prevent empty-string submissions.

@rubenmarcus
Copy link
Member Author

@coderabbitai resolve

@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2026

✅ Actions performed

Comments resolved and changes approved.

@rubenmarcus rubenmarcus merged commit aeec80b into main Feb 6, 2026
15 checks passed
@rubenmarcus rubenmarcus deleted the feat/seo-aeo-category branch February 7, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant