Skip to content

feat: add ship-pr, prep, sanity-plugin-md-notes, ui-match, and json-ld skills#3

Merged
voidhrithik merged 4 commits into
mainfrom
feat/skills-entries
Jul 6, 2026
Merged

feat: add ship-pr, prep, sanity-plugin-md-notes, ui-match, and json-ld skills#3
voidhrithik merged 4 commits into
mainfrom
feat/skills-entries

Conversation

@sameerroboto

@sameerroboto sameerroboto commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Problem / Intent

The Commons has org standards and stack entries but no shared agent skills yet. Skills developed across recent sessions (ship-pr, prep, sanity-plugin-md-notes, ui-match, json-ld) live only on individual machines and aren't discoverable by the team.

Approach

Add the five skills under entries/skills/, one directory per skill, each self-contained with its SKILL.md plus any references, rules, and scripts:

  • ship-pr — commit, push, draft-PR, and Linear sync workflow
  • prep — bootstrap work on a Linear ticket (branch, status, exploration, plan)
  • sanity-plugin-md-notes — wire up the sanity-plugin-md-notes plugin in a Sanity Studio, with bundler-specific guides
  • ui-match — Figma-vs-live-site component parity audit with HTML report tooling
  • json-ld — type-safe JSON-LD structured data for Next.js with schema-dts, with per-schema-type rules

Summary by CodeRabbit

  • New Features
    • Added a comprehensive JSON-LD documentation set for Next.js, covering common schema types, implementation examples, validation guidance, and an audit workflow.
    • Added new skill docs for planning, shipping PRs, and UI-to-Figma comparison workflows, including supporting references and sample processes.
    • Added practical guides for Sanity Markdown notes integration, with setup paths for different build tools and authoring conventions.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR adds five new documentation-only skill entries under entries/skills: a comprehensive JSON-LD structured-data skill (AGENTS.md, README.md, SKILL.md, metadata.json, and per-schema rule files plus an audit workflow), a "prep" Linear-ticket bootstrap skill, a sanity-plugin-md-notes integration skill (opt-in, authoring, Vite/Webpack guides), a "ship-pr" PR automation skill, and a "ui-match" Figma-vs-live comparison skill with Python/Bash/JS scripts for capture, cropping, report generation, and serving.

Changes

JSON-LD Structured Data Skill

Layer / File(s) Summary
Core skill overview and templates
entries/skills/json-ld/AGENTS.md, README.md, SKILL.md, metadata.json, rules/_sections.md, rules/_template.md
Establishes the JSON-LD injection pattern, quick-reference schema table, and reusable rule template/metadata.
Organization, Person, Service schemas
entries/skills/json-ld/AGENTS.md (sections), rules/org-*.md
Documents Organization, Person, and Service JSON-LD implementation patterns for Next.js.
Navigation schemas
entries/skills/json-ld/AGENTS.md (sections), rules/nav-*.md
Documents BreadcrumbList, WebSite, and SiteNavigationElement JSON-LD patterns.
Content and event schemas
entries/skills/json-ld/AGENTS.md (sections), rules/content-*.md
Documents Article, BlogPosting, Course, Event, JobPosting, and Recipe JSON-LD patterns.
Commerce and interactive schemas
entries/skills/json-ld/AGENTS.md (sections), rules/ecom-product.md, rules/interactive-*.md
Documents Product, FAQPage, and HowTo JSON-LD patterns.
Local business and media schemas
entries/skills/json-ld/AGENTS.md (sections), rules/local-local-business.md, rules/media-video-object.md
Documents LocalBusiness and VideoObject JSON-LD patterns.
Audit workflow
entries/skills/json-ld/AGENTS.md (audit section), rules/audit-project.md
Defines a five-phase route discovery, classification, detection, plan-generation, and implementation audit process.

Prep Skill

Layer / File(s) Summary
Prep skill workflow
entries/skills/prep/SKILL.md
Documents ticket resolution, branch creation, Linear status update, exploration, and implementation plan generation.

sanity-plugin-md-notes Skill

Layer / File(s) Summary
Skill orchestration phases
entries/skills/sanity-plugin-md-notes/SKILL.md
Documents detection, install/wiring, schema opt-in, authoring, and verification phases.
Schema opt-in patterns
entries/skills/sanity-plugin-md-notes/OPT-IN.md
Documents withHelp() wrapping and singleton/kebab-menu help configuration.
Help file authoring conventions
entries/skills/sanity-plugin-md-notes/AUTHORING.md
Documents .help.md frontmatter, markdown features, code blocks, video embeds, and intent links.
Bundler-specific install guides
entries/skills/sanity-plugin-md-notes/VITE.md, WEBPACK.md
Documents Vite and Webpack/Turbopack/Next.js wiring checklists.

Ship-PR Skill

Layer / File(s) Summary
Ship-PR end-to-end workflow
entries/skills/ship-pr/SKILL.md
Documents ticket resolution, commit, push permission checks, draft PR creation, and Linear ticket updates.

UI-Match Skill

Layer / File(s) Summary
Skill overview and inputs
entries/skills/ui-match/README.md, SKILL.md, metadata.json
Documents skill purpose, required inputs, and output directory conventions.
Capture and segmentation
entries/skills/ui-match/references/capture.md, scripts/site_sections.js, scripts/crop.sh
Implements live-site/Figma section boundary detection and per-component PNG cropping.
Comparison and report generation
entries/skills/ui-match/references/report.md, scripts/build_report.py, scripts/serve.py
Classifies findings and generates/serves the HTML comparison report.
Optional Linear ticket integration
entries/skills/ui-match/references/linear.md
Documents screenshot upload and Linear ticket creation reflected back into findings.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Assistant
  participant LinearMCP
  participant Git
  participant GitHubCLI
  Assistant->>LinearMCP: fetch ticket details
  Assistant->>Git: check status and commit changes
  Assistant->>GitHubCLI: check push permission
  Assistant->>GitHubCLI: push branch
  Assistant->>GitHubCLI: create draft PR
  Assistant->>LinearMCP: attach PR URL and set In Review
Loading

Suggested reviewers: voidhrithik, jonoroboto

Poem

A rabbit hopped through docs today,
JSON-LD in neat array,
Schemas stacked from FAQ to Course,
Ship-PR pushed with quiet force,
Ui-match snapped each pixel true —
🐇 thump-thump, the skills are new!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding five new shared skills under entries/skills/.
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.
✨ 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 feat/skills-entries

Warning

Review ran into problems

🔥 Problems

These MCP integrations need to be re-authenticated in the Integrations settings: Linear


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

@sameerroboto
sameerroboto marked this pull request as ready for review July 6, 2026 08:55
@coderabbitai
coderabbitai Bot requested review from jonoroboto and voidhrithik July 6, 2026 08:57
@voidhrithik
voidhrithik merged commit 0b14c6b into main Jul 6, 2026
0 of 3 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 30

Caution

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

⚠️ Outside diff range comments (7)
entries/skills/json-ld/rules/_template.md (1)

1-63: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Move this template into a supported scope or extend the parser.

roboto-mem lint only recognizes the existing entry scopes, so entries/skills/... is rejected as an unknown scope before this template can be used. The current title-based placeholder frontmatter will still not match the repo’s entry schema.

🤖 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 `@entries/skills/json-ld/rules/_template.md` around lines 1 - 63, The template
is placed under an unsupported entry scope, so the lint/parser rejects it before
the schema content can be used. Move this template into one of the existing
supported scopes recognized by roboto-mem lint, or update the scope parser to
accept entries/skills; also make the frontmatter and placeholders in the
_template.md match the repo’s entry schema used by other entry templates.

Source: Pipeline failures

entries/skills/json-ld/README.md (1)

1-85: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add frontmatter or move this README out of the linted tree.

The file currently starts with a heading, so roboto-mem lint will reject it before the content is even read.

🤖 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 `@entries/skills/json-ld/README.md` around lines 1 - 85, The README in the
JSON-LD skill currently starts with a Markdown heading, which causes roboto-mem
lint to fail before parsing the document content. Add the required frontmatter
at the top of this README or relocate it outside the linted tree, and ensure the
file’s opening structure matches what the lint step expects while keeping the
existing JSON-LD guidance content intact.

Source: Pipeline failures

entries/skills/json-ld/rules/_sections.md (1)

1-12: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add frontmatter or exclude this shared markdown file.

The repo linter requires markdown entries to start with YAML frontmatter. This file currently does not, so CI will fail on it as well.

🤖 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 `@entries/skills/json-ld/rules/_sections.md` around lines 1 - 12, The shared
markdown file for rule categories is missing required YAML frontmatter, which
will cause the markdown linter to fail. Add the standard frontmatter block at
the top of this file, or if it is meant to be a shared include rather than an
entry, update the lint/configuration to exclude this file from markdown entry
checks. Use the `_sections.md` shared content as the target when applying the
fix.

Source: Pipeline failures

entries/skills/ui-match/README.md (1)

1-48: 📐 Maintainability & Code Quality | 🟠 Major

Add YAML frontmatter here.

This file currently starts with a plain heading, and the repo lint is already failing on the missing --- block.

🤖 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 `@entries/skills/ui-match/README.md` around lines 1 - 48, The README for
ui-match is missing required YAML frontmatter at the top, which is causing the
repo lint failure. Update the document so it begins with a valid frontmatter
block before the existing heading, keeping the current content intact below it.
Use the ui-match README itself as the target and preserve the existing sections
and prose after the frontmatter.

Source: Pipeline failures

entries/skills/ui-match/references/linear.md (1)

1-114: 📐 Maintainability & Code Quality | 🟠 Major

Add YAML frontmatter here too.

Like README.md, this file currently starts with a plain heading, so the markdown lint failure will persist until it begins with ---.

🤖 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 `@entries/skills/ui-match/references/linear.md` around lines 1 - 114, The
markdown file starts with a plain heading, causing the lint failure to remain.
Update the top of linear.md to include YAML frontmatter before the existing
content, matching the pattern already used in README.md, and keep the rest of
the document unchanged. Use the file’s opening section and its existing heading
as the anchor for where the frontmatter should be inserted.

Source: Pipeline failures

entries/skills/ui-match/references/capture.md (1)

41-77: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Markdownlint warnings: missing blank lines around headings/fences and unlabeled fence.

Static analysis flags MD022/MD031/MD040 at several spots (e.g. Line 42 fence has no language, headings at 41/49/57/73 aren't surrounded by blank lines). Consider adding blank lines around headings/fences and a language hint (e.g. ```text) for the plain fenced block at Line 42-44.

🤖 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 `@entries/skills/ui-match/references/capture.md` around lines 41 - 77, The
markdown in the capture instructions has lint issues from missing blank lines
around headings and fenced blocks, plus an unlabeled code fence. Update the
section around the “Try MCP first”, “Fallback”, “Find precise boundaries, then
crop”, and “Naming” headings so each heading and fence has surrounding blank
lines, and give the plain fenced snippet a language tag such as text. Use the
existing section structure in capture.md to keep the formatting consistent.

Source: Linters/SAST tools

entries/skills/json-ld/rules/org-organization.md (1)

1-108: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Move entries/skills/json-ld/rules/org-organization.md out of the linted commons scopes, or add an exception.
roboto-mem lint only derives scopes from entries/org, entries/squads, entries/stacks, and entries/projects; entries/skills/json-ld/rules/* is treated as an unknown scope directory, so this subtree will keep breaking CI unless the layout or lint rules change.

🤖 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 `@entries/skills/json-ld/rules/org-organization.md` around lines 1 - 108, The
Organization rule doc is under a directory that the lint scope resolver does not
recognize, so CI will keep failing for this subtree. Either move this document
into one of the linted commons scope directories used by the scope derivation
logic, or update the lint configuration to explicitly exempt
`entries/skills/json-ld/rules/*`; make the change in the path/layout that the
`roboto-mem lint` scope discovery uses so `org-organization.md` is included or
ignored intentionally.

Source: Pipeline failures

🤖 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 `@entries/skills/json-ld/AGENTS.md`:
- Around line 1-7: Add the required YAML frontmatter at the top of AGENTS.md so
the markdown parser sees a supported `---` block before any heading or prose.
Update the JSON-LD Structured Data agent reference header to start with
frontmatter, keeping the existing content below it, and ensure the file remains
valid within the linted entries tree.

In `@entries/skills/json-ld/README.md`:
- Around line 27-40: The quick-start Organization example uses the wrong `logo`
shape, since it still shows a string URL instead of the canonical `ImageObject`
form documented in `AGENTS.md`. Update the `jsonLd` example in the README so the
`Organization` object’s `logo` uses an `ImageObject` with the required fields
and dimensions, keeping the rest of the `WithContext<Organization>` snippet
intact.

In `@entries/skills/json-ld/rules/audit-project.md`:
- Around line 1-6: This markdown file is using the wrong entry schema for the
repository’s parser. Update the frontmatter in the JSON-LD Audit entry to match
the supported contract by replacing the current title/impact fields with the
required description/type/author/date fields, and keep the content aligned with
the entry format used elsewhere in the repo. Ensure the entry is placed in a
recognized scope/category so it no longer fails linting as an unknown
skills-scope entry.

In `@entries/skills/json-ld/rules/content-course.md`:
- Around line 65-74: The JSON-LD example places instructor at the top-level
Course object, which is invalid schema.org markup. Move the instructor property
into the hasCourseInstance object in the content-course example so it belongs to
the CourseInstance alongside courseMode and courseWorkload, and keep the
top-level Course fields limited to Course-level properties.

In `@entries/skills/json-ld/rules/content-event.md`:
- Around line 1-6: This entry is in an unsupported scope and uses the wrong
frontmatter shape, so move the content into a recognized roboto-mem entry scope
and replace the current Event metadata with the required entry fields. Update
the frontmatter in content-event.md to use description, type, author, and date
instead of title, impact, impactDescription, and tags, and ensure the entry
follows the conventions used by other valid memory entries in this rules set.

In `@entries/skills/json-ld/rules/local-local-business.md`:
- Around line 84-109: The OpeningHoursSpecification entries use plain day labels
in dayOfWeek, which should be normalized to schema.org enum URLs for consistency
and interoperability. Update the openingHoursSpecification values in the
local-local-business JSON-LD rule so each dayOfWeek item uses the full
schema.org URL form rather than short names, preserving the existing structure
in the same OpeningHoursSpecification objects.

In `@entries/skills/json-ld/rules/media-video-object.md`:
- Around line 72-79: The MediaObject example’s publisher Organization logo is
incomplete because the nested ImageObject under publisher.logo does not follow
the Organization logo contract. Update the JSON-LD example in
media-video-object.md so the publisher.logo ImageObject includes explicit width
and height alongside the existing url, matching the Organization guidance used
elsewhere in the docs.

In `@entries/skills/json-ld/rules/nav-website.md`:
- Around line 40-45: The logo ImageObject in the nav website JSON-LD uses string
literals for width and height, which violates the schema-dts contract. Update
the logo block in the nav-website markdown so the width and height fields are
removed entirely unless you can provide valid Distance or QuantitativeValue
values, and keep the change localized to the logo object definition.

In `@entries/skills/json-ld/rules/org-service.md`:
- Around line 61-69: The nested Organization logo shape in the provider example
is incomplete because provider.logo only includes the ImageObject type and url.
Update the Organization JSON-LD sample in org-service.md so the provider.logo
example remains a fully structured ImageObject with explicit width and height,
matching the core Organization guidance and the rest of the skill set.

In `@entries/skills/json-ld/SKILL.md`:
- Around line 1-16: The SKILL.md frontmatter is not compatible with the repo
parser because it uses a reserved name field and omits required metadata. Update
the frontmatter in the json-ld skill entry to use the parser’s expected fields
by removing the reserved name usage and adding the required type, author, and
date values so roboto-mem lint accepts the file.

In `@entries/skills/prep/SKILL.md`:
- Line 21: The failure handling in SKILL.md is too strict for Linear auth
errors: update the /prep flow so bad ID or MCP unavailable still reports the
specific error and stops, but auth failures follow the shared Linear MCP
contract by calling mcp__plugin_linear_linear__authenticate and continuing
through the browser login flow instead of dead-ending. Use the existing /prep
ticket validation/error handling path and the Linear auth handling in
entries/skills/ui-match/references/linear.md as the reference points when
adjusting the logic.
- Around line 61-84: The fenced example in SKILL.md is missing a language label,
so update the opening triple-backtick fence in the implementation plan template
to include a Markdown tag. Use the example block under the template section and
label the code fence with md (or text) so markdownlint no longer flags it.

In `@entries/skills/sanity-plugin-md-notes/AUTHORING.md`:
- Around line 1-5: The .help.md authoring document is missing the required YAML
frontmatter at the top, so update the opening of AUTHORING.md to start with the
repo’s expected frontmatter block before any markdown content. Keep the existing
guidance intact, but place the frontmatter first so the document matches the
format expected by the schema/help.md workflow and CI. Use the existing document
content as a reference and ensure the header is present consistently wherever
this template is used.

In `@entries/skills/sanity-plugin-md-notes/OPT-IN.md`:
- Around line 1-5: This file is missing the repository’s required YAML
frontmatter at the top, which is causing CI to fail. Update the OPT-IN.md
document so it begins with the expected frontmatter block before any markdown
content, preserving the existing help text below it. Use the existing markdown
file content as the body and add the frontmatter in the standard format used by
other docs in this repo.

In `@entries/skills/sanity-plugin-md-notes/SKILL.md`:
- Around line 1-4: The SKILL.md frontmatter for sanity-plugin-md-notes should
not include a name field because the linter already derives the skill name from
the file path and this is breaking CI. Remove the name entry from the
frontmatter at the top of SKILL.md, leaving the remaining metadata intact and
unchanged.

In `@entries/skills/sanity-plugin-md-notes/VITE.md`:
- Around line 1-5: The Vite checklist document is missing the required YAML
frontmatter at the top, which is causing CI to fail. Update VITE.md so it begins
with the repo’s expected frontmatter block before any markdown content, keeping
the existing checklist text underneath and ensuring the file structure matches
other entries in this documentation set.
- Around line 24-35: The sanity.cli.ts example is missing the import for
defineCliConfig, so the snippet cannot be copied and compiled as shown. Update
the example in the sanity.cli.ts configuration snippet to include
defineCliConfig from sanity/cli alongside sanityHelpVite, and keep the existing
defineCliConfig usage in the exported config so the example is self-contained.

In `@entries/skills/sanity-plugin-md-notes/WEBPACK.md`:
- Around line 1-5: This markdown file is missing the repo-required YAML
frontmatter at the top, which is causing CI to fail. Add the expected
frontmatter block before the existing "Webpack / Turbopack branch — install
checklist" content so the file matches the documentation format used elsewhere
in the repo.
- Around line 27-44: The next.config.ts example is missing the NextConfig type
import, so the snippet is not copy-pasteable as written. Add the missing
type-only import for NextConfig above the configuration example, and keep the
existing nextConfig declaration and webpack/turbopack blocks unchanged so the
snippet remains valid and self-contained.

In `@entries/skills/ship-pr/SKILL.md`:
- Around line 51-70: The Draft PR creation step is incomplete because `gh pr
create --draft` is invoked without the required ticket-derived metadata. Update
the Step 5 flow so the `gh pr create` call in `SKILL.md` explicitly passes the
generated PR title and heredoc body, following the documented `<ticket-id>:
<prefix>: <short description>` format and the exact body template; keep
backticks around code/component names and preserve the existing error handling
for `gh pr create` failures.

In `@entries/skills/ui-match/references/capture.md`:
- Line 1: The capture markdown file is missing the required YAML frontmatter at
the top, which is causing the memory-ci lint failure. Update the Capture &
segmentation document so it starts with frontmatter before the heading content,
keeping the existing markdown body intact; use the capture.md document structure
as the target location for this fix.

In `@entries/skills/ui-match/references/report.md`:
- Line 1: The report markdown is missing the required YAML frontmatter, causing
the memory-ci lint failure. Update the report document so it starts with the
expected frontmatter marker before any content, matching the format used by
capture.md and other lint-compliant reports. Make sure the existing
findings/report content remains below the frontmatter, and verify the file
begins with the required header using the report markdown structure.
- Around line 7-43: The markdown in the report section has missing blank lines
around headings and fenced code blocks, triggering MD022/MD031. Update the
content around the “## Schema” and “## Build + serve” sections so there is a
blank line before and after each heading and before and after each fenced block,
keeping the structure of the report intact.
- Around line 7-21: The schema example is missing the ticket integration fields
that the report generator already consumes, so update the
`/tmp/ui-match/$SLUG.findings.json` documentation to include `ticketUrl` and
`ticketKey` alongside the existing top-level properties. Reference the report
generator behavior via `ticket_banner()` and `rebuild_index()` so authors know
these optional fields are used for the header banner and index badge, and keep
the example aligned with the actual `findings.json` shape.

In `@entries/skills/ui-match/scripts/build_report.py`:
- Around line 10-21: The findings.json schema docstring is missing the ticketUrl
and ticketKey fields even though build_report.py uses them in ticket_banner()
and rebuild_index(). Update the schema description in this module to document
both fields alongside the existing top-level properties, keeping the naming
consistent with the symbols ticket_banner() and rebuild_index() so the
documented contract matches the code.
- Around line 103-151: The report writer in build_report.py uses a predictable
/tmp/ui-match default and writes output files using the raw slug from
findings.json, which can allow path tampering. Update the outdir handling in the
main report generation flow to use a safer temporary location or caller-provided
directory, and validate slug in the HTML/metadata write path so only the
expected url-safe identifier is accepted. Keep the fix centered around the
build_report logic that constructs html_path/meta paths and the slug value
before joining it into filenames.
- Around line 68-71: The report-building logic in build_report.py uses multiple
statements on single lines, which triggers Ruff E701. Split the conditional
append calls in the block that checks c["missing"], c["extra"], c["different"],
and c["matched"] into separate, properly indented lines so each if statement
contains its out.append call on its own line. Keep the behavior identical while
making the formatting compliant in build_report.py’s report generation section.
- Around line 179-184: The argument parsing in build_report.py uses an
unnecessary list comprehension and semicolon-joined statements, triggering Ruff
C416/E702. Update the command-line handling near the sys.argv setup to use a
simpler list conversion or direct slice for args, and split the combined
statements for outdir assignment and sys.exit into separate lines while keeping
the existing logic in place.

In `@entries/skills/ui-match/scripts/serve.py`:
- Around line 26-29: The opt() helper in serve.py should be made safe when a
flag is present without a following value and should avoid the chained one-liner
style that Ruff flags. Update opt() to explicitly check that the flag has a next
argument before accessing args[i+1], returning the default or a clear error when
the value is missing, and split the multiple statements in the function into
separate lines for readability and lint compliance.

In `@entries/skills/ui-match/SKILL.md`:
- Around line 1-4: Remove the name field from the skill frontmatter in the
ui-match SKILL.md metadata block, since the skill identifier is already derived
from the file path. Keep the existing description and any other frontmatter
entries intact, and update only the frontmatter section associated with the
ui-match skill so it passes validation.

---

Outside diff comments:
In `@entries/skills/json-ld/README.md`:
- Around line 1-85: The README in the JSON-LD skill currently starts with a
Markdown heading, which causes roboto-mem lint to fail before parsing the
document content. Add the required frontmatter at the top of this README or
relocate it outside the linted tree, and ensure the file’s opening structure
matches what the lint step expects while keeping the existing JSON-LD guidance
content intact.

In `@entries/skills/json-ld/rules/_sections.md`:
- Around line 1-12: The shared markdown file for rule categories is missing
required YAML frontmatter, which will cause the markdown linter to fail. Add the
standard frontmatter block at the top of this file, or if it is meant to be a
shared include rather than an entry, update the lint/configuration to exclude
this file from markdown entry checks. Use the `_sections.md` shared content as
the target when applying the fix.

In `@entries/skills/json-ld/rules/_template.md`:
- Around line 1-63: The template is placed under an unsupported entry scope, so
the lint/parser rejects it before the schema content can be used. Move this
template into one of the existing supported scopes recognized by roboto-mem
lint, or update the scope parser to accept entries/skills; also make the
frontmatter and placeholders in the _template.md match the repo’s entry schema
used by other entry templates.

In `@entries/skills/json-ld/rules/org-organization.md`:
- Around line 1-108: The Organization rule doc is under a directory that the
lint scope resolver does not recognize, so CI will keep failing for this
subtree. Either move this document into one of the linted commons scope
directories used by the scope derivation logic, or update the lint configuration
to explicitly exempt `entries/skills/json-ld/rules/*`; make the change in the
path/layout that the `roboto-mem lint` scope discovery uses so
`org-organization.md` is included or ignored intentionally.

In `@entries/skills/ui-match/README.md`:
- Around line 1-48: The README for ui-match is missing required YAML frontmatter
at the top, which is causing the repo lint failure. Update the document so it
begins with a valid frontmatter block before the existing heading, keeping the
current content intact below it. Use the ui-match README itself as the target
and preserve the existing sections and prose after the frontmatter.

In `@entries/skills/ui-match/references/capture.md`:
- Around line 41-77: The markdown in the capture instructions has lint issues
from missing blank lines around headings and fenced blocks, plus an unlabeled
code fence. Update the section around the “Try MCP first”, “Fallback”, “Find
precise boundaries, then crop”, and “Naming” headings so each heading and fence
has surrounding blank lines, and give the plain fenced snippet a language tag
such as text. Use the existing section structure in capture.md to keep the
formatting consistent.

In `@entries/skills/ui-match/references/linear.md`:
- Around line 1-114: The markdown file starts with a plain heading, causing the
lint failure to remain. Update the top of linear.md to include YAML frontmatter
before the existing content, matching the pattern already used in README.md, and
keep the rest of the document unchanged. Use the file’s opening section and its
existing heading as the anchor for where the frontmatter should be inserted.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 66fcd004-c9a8-4944-8838-3ed56d44f61e

📥 Commits

Reviewing files that changed from the base of the PR and between 80505ba and 687507b.

📒 Files selected for processing (41)
  • entries/skills/json-ld/AGENTS.md
  • entries/skills/json-ld/README.md
  • entries/skills/json-ld/SKILL.md
  • entries/skills/json-ld/metadata.json
  • entries/skills/json-ld/rules/_sections.md
  • entries/skills/json-ld/rules/_template.md
  • entries/skills/json-ld/rules/audit-project.md
  • entries/skills/json-ld/rules/content-article.md
  • entries/skills/json-ld/rules/content-blog-posting.md
  • entries/skills/json-ld/rules/content-course.md
  • entries/skills/json-ld/rules/content-event.md
  • entries/skills/json-ld/rules/content-job-posting.md
  • entries/skills/json-ld/rules/content-recipe.md
  • entries/skills/json-ld/rules/ecom-product.md
  • entries/skills/json-ld/rules/interactive-faq-page.md
  • entries/skills/json-ld/rules/interactive-howto.md
  • entries/skills/json-ld/rules/local-local-business.md
  • entries/skills/json-ld/rules/media-video-object.md
  • entries/skills/json-ld/rules/nav-breadcrumb-list.md
  • entries/skills/json-ld/rules/nav-site-navigation.md
  • entries/skills/json-ld/rules/nav-website.md
  • entries/skills/json-ld/rules/org-organization.md
  • entries/skills/json-ld/rules/org-person.md
  • entries/skills/json-ld/rules/org-service.md
  • entries/skills/prep/SKILL.md
  • entries/skills/sanity-plugin-md-notes/AUTHORING.md
  • entries/skills/sanity-plugin-md-notes/OPT-IN.md
  • entries/skills/sanity-plugin-md-notes/SKILL.md
  • entries/skills/sanity-plugin-md-notes/VITE.md
  • entries/skills/sanity-plugin-md-notes/WEBPACK.md
  • entries/skills/ship-pr/SKILL.md
  • entries/skills/ui-match/README.md
  • entries/skills/ui-match/SKILL.md
  • entries/skills/ui-match/metadata.json
  • entries/skills/ui-match/references/capture.md
  • entries/skills/ui-match/references/linear.md
  • entries/skills/ui-match/references/report.md
  • entries/skills/ui-match/scripts/build_report.py
  • entries/skills/ui-match/scripts/crop.sh
  • entries/skills/ui-match/scripts/serve.py
  • entries/skills/ui-match/scripts/site_sections.js

Comment on lines +1 to +7
# JSON-LD Structured Data — Agent Reference

> This document is optimized for AI agents and LLMs. For human overview, see SKILL.md.

## Prerequisites

```bash

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add the required YAML frontmatter here.

This file starts with a heading, but the repo’s markdown parser expects a --- frontmatter block first. As-is, it will fail CI unless this doc is moved out of the linted entries/ tree or given the supported header.

🧰 Tools
🪛 GitHub Actions: memory-ci / 0_lint.txt

[error] 1-1: Lint failed: Missing YAML frontmatter. file must start with ---

🪛 GitHub Actions: memory-ci / lint

[error] 1-1: Lint failed (node .roboto-mem/cli.mjs lint). Missing YAML frontmatter: file must start with ---

🤖 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 `@entries/skills/json-ld/AGENTS.md` around lines 1 - 7, Add the required YAML
frontmatter at the top of AGENTS.md so the markdown parser sees a supported
`---` block before any heading or prose. Update the JSON-LD Structured Data
agent reference header to start with frontmatter, keeping the existing content
below it, and ensure the file remains valid within the linted entries tree.

Source: Pipeline failures

Comment on lines +27 to +40
```tsx
import { Organization, WithContext } from 'schema-dts'

const jsonLd: WithContext<Organization> = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'My Company',
url: 'https://www.example.com',
logo: 'https://www.example.com/logo.png',
sameAs: [
'https://twitter.com/example',
'https://linkedin.com/company/example',
],
}

Copy link
Copy Markdown

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

Fix the quick-start logo example.

This snippet still uses a string URL for logo, but AGENTS.md documents the canonical Organization shape as an ImageObject with dimensions. Keeping both forms will teach users the wrong JSON-LD shape.

🤖 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 `@entries/skills/json-ld/README.md` around lines 27 - 40, The quick-start
Organization example uses the wrong `logo` shape, since it still shows a string
URL instead of the canonical `ImageObject` form documented in `AGENTS.md`.
Update the `jsonLd` example in the README so the `Organization` object’s `logo`
uses an `ImageObject` with the required fields and dimensions, keeping the rest
of the `WithContext<Organization>` snippet intact.

Comment on lines +1 to +6
---
title: JSON-LD Audit
impact: CRITICAL
impactDescription: discovers missing structured data across an entire Next.js project
tags: json-ld, schema, seo, audit, analysis, implementation-plan, routes
---

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Convert this to the repo’s supported entry format.

This file is being linted as an entry, but the skills scope is unknown and the frontmatter schema here (title/impact/...) does not match the parser’s required description/type/author/date contract.

🧰 Tools
🪛 GitHub Actions: memory-ci / 0_lint.txt

[error] 1-1: Lint failed: unknown scope directory: entries/skills/json-ld/rules/audit-project.md

🪛 GitHub Actions: memory-ci / lint

[error] 1-1: Lint failed (node .roboto-mem/cli.mjs lint). unknown scope directory: entries/skills/json-ld/rules/audit-project.md

🤖 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 `@entries/skills/json-ld/rules/audit-project.md` around lines 1 - 6, This
markdown file is using the wrong entry schema for the repository’s parser.
Update the frontmatter in the JSON-LD Audit entry to match the supported
contract by replacing the current title/impact fields with the required
description/type/author/date fields, and keep the content aligned with the entry
format used elsewhere in the repo. Ensure the entry is placed in a recognized
scope/category so it no longer fails linting as an unknown skills-scope entry.

Source: Pipeline failures

Comment on lines +65 to +74
instructor: {
'@type': 'Person',
name: course.instructor.name,
url: course.instructor.url,
},
hasCourseInstance: {
'@type': 'CourseInstance',
courseMode: 'online',
courseWorkload: course.duration,
},

Copy link
Copy Markdown

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
curl -s https://schema.org/instructor | sed -n '/Used on these types/,/Examples/p'
curl -s https://schema.org/CourseInstance | sed -n '/instructor/,/Examples/p'

Repository: robotostudio/team-memory

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="entries/skills/json-ld/rules/content-course.md"
wc -l "$file"
sed -n '50,90p' "$file" | cat -n

Repository: robotostudio/team-memory

Length of output: 1545


Move instructor under hasCourseInstance. instructor belongs on CourseInstance, not the top-level Course, so this example emits invalid schema.org markup.

Suggested fix
   const jsonLd: WithContext<Course> = {
     '`@context`': 'https://schema.org',
     '`@type`': 'Course',
     name: course.title,
     description: course.description,
     url: course.url,
     provider: {
       '`@type`': 'Organization',
       name: course.provider.name,
       sameAs: course.provider.url,
     },
-    instructor: {
-      '`@type`': 'Person',
-      name: course.instructor.name,
-      url: course.instructor.url,
-    },
     hasCourseInstance: {
       '`@type`': 'CourseInstance',
       courseMode: 'online',
       courseWorkload: course.duration,
+      instructor: {
+        '`@type`': 'Person',
+        name: course.instructor.name,
+        url: course.instructor.url,
+      },
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
instructor: {
'@type': 'Person',
name: course.instructor.name,
url: course.instructor.url,
},
hasCourseInstance: {
'@type': 'CourseInstance',
courseMode: 'online',
courseWorkload: course.duration,
},
hasCourseInstance: {
'`@type`': 'CourseInstance',
courseMode: 'online',
courseWorkload: course.duration,
instructor: {
'`@type`': 'Person',
name: course.instructor.name,
url: course.instructor.url,
},
},
🤖 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 `@entries/skills/json-ld/rules/content-course.md` around lines 65 - 74, The
JSON-LD example places instructor at the top-level Course object, which is
invalid schema.org markup. Move the instructor property into the
hasCourseInstance object in the content-course example so it belongs to the
CourseInstance alongside courseMode and courseWorkload, and keep the top-level
Course fields limited to Course-level properties.

Source: MCP tools

Comment on lines +1 to +6
---
title: Event
impact: LOW
impactDescription: displays event listing with date, location, and tickets in search
tags: json-ld, schema, seo, event, conference, meetup, concert
---

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

git ls-files | rg '(^|/)(\.roboto-mem|entries/skills/json-ld/rules/content-event\.md|memory-ci|cli\.mjs|scope|scop|frontmatter|entry|rules)'

Repository: robotostudio/team-memory

Length of output: 1201


🏁 Script executed:

sed -n '1,240p' .roboto-mem/cli.mjs

Repository: robotostudio/team-memory

Length of output: 8669


🏁 Script executed:

rg -n "unknown scope directory|scope directory|description|type|author|date|impactDescription|impact|title" .roboto-mem/cli.mjs entries/skills/json-ld/rules/_template.md entries/skills/json-ld/rules/content-event.md entries/skills/json-ld/rules/content-article.md entries/skills/json-ld/rules/audit-project.md

Repository: robotostudio/team-memory

Length of output: 50380


🏁 Script executed:

rg -n "unknown scope directory|scope directory|scope.*directory|recognized scope|scopes" .roboto-mem/cli.mjs .github/workflows/memory-ci.yml entries/org/scoped-diffs.md

Repository: robotostudio/team-memory

Length of output: 884


🏁 Script executed:

sed -n '2311,2355p' .roboto-mem/cli.mjs && printf '\n---\n' && sed -n '11720,11790p' .roboto-mem/cli.mjs && printf '\n---\n' && sed -n '1,120p' entries/org/scoped-diffs.md

Repository: robotostudio/team-memory

Length of output: 5380


Move this entry under a supported scope and use the required frontmatter.
entries/skills/json-ld/rules/ is not a recognized roboto-mem scope, so memory-ci will reject this file. If it’s meant to be an entry, it also needs description, type, author, and date frontmatter instead of title/impact/....

🧰 Tools
🪛 GitHub Actions: memory-ci / 0_lint.txt

[error] 1-1: Lint failed: unknown scope directory: entries/skills/json-ld/rules/content-event.md

🪛 GitHub Actions: memory-ci / lint

[error] 1-1: Lint failed (node .roboto-mem/cli.mjs lint). unknown scope directory: entries/skills/json-ld/rules/content-event.md

🤖 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 `@entries/skills/json-ld/rules/content-event.md` around lines 1 - 6, This entry
is in an unsupported scope and uses the wrong frontmatter shape, so move the
content into a recognized roboto-mem entry scope and replace the current Event
metadata with the required entry fields. Update the frontmatter in
content-event.md to use description, type, author, and date instead of title,
impact, impactDescription, and tags, and ensure the entry follows the
conventions used by other valid memory entries in this rules set.

Source: Pipeline failures

Comment on lines +68 to +71
if c["missing"]: out.append(f'<span class="pill red">🔴 {c["missing"]} missing on site</span>')
if c["extra"]: out.append(f'<span class="pill amber">🟡 {c["extra"]} extra on site</span>')
if c["different"]: out.append(f'<span class="pill violet">⚠️ {c["different"]} built differently</span>')
if c["matched"]: out.append(f'<span class="pill green">✅ {c["matched"]} matched</span>')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Lint: multi-statement lines flagged by Ruff (E701).

♻️ Proposed fix
 def pills(c):
     out = []
-    if c["missing"]:   out.append(f'<span class="pill red">🔴 {c["missing"]} missing on site</span>')
-    if c["extra"]:     out.append(f'<span class="pill amber">🟡 {c["extra"]} extra on site</span>')
-    if c["different"]: out.append(f'<span class="pill violet">⚠️ {c["different"]} built differently</span>')
-    if c["matched"]:   out.append(f'<span class="pill green">✅ {c["matched"]} matched</span>')
+    if c["missing"]:
+        out.append(f'<span class="pill red">🔴 {c["missing"]} missing on site</span>')
+    if c["extra"]:
+        out.append(f'<span class="pill amber">🟡 {c["extra"]} extra on site</span>')
+    if c["different"]:
+        out.append(f'<span class="pill violet">⚠️ {c["different"]} built differently</span>')
+    if c["matched"]:
+        out.append(f'<span class="pill green">✅ {c["matched"]} matched</span>')
     return "\n  ".join(out)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if c["missing"]: out.append(f'<span class="pill red">🔴 {c["missing"]} missing on site</span>')
if c["extra"]: out.append(f'<span class="pill amber">🟡 {c["extra"]} extra on site</span>')
if c["different"]: out.append(f'<span class="pill violet">⚠️ {c["different"]} built differently</span>')
if c["matched"]: out.append(f'<span class="pill green">✅ {c["matched"]} matched</span>')
def pills(c):
out = []
if c["missing"]:
out.append(f'<span class="pill red">🔴 {c["missing"]} missing on site</span>')
if c["extra"]:
out.append(f'<span class="pill amber">🟡 {c["extra"]} extra on site</span>')
if c["different"]:
out.append(f'<span class="pill violet">⚠️ {c["different"]} built differently</span>')
if c["matched"]:
out.append(f'<span class="pill green">✅ {c["matched"]} matched</span>')
return "\n ".join(out)
🧰 Tools
🪛 Ruff (0.15.20)

[error] 68-68: Multiple statements on one line (colon)

(E701)


[error] 69-69: Multiple statements on one line (colon)

(E701)


[error] 70-70: Multiple statements on one line (colon)

(E701)


[error] 71-71: Multiple statements on one line (colon)

(E701)

🤖 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 `@entries/skills/ui-match/scripts/build_report.py` around lines 68 - 71, The
report-building logic in build_report.py uses multiple statements on single
lines, which triggers Ruff E701. Split the conditional append calls in the block
that checks c["missing"], c["extra"], c["different"], and c["matched"] into
separate, properly indented lines so each if statement contains its out.append
call on its own line. Keep the behavior identical while making the formatting
compliant in build_report.py’s report generation section.

Source: Linters/SAST tools

Comment on lines +103 to +151
slug = f["slug"]
counts = {k: len(f.get(k, [])) for k in ("missing","extra","different","matched")}
parts = []
parts.append(f'''<!doctype html><html lang="en"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>{esc(f["page"])} — Figma ↔ Site parity</title><style>{CSS}</style></head><body>
<header>
<h1>{esc(f["page"])} — component parity: Figma vs live site</h1>
<div class="links">
<a href="{esc(f.get("figmaUrl","#"))}" target="_blank">Figma design ↗</a>
<a href="{esc(f.get("liveUrl","#"))}" target="_blank">Live site ↗</a>
</div>
{ticket_banner(f)}
</header>
<div class="summary">
{pills(counts)}
</div>
<main>''')

if f.get("missing"):
parts.append('<h2><span class="dot" style="background:var(--red)"></span>Missing on the live site '
'<span style="color:var(--mut);font-weight:400">— in Figma, not built → ticket</span></h2>')
parts.append('<p class="sub">These components exist in the Figma design but are not on the live page.</p>')
parts += [single_item("fig","FIGMA",it) for it in f["missing"]]

if f.get("extra"):
parts.append('<h2><span class="dot" style="background:var(--amber)"></span>Extra on the live site '
'<span style="color:var(--mut);font-weight:400">— live, but not in current Figma → confirm intended</span></h2>')
parts.append('<p class="sub">These are on the live page but do not appear in the Figma design.</p>')
parts += [single_item("site","LIVE SITE",it) for it in f["extra"]]

if f.get("different"):
parts.append('<h2><span class="dot" style="background:var(--violet)"></span>Matched, but built differently</h2>')
parts.append('<p class="sub">Present on both — same content, different component. Worth a design decision.</p>')
parts += [diff_item(it) for it in f["different"]]

if f.get("matched"):
parts.append('<h2><span class="dot" style="background:var(--green)"></span>'
f'Matched ({counts["matched"]})</h2>')
parts.append('<p class="sub">' + " · ".join(esc(m) for m in f["matched"]) + '</p>')

parts.append('</main></body></html>')
html_path = os.path.join(outdir, f"{slug}.html")
with open(html_path, "w") as fp:
fp.write("\n".join(parts))

meta = {"page": f["page"], "slug": slug, "counts": counts,
"figmaUrl": f.get("figmaUrl",""), "liveUrl": f.get("liveUrl",""),
"ticketUrl": f.get("ticketUrl",""), "ticketKey": f.get("ticketKey","")}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Hardcoded /tmp default and unsanitized slug used directly in output file paths.

Two related gaps flagged by static analysis:

  • Line 180: default outdir is the predictable, world-writable /tmp/ui-match (Ruff S108) — on a shared host this is susceptible to pre-creation/symlink tampering.
  • Lines 145/151: slug comes straight from findings.json content and is interpolated into os.path.join(outdir, f"{slug}.html")/f"{slug}.meta.json" with no validation that it's the "url-safe id" the schema comment promises — a crafted slug (e.g. containing ../) could write outside outdir.

Given this is a local agent-driven reporting tool (not network-facing), actual exploitability is low, but a cheap slug sanity-check would close the gap:

🛡️ Proposed hardening
+import re
+SLUG_RE = re.compile(r"^[a-z0-9-]+$")
+
 def build_report(f, outdir):
     slug = f["slug"]
+    if not SLUG_RE.match(slug):
+        raise ValueError(f"invalid slug: {slug!r} (must be [a-z0-9-]+)")

Also applies to: 180-180

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 145-145: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(html_path, "w")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)


[warning] 151-151: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(os.path.join(outdir, f"{slug}.meta.json"), "w")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

🤖 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 `@entries/skills/ui-match/scripts/build_report.py` around lines 103 - 151, The
report writer in build_report.py uses a predictable /tmp/ui-match default and
writes output files using the raw slug from findings.json, which can allow path
tampering. Update the outdir handling in the main report generation flow to use
a safer temporary location or caller-provided directory, and validate slug in
the HTML/metadata write path so only the expected url-safe identifier is
accepted. Keep the fix centered around the build_report logic that constructs
html_path/meta paths and the slug value before joining it into filenames.

Source: Linters/SAST tools

Comment on lines +179 to +184
args = [a for a in sys.argv[1:]]
outdir = "/tmp/ui-match"
if "--outdir" in args:
i = args.index("--outdir"); outdir = args[i+1]; del args[i:i+2]
if not args:
print("usage: build_report.py <findings.json> [--outdir DIR]"); sys.exit(1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Lint: unnecessary list comprehension and semicolon-joined statements (Ruff C416/E702).

♻️ Proposed fix
 def main():
-    args = [a for a in sys.argv[1:]]
+    args = list(sys.argv[1:])
     outdir = "/tmp/ui-match"
     if "--outdir" in args:
-        i = args.index("--outdir"); outdir = args[i+1]; del args[i:i+2]
+        i = args.index("--outdir")
+        outdir = args[i + 1]
+        del args[i:i + 2]
     if not args:
-        print("usage: build_report.py <findings.json> [--outdir DIR]"); sys.exit(1)
+        print("usage: build_report.py <findings.json> [--outdir DIR]")
+        sys.exit(1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
args = [a for a in sys.argv[1:]]
outdir = "/tmp/ui-match"
if "--outdir" in args:
i = args.index("--outdir"); outdir = args[i+1]; del args[i:i+2]
if not args:
print("usage: build_report.py <findings.json> [--outdir DIR]"); sys.exit(1)
args = list(sys.argv[1:])
outdir = "/tmp/ui-match"
if "--outdir" in args:
i = args.index("--outdir")
outdir = args[i + 1]
del args[i:i + 2]
if not args:
print("usage: build_report.py <findings.json> [--outdir DIR]")
sys.exit(1)
🧰 Tools
🪛 ast-grep (0.44.1)

[info] 179-179: Do not hardcode temporary file or directory names
Context: "/tmp/ui-match"
Note: [CWE-377] Insecure Temporary File.

(hardcoded-tmp-file)

🪛 Ruff (0.15.20)

[warning] 179-179: Unnecessary list comprehension (rewrite using list())

Rewrite using list()

(C416)


[error] 180-180: Probable insecure usage of temporary file or directory: "/tmp/ui-match"

(S108)


[error] 182-182: Multiple statements on one line (semicolon)

(E702)


[error] 182-182: Multiple statements on one line (semicolon)

(E702)


[error] 184-184: Multiple statements on one line (semicolon)

(E702)

🤖 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 `@entries/skills/ui-match/scripts/build_report.py` around lines 179 - 184, The
argument parsing in build_report.py uses an unnecessary list comprehension and
semicolon-joined statements, triggering Ruff C416/E702. Update the command-line
handling near the sys.argv setup to use a simpler list conversion or direct
slice for args, and split the combined statements for outdir assignment and
sys.exit into separate lines while keeping the existing logic in place.

Source: Linters/SAST tools

Comment on lines +26 to +29
def opt(flag, default):
if flag in args:
i = args.index(flag); v = args[i+1]; del args[i:i+2]; return v
return default

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Guard opt() against missing values.

--page or --port without a following argument will crash with IndexError, and the one-liner also trips Ruff E702.

Suggested fix
     def opt(flag, default):
         if flag in args:
-            i = args.index(flag); v = args[i+1]; del args[i:i+2]; return v
+            i = args.index(flag)
+            if i + 1 >= len(args):
+                return default
+            v = args[i + 1]
+            del args[i : i + 2]
+            return v
         return default
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def opt(flag, default):
if flag in args:
i = args.index(flag); v = args[i+1]; del args[i:i+2]; return v
return default
def opt(flag, default):
if flag in args:
i = args.index(flag)
if i + 1 >= len(args):
return default
v = args[i + 1]
del args[i : i + 2]
return v
return default
🧰 Tools
🪛 ast-grep (0.44.1)

[info] 29-29: Do not hardcode temporary file or directory names
Context: "/tmp/ui-match"
Note: [CWE-377] Insecure Temporary File.

(hardcoded-tmp-file)

🪛 Ruff (0.15.20)

[warning] 26-26: Missing return type annotation for private function opt

(ANN202)


[error] 28-28: Multiple statements on one line (semicolon)

(E702)


[error] 28-28: Multiple statements on one line (semicolon)

(E702)


[error] 28-28: Multiple statements on one line (semicolon)

(E702)

🤖 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 `@entries/skills/ui-match/scripts/serve.py` around lines 26 - 29, The opt()
helper in serve.py should be made safe when a flag is present without a
following value and should avoid the chained one-liner style that Ruff flags.
Update opt() to explicitly check that the flag has a next argument before
accessing args[i+1], returning the default or a clear error when the value is
missing, and split the multiple statements in the function into separate lines
for readability and lint compliance.

Source: Linters/SAST tools

Comment on lines +1 to +4
---
name: ui-match
description: Compares a page's Figma design against the live website and reports which components (page-builder blocks) are missing on the site, extra on the site, built differently, or matched — as a clickable HTML report with side-by-side screenshots, then optionally files one Linear ticket. Use when the user wants to check Figma-vs-live UI parity, find components that exist in Figma but are not built on the site (or vice-versa), "match Figma to the live site", audit design/build drift for a page, or invokes /ui-match.
---

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major

Remove name from the frontmatter.

The linter derives the skill name from the file path, so keeping this field causes validation to fail.

Suggested fix
 ---
-name: ui-match
 description: Compares a page's Figma design against the live website and reports which components (page-builder blocks) are missing on the site, extra on the site, built differently, or matched — as a clickable HTML report with side-by-side screenshots, then optionally files one Linear ticket. Use when the user wants to check Figma-vs-live UI parity, find components that exist in Figma but are not built on the site (or vice-versa), "match Figma to the live site", audit design/build drift for a page, or invokes /ui-match.
 ---
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---
name: ui-match
description: Compares a page's Figma design against the live website and reports which components (page-builder blocks) are missing on the site, extra on the site, built differently, or matched — as a clickable HTML report with side-by-side screenshots, then optionally files one Linear ticket. Use when the user wants to check Figma-vs-live UI parity, find components that exist in Figma but are not built on the site (or vice-versa), "match Figma to the live site", audit design/build drift for a page, or invokes /ui-match.
---
---
description: Compares a page's Figma design against the live website and reports which components (page-builder blocks) are missing on the site, extra on the site, built differently, or matched — as a clickable HTML report with side-by-side screenshots, then optionally files one Linear ticket. Use when the user wants to check Figma-vs-live UI parity, find components that exist in Figma but are not built on the site (or vice-versa), "match Figma to the live site", audit design/build drift for a page, or invokes /ui-match.
---
🧰 Tools
🪛 GitHub Actions: memory-ci / 0_lint.txt

[error] 1-1: Lint failed: 'name comes from the file path, not frontmatter'

🪛 GitHub Actions: memory-ci / lint

[error] 1-1: Lint failed (node .roboto-mem/cli.mjs lint). name comes from the file path, not frontmatter

🤖 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 `@entries/skills/ui-match/SKILL.md` around lines 1 - 4, Remove the name field
from the skill frontmatter in the ui-match SKILL.md metadata block, since the
skill identifier is already derived from the file path. Keep the existing
description and any other frontmatter entries intact, and update only the
frontmatter section associated with the ui-match skill so it passes validation.

Source: Pipeline failures

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