fix(ci): resolve cross-platform test failures#1039
Conversation
- Sanity check script (check-codex-global-state.sh) now falls back to grep -E when ripgrep is not available, fixing the codex-hooks sync test on all CI platforms. Patterns converted to POSIX ERE for portability. - Unicode safety test accepts both / and \ path separators so the executable-file assertion passes on Windows. - Gacha test sets PYTHONUTF8=1 so Python uses UTF-8 stdout encoding on Windows instead of cp1252, preventing UnicodeEncodeError on box-drawing characters. - Quoted-hook-path test skipped on Windows where NTFS disallows double-quote characters in filenames.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRefactors text-search in Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d728312b58
ℹ️ 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".
|
|
||
| if [[ -f "$AGENTS_FILE" ]]; then | ||
| if rg -n '^# Everything Claude Code \(ECC\) — Agent Instructions' "$AGENTS_FILE" >/dev/null 2>&1; then | ||
| if search_file '^# Everything Claude Code \(ECC\)' "$AGENTS_FILE"; then |
There was a problem hiding this comment.
Require exact ECC root heading in sanity check
The new regex ^# Everything Claude Code \(ECC\) is now prefix-only, so a truncated or altered AGENTS heading can still pass this validation. In this script’s post-sync regression role, that creates a false positive where AGENTS contains ECC root instructions is reported even when the canonical root instructions header is incomplete, which can hide a broken merge/state. Use a full-match pattern (or another strict invariant) so corrupted AGENTS content is detected reliably.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR hardens CI cross-platform reliability by fixing three root-cause test failures (missing
Confidence Score: 5/5Safe to merge — all changes are targeted cross-platform fixes with no logic regressions and no new risks introduced. All four CI fixes are correct and narrowly scoped. The search_file() fallback preserves exit-code semantics; POSIX ERE patterns are valid for both rg and grep -E; the Windows path-separator and encoding fixes are idiomatic; the Windows test skip correctly avoids inflating the failure counter. Supply-chain improvements are purely additive. No P0 or P1 findings. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[CI Test Runner] --> B{Platform?}
B -->|Windows| C[codex-hooks: skip quoted-path test]
B -->|Windows| D[gacha test: PYTHONUTF8=1 env var]
B -->|Windows| E[unicode test: path regex handles backslash]
B -->|Ubuntu / macOS| F[check-codex-global-state.sh]
F --> G{rg on PATH?}
G -->|Yes| H[search_file uses rg -n]
G -->|No| I[search_file uses grep -En]
H --> J[Patterns use POSIX ERE character classes]
I --> J
J --> K[Exit 0 if match / Exit 1 if not]
Reviews (6): Last reviewed commit: "fix: replace unicode arrows in lead-inte..." | Re-trigger Greptile |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
scripts/codex/check-codex-global-state.sh (1)
116-116: Escape section names before embedding them in regex patterns.
$sectionvalues include.characters, which are regex wildcards. That can allow unintended matches and mask malformed config sections. Consider escaping before building^\[$section\].Suggested hardening diff
+escape_ere() { + printf '%s' "$1" | sed 's/[][(){}.^$*+?|\\]/\\&/g' +} + for section in \ 'mcp_servers.github' \ 'mcp_servers.memory' \ 'mcp_servers.sequential-thinking' \ 'mcp_servers.context7' do - if search_file "^\[$section\]" "$CONFIG_FILE"; then + escaped_section="$(escape_ere "$section")" + if search_file "^\[$escaped_section\]" "$CONFIG_FILE"; then ok "MCP section [$section] exists" else fail "MCP section [$section] missing" fi done🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/codex/check-codex-global-state.sh` at line 116, The check embeds $section directly into the regex "^\[$section\]" which treats dots and other metacharacters as wildcards; update the code that calls search_file so it first escapes regex metacharacters in $section (e.g., via a small helper like escape_regex that backsslashes []\.^$*+?(){}| and so on, or by using a literal/ fixed-string search if search_file supports it), then use the escaped value when building the pattern (replace "^\[$section\]" with "^\[$escaped_section\]"), referencing the search_file call, the $section variable, and CONFIG_FILE in your change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@scripts/codex/check-codex-global-state.sh`:
- Line 116: The check embeds $section directly into the regex "^\[$section\]"
which treats dots and other metacharacters as wildcards; update the code that
calls search_file so it first escapes regex metacharacters in $section (e.g.,
via a small helper like escape_regex that backsslashes []\.^$*+?(){}| and so on,
or by using a literal/ fixed-string search if search_file supports it), then use
the escaped value when building the pattern (replace "^\[$section\]" with
"^\[$escaped_section\]"), referencing the search_file call, the $section
variable, and CONFIG_FILE in your change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cac034e7-33ad-4d75-b806-e500b6bafab5
📒 Files selected for processing (4)
scripts/codex/check-codex-global-state.shtests/scripts/check-unicode-safety.test.jstests/scripts/codex-hooks.test.jstests/scripts/openclaw-persona-forge-gacha.test.js
…files New skill: - remotion-video-creation: 29 domain-specific Remotion rules covering 3D/Three.js, animations, audio, captions, charts, compositions, fonts, GIFs, Lottie, measuring, sequencing, tailwind, text animations, timing, transitions, trimming, and video embedding. Ported from personal skills. Restored: - autonomous-agent-harness/SKILL.md (was in commit but missing from worktree) - lead-intelligence/ (full directory restored from branch commit) Updated: - manifests/install-modules.json: added remotion-video-creation to media-generation - README.md + AGENTS.md: synced counts to 139 skills Catalog validates: 30 agents, 60 commands, 139 skills.
|
Analysis Failed
Troubleshooting
Retry: |
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (3)
skills/lead-intelligence/agents/outreach-drafter.md (1)
16-16: Clarify expected input data format.Line 16 states the agent receives "enriched prospect profiles and warm path data" but doesn't specify the expected structure. Looking at the upstream agents, there's a potential format mismatch:
- enrichment-agent (from context snippet 1) outputs
Personalization Hooks: [text]as natural language- mutual-mapper (from context snippet 2) outputs
Via:,Relationship:,Suggested approach:- outreach-drafter output (lines 88-91) expects
Referenced:,Warm path:,Confidence:This creates an implicit requirement for the agent to parse natural language from enrichment-agent and transform field names from mutual-mapper. Consider either:
- Standardizing field names across all three agents, or
- Documenting the input format transformation requirements in this agent's Task section
📋 Suggested clarification
Add an "Input Format" section after line 16:
## Input Format Expects enriched profile data from `enrichment-agent` and warm path data from `mutual-mapper`: **From enrichment-agent:** - Person details (Title, Company, Location, X handle) - Company intel (Stage, Funding, Headcount, News) - Recent Activity (tweets/posts with dates) - Personalization Hooks (natural language text to parse) **From mutual-mapper:** - Target name and handle - Warm path(s) with: Via (mutual name/handle), Relationship (connection type), Suggested approach🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/lead-intelligence/agents/outreach-drafter.md` at line 16, Add an "Input Format" section right after the sentence about receiving "enriched prospect profiles and warm path data" that explicitly documents the expected structure and any transformation rules between upstream agents: enumerate fields produced by enrichment-agent (e.g., Person details, Company intel, Recent Activity, Personalization Hooks) and by mutual-mapper (e.g., Target name/handle, Via, Relationship, Suggested approach), and map how those natural-language fields must be parsed or renamed to the outreach-drafter's expected output fields (e.g., Referenced:, Warm path:, Confidence:) so the agent knows to parse "Personalization Hooks" text and convert mutual-mapper "Via/Relationship/Suggested approach" into the Warm path entries.skills/lead-intelligence/SKILL.md (1)
144-144: Minor: Hyphenate compound adjective.When "open source" modifies "contributions" as a compound adjective, it should be hyphenated: "open-source contributions".
📝 Proposed fix
-- GitHub: open source contributions (for developer-centric leads) +- GitHub: open-source contributions (for developer-centric leads)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/lead-intelligence/SKILL.md` at line 144, Replace the un-hyphenated phrase in the SKILL.md line "GitHub: open source contributions (for developer-centric leads)" with the hyphenated compound adjective form "open-source contributions" so it reads "GitHub: open-source contributions (for developer-centric leads)"; locate the string "GitHub: open source contributions (for developer-centric leads)" and update it accordingly.skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx (1)
20-32: Add fail-fast validation for timing parameters.At Line 20 and Line 52, invalid values like
charFrames <= 0orblinkFrames <= 0can cause broken math (frame % 0, divide-by-zero behavior) and hard-to-debug animation output. Add explicit guards with clear errors.As per coding guidelines "Fail fast with clear error messages when validation fails" and "Always handle errors explicitly at every level and never silently swallow errors".Proposed patch
const getTypedText = ({ frame, fullText, pauseAfter, charFrames, pauseFrames, }: { frame: number; fullText: string; pauseAfter: string; charFrames: number; pauseFrames: number; }): string => { + if (charFrames <= 0) { + throw new Error('charFrames must be greater than 0'); + } + if (pauseFrames < 0) { + throw new Error('pauseFrames must be greater than or equal to 0'); + } + const pauseIndex = fullText.indexOf(pauseAfter); const preLen = pauseIndex >= 0 ? pauseIndex + pauseAfter.length : fullText.length; @@ const Cursor: React.FC<{ frame: number; blinkFrames: number; symbol?: string; }> = ({frame, blinkFrames, symbol = '\u258C'}) => { + if (blinkFrames <= 0) { + throw new Error('blinkFrames must be greater than 0'); + } + const opacity = interpolate( frame % blinkFrames, [0, blinkFrames / 2, blinkFrames],Also applies to: 52-60
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx` around lines 20 - 32, Add fail-fast validation in getTypedText to guard against invalid timing parameters: check that charFrames and pauseFrames are positive integers and that pauseAfter is a valid index/range; if any check fails, throw a clear Error (e.g., "getTypedText: charFrames must be > 0, got X"). Also add the same validation for the cursor-blink routine that uses blinkFrames (the function handling blinkFrames around lines 52-60): ensure blinkFrames > 0 and throw a descriptive Error if not. Keep messages specific to the parameter and function name so failures point to the exact invalid value and location.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/remotion-video-creation/rules/charts.md`:
- Line 14: Update the documentation text to correct the two typos: change the
phrase "third party" in the sentence "Disable all animations by third party
libraries." to the compound adjective "third-party", and correct the misspelling
"implmentation" to "implementation" wherever it appears (notably the instance on
line 20) in the charts.md content.
- Line 20: Update the broken link in charts.md that points to
"assets/charts/bar-chart.tsx": change the path to the correct asset file name
"assets/charts-bar-chart.tsx" (remove the non-existent "charts/" subdirectory
and use the hyphenated filename) so the Bar Chart Example link resolves to the
existing asset.
In `@skills/remotion-video-creation/rules/display-captions.md`:
- Around line 8-126: Reorganize the document to match the required "When to
Use", "How It Works", and "Examples" sections: add a brief "When to Use" that
describes scenarios for caption display, move the "Prerequisites" and the
createTikTokStyleCaptions usage (including useMemo and SWITCH_CAPTIONS_EVERY_MS)
plus the Sequence rendering logic (pages, Sequence,
startFrame/endFrame/durationInFrames) into a combined "How It Works" section,
and place the word-highlighting example (CaptionPage, useCurrentFrame,
useVideoConfig, TikTokPage, page.tokens and token timing logic) into an
"Examples" section; preserve all technical details and referenced symbols
(createTikTokStyleCaptions, pages, SWITCH_CAPTIONS_EVERY_MS, Sequence,
CaptionPage, TikTokPage) and ensure headings are Markdown-formatted as required.
- Around line 109-121: The current React key uses token.fromMs which can
collide; update the map callback in page.tokens.map to accept the index
(map((token, idx) => ...)) and set a stable unique key combining fromMs with
either the index or token text (e.g., `${token.fromMs}-${idx}` or
`${token.fromMs}-${token.text}`) on the <span> so keys are deterministic and
unique (change reference to token.fromMs in the key prop).
In `@skills/remotion-video-creation/rules/extract-frames.md`:
- Around line 196-205: The timeout Promise can still reject after
extractFrames() wins the race; change the Promise.race usage so the timeout
timer is cleared when extractFrames resolves: capture the timeoutId created
inside timeoutPromise (or move timeoutId to an outer scope), then when invoking
Promise.race([extractFrames(), timeoutPromise]) attach a .then/.finally handler
on the successful extractFrames call (or wrap extractFrames in a small wrapper)
to call clearTimeout(timeoutId) and remove any listeners on controller.signal;
reference timeoutPromise, timeoutId, controller.signal, extractFrames(), and the
Promise.race call to locate where to add the clearTimeout on success.
- Around line 8-191: The document is missing the required skill-document
sections; add explicit "When to Use", "How It Works", and "Examples" headings to
the markdown around the existing content so it matches the skills/*.md
format—insert a "When to Use" section summarizing scenarios for extractFrames(),
a "How It Works" section describing the flow (Input,
computeDuration/getFormat/getPrimaryVideoTrack, timestamps resolution,
VideoSampleSink.samplesAtTimestamps, AbortSignal handling) and an "Examples"
section that includes the provided usage, filmstrip, and cancellation snippets
(referencing ExtractFramesProps, extractFrames, and VideoSampleSink) so the doc
validates against the required structure.
In `@skills/remotion-video-creation/rules/fonts.md`:
- Line 36: Fix the spelling in the Markdown sentence "Preferrably, specify only
needed weights and subsets to reduce file size:" by replacing "Preferrably" with
"Preferably" wherever that exact phrase appears (e.g., in the fonts.md content
string) so the user-facing docs read "Preferably, specify only needed weights
and subsets to reduce file size:".
- Around line 8-152: Add the three mandatory skill doc sections "When to Use",
"How It Works", and "Examples" to this markdown: create a "When to Use" section
under the top-level "Using fonts in Remotion" that explains scenarios for
choosing Google vs local fonts, a "How It Works" section that briefly describes
the APIs and flow (mention `@remotion/google-fonts` loadFont and waitUntilDone,
and `@remotion/fonts` loadFont with staticFile), and an "Examples" section that
includes short, focused examples already in the file (the Google Fonts snippets
using loadFont from `@remotion/google-fonts` and the local font snippets using
`@remotion/fonts` + staticFile) so the doc conforms to the skills/**/*.md required
structure.
In `@skills/remotion-video-creation/rules/tailwind.md`:
- Around line 7-11: The skill doc is missing the required sections; add clear
Markdown headings "When to Use", "How It Works", and "Examples" to
skills/remotion-video-creation/rules/tailwind.md; under "When to Use" state when
Tailwind in Remotion is appropriate, under "How It Works" describe that Tailwind
must be installed/enabled (fetch https://www.remotion.dev/docs/tailwind using
WebFetch) and explain the rule "Don't use transition-* or animate-*; always
animate using useCurrentFrame()", and under "Examples" show one or two concise
examples demonstrating Tailwind utility classes for styling combined with an
animation implemented via the useCurrentFrame() hook (reference useCurrentFrame
and Tailwind classes in the text).
---
Nitpick comments:
In `@skills/lead-intelligence/agents/outreach-drafter.md`:
- Line 16: Add an "Input Format" section right after the sentence about
receiving "enriched prospect profiles and warm path data" that explicitly
documents the expected structure and any transformation rules between upstream
agents: enumerate fields produced by enrichment-agent (e.g., Person details,
Company intel, Recent Activity, Personalization Hooks) and by mutual-mapper
(e.g., Target name/handle, Via, Relationship, Suggested approach), and map how
those natural-language fields must be parsed or renamed to the
outreach-drafter's expected output fields (e.g., Referenced:, Warm path:,
Confidence:) so the agent knows to parse "Personalization Hooks" text and
convert mutual-mapper "Via/Relationship/Suggested approach" into the Warm path
entries.
In `@skills/lead-intelligence/SKILL.md`:
- Line 144: Replace the un-hyphenated phrase in the SKILL.md line "GitHub: open
source contributions (for developer-centric leads)" with the hyphenated compound
adjective form "open-source contributions" so it reads "GitHub: open-source
contributions (for developer-centric leads)"; locate the string "GitHub: open
source contributions (for developer-centric leads)" and update it accordingly.
In `@skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx`:
- Around line 20-32: Add fail-fast validation in getTypedText to guard against
invalid timing parameters: check that charFrames and pauseFrames are positive
integers and that pauseAfter is a valid index/range; if any check fails, throw a
clear Error (e.g., "getTypedText: charFrames must be > 0, got X"). Also add the
same validation for the cursor-blink routine that uses blinkFrames (the function
handling blinkFrames around lines 52-60): ensure blinkFrames > 0 and throw a
descriptive Error if not. Keep messages specific to the parameter and function
name so failures point to the exact invalid value and location.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 482f5ee2-e4bb-4411-ba2d-94842cd52bdc
📒 Files selected for processing (41)
AGENTS.mdREADME.mdmanifests/install-modules.jsonskills/autonomous-agent-harness/SKILL.mdskills/lead-intelligence/SKILL.mdskills/lead-intelligence/agents/enrichment-agent.mdskills/lead-intelligence/agents/mutual-mapper.mdskills/lead-intelligence/agents/outreach-drafter.mdskills/lead-intelligence/agents/signal-scorer.mdskills/remotion-video-creation/SKILL.mdskills/remotion-video-creation/rules/3d.mdskills/remotion-video-creation/rules/animations.mdskills/remotion-video-creation/rules/assets.mdskills/remotion-video-creation/rules/assets/charts-bar-chart.tsxskills/remotion-video-creation/rules/assets/text-animations-typewriter.tsxskills/remotion-video-creation/rules/assets/text-animations-word-highlight.tsxskills/remotion-video-creation/rules/audio.mdskills/remotion-video-creation/rules/calculate-metadata.mdskills/remotion-video-creation/rules/can-decode.mdskills/remotion-video-creation/rules/charts.mdskills/remotion-video-creation/rules/compositions.mdskills/remotion-video-creation/rules/display-captions.mdskills/remotion-video-creation/rules/extract-frames.mdskills/remotion-video-creation/rules/fonts.mdskills/remotion-video-creation/rules/get-audio-duration.mdskills/remotion-video-creation/rules/get-video-dimensions.mdskills/remotion-video-creation/rules/get-video-duration.mdskills/remotion-video-creation/rules/gifs.mdskills/remotion-video-creation/rules/images.mdskills/remotion-video-creation/rules/import-srt-captions.mdskills/remotion-video-creation/rules/lottie.mdskills/remotion-video-creation/rules/measuring-dom-nodes.mdskills/remotion-video-creation/rules/measuring-text.mdskills/remotion-video-creation/rules/sequencing.mdskills/remotion-video-creation/rules/tailwind.mdskills/remotion-video-creation/rules/text-animations.mdskills/remotion-video-creation/rules/timing.mdskills/remotion-video-creation/rules/transcribe-captions.mdskills/remotion-video-creation/rules/transitions.mdskills/remotion-video-creation/rules/trimming.mdskills/remotion-video-creation/rules/videos.md
✅ Files skipped from review due to trivial changes (31)
- AGENTS.md
- manifests/install-modules.json
- skills/remotion-video-creation/rules/transitions.md
- skills/remotion-video-creation/rules/transcribe-captions.md
- skills/remotion-video-creation/SKILL.md
- skills/remotion-video-creation/rules/text-animations.md
- skills/remotion-video-creation/rules/get-audio-duration.md
- skills/remotion-video-creation/rules/trimming.md
- skills/remotion-video-creation/rules/measuring-text.md
- README.md
- skills/remotion-video-creation/rules/import-srt-captions.md
- skills/remotion-video-creation/rules/assets.md
- skills/remotion-video-creation/rules/sequencing.md
- skills/remotion-video-creation/rules/measuring-dom-nodes.md
- skills/remotion-video-creation/rules/get-video-dimensions.md
- skills/remotion-video-creation/rules/get-video-duration.md
- skills/remotion-video-creation/rules/lottie.md
- skills/lead-intelligence/agents/signal-scorer.md
- skills/lead-intelligence/agents/mutual-mapper.md
- skills/lead-intelligence/agents/enrichment-agent.md
- skills/remotion-video-creation/rules/can-decode.md
- skills/autonomous-agent-harness/SKILL.md
- skills/remotion-video-creation/rules/timing.md
- skills/remotion-video-creation/rules/3d.md
- skills/remotion-video-creation/rules/audio.md
- skills/remotion-video-creation/rules/animations.md
- skills/remotion-video-creation/rules/images.md
- skills/remotion-video-creation/rules/gifs.md
- skills/remotion-video-creation/rules/videos.md
- skills/remotion-video-creation/rules/compositions.md
- skills/remotion-video-creation/rules/calculate-metadata.md
|
|
||
| ## No animations not powered by `useCurrentFrame()` | ||
|
|
||
| Disable all animations by third party libraries. |
There was a problem hiding this comment.
Minor text issues flagged by static analysis.
- Line 14: "third party" → "third-party" (compound adjective)
- Line 20: "implmentation" → "implementation" (typo)
📝 Proposed fix
-Disable all animations by third party libraries.
+Disable all animations by third-party libraries. 📝 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.
| Disable all animations by third party libraries. | |
| Disable all animations by third-party libraries. |
🧰 Tools
🪛 LanguageTool
[grammar] ~14-~14: Use a hyphen to join words.
Context: ...rame()` Disable all animations by third party libraries. They will cause flick...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/charts.md` at line 14, Update the
documentation text to correct the two typos: change the phrase "third party" in
the sentence "Disable all animations by third party libraries." to the compound
adjective "third-party", and correct the misspelling "implmentation" to
"implementation" wherever it appears (notably the instance on line 20) in the
charts.md content.
|
|
||
| ## Bar Chart Animations | ||
|
|
||
| See [Bar Chart Example](assets/charts/bar-chart.tsx) for a basic example implmentation. |
There was a problem hiding this comment.
Broken link to bar chart example.
The link references assets/charts/bar-chart.tsx, but the actual asset file is assets/charts-bar-chart.tsx. This path has a non-existent charts/ subdirectory and incorrect filename.
📝 Proposed fix
-See [Bar Chart Example](assets/charts/bar-chart.tsx) for a basic example implmentation.
+See [Bar Chart Example](assets/charts-bar-chart.tsx) for a basic example implementation.📝 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.
| See [Bar Chart Example](assets/charts/bar-chart.tsx) for a basic example implmentation. | |
| See [Bar Chart Example](assets/charts-bar-chart.tsx) for a basic example implementation. |
🧰 Tools
🪛 LanguageTool
[grammar] ~20-~20: Ensure spelling is correct
Context: ...arts/bar-chart.tsx) for a basic example implmentation. ### Staggered Bars You can animate the heig...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/charts.md` at line 20, Update the broken
link in charts.md that points to "assets/charts/bar-chart.tsx": change the path
to the correct asset file name "assets/charts-bar-chart.tsx" (remove the
non-existent "charts/" subdirectory and use the hyphenated filename) so the Bar
Chart Example link resolves to the existing asset.
| # Displaying captions in Remotion | ||
|
|
||
| This guide explains how to display captions in Remotion, assuming you already have captions in the `Caption` format. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| First, the @remotion/captions package needs to be installed. | ||
| If it is not installed, use the following command: | ||
|
|
||
| ```bash | ||
| npx remotion add @remotion/captions # If project uses npm | ||
| bunx remotion add @remotion/captions # If project uses bun | ||
| yarn remotion add @remotion/captions # If project uses yarn | ||
| pnpm exec remotion add @remotion/captions # If project uses pnpm | ||
| ``` | ||
|
|
||
| ## Creating pages | ||
|
|
||
| Use `createTikTokStyleCaptions()` to group captions into pages. The `combineTokensWithinMilliseconds` option controls how many words appear at once: | ||
|
|
||
| ```tsx | ||
| import {useMemo} from 'react'; | ||
| import {createTikTokStyleCaptions} from '@remotion/captions'; | ||
| import type {Caption} from '@remotion/captions'; | ||
|
|
||
| // How often captions should switch (in milliseconds) | ||
| // Higher values = more words per page | ||
| // Lower values = fewer words (more word-by-word) | ||
| const SWITCH_CAPTIONS_EVERY_MS = 1200; | ||
|
|
||
| const {pages} = useMemo(() => { | ||
| return createTikTokStyleCaptions({ | ||
| captions, | ||
| combineTokensWithinMilliseconds: SWITCH_CAPTIONS_EVERY_MS, | ||
| }); | ||
| }, [captions]); | ||
| ``` | ||
|
|
||
| ## Rendering with Sequences | ||
|
|
||
| Map over the pages and render each one in a `<Sequence>`. Calculate the start frame and duration from the page timing: | ||
|
|
||
| ```tsx | ||
| import {Sequence, useVideoConfig, AbsoluteFill} from 'remotion'; | ||
| import type {TikTokPage} from '@remotion/captions'; | ||
|
|
||
| const CaptionedContent: React.FC = () => { | ||
| const {fps} = useVideoConfig(); | ||
|
|
||
| return ( | ||
| <AbsoluteFill> | ||
| {pages.map((page, index) => { | ||
| const nextPage = pages[index + 1] ?? null; | ||
| const startFrame = (page.startMs / 1000) * fps; | ||
| const endFrame = Math.min( | ||
| nextPage ? (nextPage.startMs / 1000) * fps : Infinity, | ||
| startFrame + (SWITCH_CAPTIONS_EVERY_MS / 1000) * fps, | ||
| ); | ||
| const durationInFrames = endFrame - startFrame; | ||
|
|
||
| if (durationInFrames <= 0) { | ||
| return null; | ||
| } | ||
|
|
||
| return ( | ||
| <Sequence | ||
| key={index} | ||
| from={startFrame} | ||
| durationInFrames={durationInFrames} | ||
| > | ||
| <CaptionPage page={page} /> | ||
| </Sequence> | ||
| ); | ||
| })} | ||
| </AbsoluteFill> | ||
| ); | ||
| }; | ||
| ``` | ||
|
|
||
| ## Word highlighting | ||
|
|
||
| A caption page contains `tokens` which you can use to highlight the currently spoken word: | ||
|
|
||
| ```tsx | ||
| import {AbsoluteFill, useCurrentFrame, useVideoConfig} from 'remotion'; | ||
| import type {TikTokPage} from '@remotion/captions'; | ||
|
|
||
| const HIGHLIGHT_COLOR = '#39E508'; | ||
|
|
||
| const CaptionPage: React.FC<{page: TikTokPage}> = ({page}) => { | ||
| const frame = useCurrentFrame(); | ||
| const {fps} = useVideoConfig(); | ||
|
|
||
| // Current time relative to the start of the sequence | ||
| const currentTimeMs = (frame / fps) * 1000; | ||
| // Convert to absolute time by adding the page start | ||
| const absoluteTimeMs = page.startMs + currentTimeMs; | ||
|
|
||
| return ( | ||
| <AbsoluteFill style={{justifyContent: 'center', alignItems: 'center'}}> | ||
| <div style={{fontSize: 80, fontWeight: 'bold', whiteSpace: 'pre'}}> | ||
| {page.tokens.map((token) => { | ||
| const isActive = | ||
| token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs; | ||
|
|
||
| return ( | ||
| <span | ||
| key={token.fromMs} | ||
| style={{color: isActive ? HIGHLIGHT_COLOR : 'white'}} | ||
| > | ||
| {token.text} | ||
| </span> | ||
| ); | ||
| })} | ||
| </div> | ||
| </AbsoluteFill> | ||
| ); | ||
| }; | ||
| ``` |
There was a problem hiding this comment.
Section structure violates coding guidelines.
The file uses sections "Prerequisites", "Creating pages", "Rendering with Sequences", and "Word highlighting", but the coding guidelines require: "When to Use, How It Works, and Examples".
Please reorganize the content to follow the required structure. As per coding guidelines: Skill format must be Markdown with clear sections for When to Use, How It Works, and Examples.
💡 Suggested section reorganization
Consider restructuring as:
- When to Use: Explain scenarios where caption display is needed (currently missing)
- How It Works: Cover the Prerequisites, TikTok-style page creation, and Sequence rendering (merge lines 12-85)
- Examples: Show the complete word highlighting example (lines 87-126)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/display-captions.md` around lines 8 -
126, Reorganize the document to match the required "When to Use", "How It
Works", and "Examples" sections: add a brief "When to Use" that describes
scenarios for caption display, move the "Prerequisites" and the
createTikTokStyleCaptions usage (including useMemo and SWITCH_CAPTIONS_EVERY_MS)
plus the Sequence rendering logic (pages, Sequence,
startFrame/endFrame/durationInFrames) into a combined "How It Works" section,
and place the word-highlighting example (CaptionPage, useCurrentFrame,
useVideoConfig, TikTokPage, page.tokens and token timing logic) into an
"Examples" section; preserve all technical details and referenced symbols
(createTikTokStyleCaptions, pages, SWITCH_CAPTIONS_EVERY_MS, Sequence,
CaptionPage, TikTokPage) and ensure headings are Markdown-formatted as required.
| {page.tokens.map((token) => { | ||
| const isActive = | ||
| token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs; | ||
|
|
||
| return ( | ||
| <span | ||
| key={token.fromMs} | ||
| style={{color: isActive ? HIGHLIGHT_COLOR : 'white'}} | ||
| > | ||
| {token.text} | ||
| </span> | ||
| ); | ||
| })} |
There was a problem hiding this comment.
Potential React key uniqueness issue.
Line 115 uses token.fromMs as the React key, but multiple tokens could theoretically start at the same millisecond, causing key collisions. Consider using the array index or a combination of fromMs and the token text for uniqueness.
🔑 Proposed fix for unique keys
{page.tokens.map((token) => {
const isActive =
token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs;
return (
<span
- key={token.fromMs}
+ key={`${token.fromMs}-${token.text}`}
style={{color: isActive ? HIGHLIGHT_COLOR : 'white'}}
>
{token.text}
</span>
);
})}Alternatively, if the token order is stable:
- {page.tokens.map((token) => {
+ {page.tokens.map((token, tokenIndex) => {
const isActive =
token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs;
return (
<span
- key={token.fromMs}
+ key={tokenIndex}
style={{color: isActive ? HIGHLIGHT_COLOR : 'white'}}
>
{token.text}
</span>
);
})}📝 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.
| {page.tokens.map((token) => { | |
| const isActive = | |
| token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs; | |
| return ( | |
| <span | |
| key={token.fromMs} | |
| style={{color: isActive ? HIGHLIGHT_COLOR : 'white'}} | |
| > | |
| {token.text} | |
| </span> | |
| ); | |
| })} | |
| {page.tokens.map((token) => { | |
| const isActive = | |
| token.fromMs <= absoluteTimeMs && token.toMs > absoluteTimeMs; | |
| return ( | |
| <span | |
| key={`${token.fromMs}-${token.text}`} | |
| style={{color: isActive ? HIGHLIGHT_COLOR : 'white'}} | |
| > | |
| {token.text} | |
| </span> | |
| ); | |
| })} |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/display-captions.md` around lines 109 -
121, The current React key uses token.fromMs which can collide; update the map
callback in page.tokens.map to accept the index (map((token, idx) => ...)) and
set a stable unique key combining fromMs with either the index or token text
(e.g., `${token.fromMs}-${idx}` or `${token.fromMs}-${token.text}`) on the
<span> so keys are deterministic and unique (change reference to token.fromMs in
the key prop).
| # Extracting frames from videos | ||
|
|
||
| Use Mediabunny to extract frames from videos at specific timestamps. This is useful for generating thumbnails, filmstrips, or processing individual frames. | ||
|
|
||
| ## The `extractFrames()` function | ||
|
|
||
| This function can be copy-pasted into any project. | ||
|
|
||
| ```tsx | ||
| import { | ||
| ALL_FORMATS, | ||
| Input, | ||
| UrlSource, | ||
| VideoSample, | ||
| VideoSampleSink, | ||
| } from "mediabunny"; | ||
|
|
||
| type Options = { | ||
| track: { width: number; height: number }; | ||
| container: string; | ||
| durationInSeconds: number | null; | ||
| }; | ||
|
|
||
| export type ExtractFramesTimestampsInSecondsFn = ( | ||
| options: Options | ||
| ) => Promise<number[]> | number[]; | ||
|
|
||
| export type ExtractFramesProps = { | ||
| src: string; | ||
| timestampsInSeconds: number[] | ExtractFramesTimestampsInSecondsFn; | ||
| onVideoSample: (sample: VideoSample) => void; | ||
| signal?: AbortSignal; | ||
| }; | ||
|
|
||
| export async function extractFrames({ | ||
| src, | ||
| timestampsInSeconds, | ||
| onVideoSample, | ||
| signal, | ||
| }: ExtractFramesProps): Promise<void> { | ||
| using input = new Input({ | ||
| formats: ALL_FORMATS, | ||
| source: new UrlSource(src), | ||
| }); | ||
|
|
||
| const [durationInSeconds, format, videoTrack] = await Promise.all([ | ||
| input.computeDuration(), | ||
| input.getFormat(), | ||
| input.getPrimaryVideoTrack(), | ||
| ]); | ||
|
|
||
| if (!videoTrack) { | ||
| throw new Error("No video track found in the input"); | ||
| } | ||
|
|
||
| if (signal?.aborted) { | ||
| throw new Error("Aborted"); | ||
| } | ||
|
|
||
| const timestamps = | ||
| typeof timestampsInSeconds === "function" | ||
| ? await timestampsInSeconds({ | ||
| track: { | ||
| width: videoTrack.displayWidth, | ||
| height: videoTrack.displayHeight, | ||
| }, | ||
| container: format.name, | ||
| durationInSeconds, | ||
| }) | ||
| : timestampsInSeconds; | ||
|
|
||
| if (timestamps.length === 0) { | ||
| return; | ||
| } | ||
|
|
||
| if (signal?.aborted) { | ||
| throw new Error("Aborted"); | ||
| } | ||
|
|
||
| const sink = new VideoSampleSink(videoTrack); | ||
|
|
||
| for await (using videoSample of sink.samplesAtTimestamps(timestamps)) { | ||
| if (signal?.aborted) { | ||
| break; | ||
| } | ||
|
|
||
| if (!videoSample) { | ||
| continue; | ||
| } | ||
|
|
||
| onVideoSample(videoSample); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Basic usage | ||
|
|
||
| Extract frames at specific timestamps: | ||
|
|
||
| ```tsx | ||
| await extractFrames({ | ||
| src: "https://remotion.media/video.mp4", | ||
| timestampsInSeconds: [0, 1, 2, 3, 4], | ||
| onVideoSample: (sample) => { | ||
| const canvas = document.createElement("canvas"); | ||
| canvas.width = sample.displayWidth; | ||
| canvas.height = sample.displayHeight; | ||
| const ctx = canvas.getContext("2d"); | ||
| sample.draw(ctx!, 0, 0); | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ## Creating a filmstrip | ||
|
|
||
| Use a callback function to dynamically calculate timestamps based on video metadata: | ||
|
|
||
| ```tsx | ||
| const canvasWidth = 500; | ||
| const canvasHeight = 80; | ||
| const fromSeconds = 0; | ||
| const toSeconds = 10; | ||
|
|
||
| await extractFrames({ | ||
| src: "https://remotion.media/video.mp4", | ||
| timestampsInSeconds: async ({ track, durationInSeconds }) => { | ||
| const aspectRatio = track.width / track.height; | ||
| const amountOfFramesFit = Math.ceil( | ||
| canvasWidth / (canvasHeight * aspectRatio) | ||
| ); | ||
| const segmentDuration = toSeconds - fromSeconds; | ||
| const timestamps: number[] = []; | ||
|
|
||
| for (let i = 0; i < amountOfFramesFit; i++) { | ||
| timestamps.push( | ||
| fromSeconds + (segmentDuration / amountOfFramesFit) * (i + 0.5) | ||
| ); | ||
| } | ||
|
|
||
| return timestamps; | ||
| }, | ||
| onVideoSample: (sample) => { | ||
| console.log(`Frame at ${sample.timestamp}s`); | ||
|
|
||
| const canvas = document.createElement("canvas"); | ||
| canvas.width = sample.displayWidth; | ||
| canvas.height = sample.displayHeight; | ||
| const ctx = canvas.getContext("2d"); | ||
| sample.draw(ctx!, 0, 0); | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ## Cancellation with AbortSignal | ||
|
|
||
| Cancel frame extraction after a timeout: | ||
|
|
||
| ```tsx | ||
| const controller = new AbortController(); | ||
|
|
||
| setTimeout(() => controller.abort(), 5000); | ||
|
|
||
| try { | ||
| await extractFrames({ | ||
| src: "https://remotion.media/video.mp4", | ||
| timestampsInSeconds: [0, 1, 2, 3, 4], | ||
| onVideoSample: (sample) => { | ||
| using frame = sample; | ||
| const canvas = document.createElement("canvas"); | ||
| canvas.width = frame.displayWidth; | ||
| canvas.height = frame.displayHeight; | ||
| const ctx = canvas.getContext("2d"); | ||
| frame.draw(ctx!, 0, 0); | ||
| }, | ||
| signal: controller.signal, | ||
| }); | ||
|
|
||
| console.log("Frame extraction complete!"); | ||
| } catch (error) { | ||
| console.error("Frame extraction was aborted or failed:", error); | ||
| } | ||
| ``` | ||
|
|
||
| ## Timeout with Promise.race |
There was a problem hiding this comment.
Missing required skill-document section structure.
This doc is well-written, but it does not include the required explicit sections When to Use, How It Works, and Examples.
📌 Suggested structure update
# Extracting frames from videos
Use Mediabunny to extract frames from videos at specific timestamps. This is useful for generating thumbnails, filmstrips, or processing individual frames.
+
+## When to Use
+
+- Generate thumbnails at fixed timestamps
+- Build filmstrips/previews
+- Run per-frame processing pipelines
+
+## How It Works
+
+1. Open input with Mediabunny
+2. Resolve duration/format/primary video track
+3. Resolve timestamps (array or callback)
+4. Iterate samples via `VideoSampleSink`
+5. Invoke `onVideoSample` for each frame (with abort support)
## The `extractFrames()` function
@@
-## Basic usage
+## Examples
+
+### Basic usage
@@
-## Creating a filmstrip
+### Creating a filmstrip
@@
-## Cancellation with AbortSignal
+### Cancellation with AbortSignal
@@
-## Timeout with Promise.race
+### Timeout with Promise.raceAs per coding guidelines, "skills/**/*.md: Skill format must be Markdown with clear sections for When to Use, How It Works, and Examples".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/extract-frames.md` around lines 8 - 191,
The document is missing the required skill-document sections; add explicit "When
to Use", "How It Works", and "Examples" headings to the markdown around the
existing content so it matches the skills/*.md format—insert a "When to Use"
section summarizing scenarios for extractFrames(), a "How It Works" section
describing the flow (Input, computeDuration/getFormat/getPrimaryVideoTrack,
timestamps resolution, VideoSampleSink.samplesAtTimestamps, AbortSignal
handling) and an "Examples" section that includes the provided usage, filmstrip,
and cancellation snippets (referencing ExtractFramesProps, extractFrames, and
VideoSampleSink) so the doc validates against the required structure.
| const timeoutPromise = new Promise<never>((_, reject) => { | ||
| const timeoutId = setTimeout(() => { | ||
| controller.abort(); | ||
| reject(new Error("Frame extraction timed out after 10 seconds")); | ||
| }, 10000); | ||
|
|
||
| controller.signal.addEventListener("abort", () => clearTimeout(timeoutId), { | ||
| once: true, | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Clear timeout on success to avoid delayed rejection from the raced promise.
In the timeout example, timeoutPromise can still reject later after extractFrames() resolves, because the timer is only cleared on abort.
✅ Safer Promise.race example
const controller = new AbortController();
+let timeoutId: ReturnType<typeof setTimeout> | undefined;
const timeoutPromise = new Promise<never>((_, reject) => {
- const timeoutId = setTimeout(() => {
+ timeoutId = setTimeout(() => {
controller.abort();
reject(new Error("Frame extraction timed out after 10 seconds"));
}, 10000);
controller.signal.addEventListener("abort", () => clearTimeout(timeoutId), {
once: true,
});
});
try {
await Promise.race([
@@
timeoutPromise,
]);
console.log("Frame extraction complete!");
} catch (error) {
console.error("Frame extraction was aborted or failed:", error);
+} finally {
+ if (timeoutId) clearTimeout(timeoutId);
}Also applies to: 207-223
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/extract-frames.md` around lines 196 -
205, The timeout Promise can still reject after extractFrames() wins the race;
change the Promise.race usage so the timeout timer is cleared when extractFrames
resolves: capture the timeoutId created inside timeoutPromise (or move timeoutId
to an outer scope), then when invoking Promise.race([extractFrames(),
timeoutPromise]) attach a .then/.finally handler on the successful extractFrames
call (or wrap extractFrames in a small wrapper) to call clearTimeout(timeoutId)
and remove any listeners on controller.signal; reference timeoutPromise,
timeoutId, controller.signal, extractFrames(), and the Promise.race call to
locate where to add the clearTimeout on success.
| # Using fonts in Remotion | ||
|
|
||
| ## Google Fonts with @remotion/google-fonts | ||
|
|
||
| The recommended way to use Google Fonts. It's type-safe and automatically blocks rendering until the font is ready. | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| First, the @remotion/google-fonts package needs to be installed. | ||
| If it is not installed, use the following command: | ||
|
|
||
| ```bash | ||
| npx remotion add @remotion/google-fonts # If project uses npm | ||
| bunx remotion add @remotion/google-fonts # If project uses bun | ||
| yarn remotion add @remotion/google-fonts # If project uses yarn | ||
| pnpm exec remotion add @remotion/google-fonts # If project uses pnpm | ||
| ``` | ||
|
|
||
| ```tsx | ||
| import { loadFont } from "@remotion/google-fonts/Lobster"; | ||
|
|
||
| const { fontFamily } = loadFont(); | ||
|
|
||
| export const MyComposition = () => { | ||
| return <div style={{ fontFamily }}>Hello World</div>; | ||
| }; | ||
| ``` | ||
|
|
||
| Preferrably, specify only needed weights and subsets to reduce file size: | ||
|
|
||
| ```tsx | ||
| import { loadFont } from "@remotion/google-fonts/Roboto"; | ||
|
|
||
| const { fontFamily } = loadFont("normal", { | ||
| weights: ["400", "700"], | ||
| subsets: ["latin"], | ||
| }); | ||
| ``` | ||
|
|
||
| ### Waiting for font to load | ||
|
|
||
| Use `waitUntilDone()` if you need to know when the font is ready: | ||
|
|
||
| ```tsx | ||
| import { loadFont } from "@remotion/google-fonts/Lobster"; | ||
|
|
||
| const { fontFamily, waitUntilDone } = loadFont(); | ||
|
|
||
| await waitUntilDone(); | ||
| ``` | ||
|
|
||
| ## Local fonts with @remotion/fonts | ||
|
|
||
| For local font files, use the `@remotion/fonts` package. | ||
|
|
||
| ### Prerequisites | ||
|
|
||
| First, install @remotion/fonts: | ||
|
|
||
| ```bash | ||
| npx remotion add @remotion/fonts # If project uses npm | ||
| bunx remotion add @remotion/fonts # If project uses bun | ||
| yarn remotion add @remotion/fonts # If project uses yarn | ||
| pnpm exec remotion add @remotion/fonts # If project uses pnpm | ||
| ``` | ||
|
|
||
| ### Loading a local font | ||
|
|
||
| Place your font file in the `public/` folder and use `loadFont()`: | ||
|
|
||
| ```tsx | ||
| import { loadFont } from "@remotion/fonts"; | ||
| import { staticFile } from "remotion"; | ||
|
|
||
| await loadFont({ | ||
| family: "MyFont", | ||
| url: staticFile("MyFont-Regular.woff2"), | ||
| }); | ||
|
|
||
| export const MyComposition = () => { | ||
| return <div style={{ fontFamily: "MyFont" }}>Hello World</div>; | ||
| }; | ||
| ``` | ||
|
|
||
| ### Loading multiple weights | ||
|
|
||
| Load each weight separately with the same family name: | ||
|
|
||
| ```tsx | ||
| import { loadFont } from "@remotion/fonts"; | ||
| import { staticFile } from "remotion"; | ||
|
|
||
| await Promise.all([ | ||
| loadFont({ | ||
| family: "Inter", | ||
| url: staticFile("Inter-Regular.woff2"), | ||
| weight: "400", | ||
| }), | ||
| loadFont({ | ||
| family: "Inter", | ||
| url: staticFile("Inter-Bold.woff2"), | ||
| weight: "700", | ||
| }), | ||
| ]); | ||
| ``` | ||
|
|
||
| ### Available options | ||
|
|
||
| ```tsx | ||
| loadFont({ | ||
| family: "MyFont", // Required: name to use in CSS | ||
| url: staticFile("font.woff2"), // Required: font file URL | ||
| format: "woff2", // Optional: auto-detected from extension | ||
| weight: "400", // Optional: font weight | ||
| style: "normal", // Optional: normal or italic | ||
| display: "block", // Optional: font-display behavior | ||
| }); | ||
| ``` | ||
|
|
||
| ## Using in components | ||
|
|
||
| Call `loadFont()` at the top level of your component or in a separate file that's imported early: | ||
|
|
||
| ```tsx | ||
| import { loadFont } from "@remotion/google-fonts/Montserrat"; | ||
|
|
||
| const { fontFamily } = loadFont("normal", { | ||
| weights: ["400", "700"], | ||
| subsets: ["latin"], | ||
| }); | ||
|
|
||
| export const Title: React.FC<{ text: string }> = ({ text }) => { | ||
| return ( | ||
| <h1 | ||
| style={{ | ||
| fontFamily, | ||
| fontSize: 80, | ||
| fontWeight: "bold", | ||
| }} | ||
| > | ||
| {text} | ||
| </h1> | ||
| ); | ||
| }; | ||
| ``` |
There was a problem hiding this comment.
Add required skill sections (When to Use, How It Works, Examples).
This file is well-written, but it does not use the mandatory section structure required for skill docs. Please add clearly named sections for all three required headings.
As per coding guidelines, skills/**/*.md: "Skill format must be Markdown with clear sections for When to Use, How It Works, and Examples".
🧰 Tools
🪛 LanguageTool
[grammar] ~35-~35: Ensure spelling is correct
Context: ...ontFamily }}>Hello World; }; ``` Preferrably, specify only needed weights and subset...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/fonts.md` around lines 8 - 152, Add the
three mandatory skill doc sections "When to Use", "How It Works", and "Examples"
to this markdown: create a "When to Use" section under the top-level "Using
fonts in Remotion" that explains scenarios for choosing Google vs local fonts, a
"How It Works" section that briefly describes the APIs and flow (mention
`@remotion/google-fonts` loadFont and waitUntilDone, and `@remotion/fonts` loadFont
with staticFile), and an "Examples" section that includes short, focused
examples already in the file (the Google Fonts snippets using loadFont from
`@remotion/google-fonts` and the local font snippets using `@remotion/fonts` +
staticFile) so the doc conforms to the skills/**/*.md required structure.
| }; | ||
| ``` | ||
|
|
||
| Preferrably, specify only needed weights and subsets to reduce file size: |
There was a problem hiding this comment.
Fix typo: “Preferrably” → “Preferably”.
Small spelling issue in user-facing docs.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/fonts.md` at line 36, Fix the spelling
in the Markdown sentence "Preferrably, specify only needed weights and subsets
to reduce file size:" by replacing "Preferrably" with "Preferably" wherever that
exact phrase appears (e.g., in the fonts.md content string) so the user-facing
docs read "Preferably, specify only needed weights and subsets to reduce file
size:".
| You can and should use TailwindCSS in Remotion, if TailwindCSS is installed in the project. | ||
|
|
||
| Don't use `transition-*` or `animate-*` classes - always animate using the `useCurrentFrame()` hook. | ||
|
|
||
| Tailwind must be installed and enabled first in a Remotion project - fetch https://www.remotion.dev/docs/tailwind using WebFetch for instructions. No newline at end of file |
There was a problem hiding this comment.
Add the required skill sections (When to Use, How It Works, Examples).
This new skill doc is missing the required section structure for skills/**/*.md.
Proposed structure update
-You can and should use TailwindCSS in Remotion, if TailwindCSS is installed in the project.
-
-Don't use `transition-*` or `animate-*` classes - always animate using the `useCurrentFrame()` hook.
-
-Tailwind must be installed and enabled first in a Remotion project - fetch https://www.remotion.dev/docs/tailwind using WebFetch for instructions.
+## When to Use
+
+Use TailwindCSS in Remotion projects only when Tailwind is already installed and enabled.
+
+## How It Works
+
+- Tailwind utility classes are allowed for styling.
+- Do **not** use `transition-*` or `animate-*` classes.
+- Drive animation values using Remotion’s `useCurrentFrame()` hook.
+
+## Examples
+
+- ✅ Static styling with Tailwind utility classes.
+- ✅ Frame-driven animation logic via `useCurrentFrame()`.
+- ❌ Tailwind `transition-*` or `animate-*` classes for motion.
+
+For setup instructions, fetch https://www.remotion.dev/docs/tailwind using WebFetch.As per coding guidelines, skills/**/*.md: Skill format must be Markdown with clear sections for When to Use, How It Works, and Examples.
📝 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.
| You can and should use TailwindCSS in Remotion, if TailwindCSS is installed in the project. | |
| Don't use `transition-*` or `animate-*` classes - always animate using the `useCurrentFrame()` hook. | |
| Tailwind must be installed and enabled first in a Remotion project - fetch https://www.remotion.dev/docs/tailwind using WebFetch for instructions. | |
| ## When to Use | |
| Use TailwindCSS in Remotion projects only when Tailwind is already installed and enabled. | |
| ## How It Works | |
| - Tailwind utility classes are allowed for styling. | |
| - Do **not** use `transition-*` or `animate-*` classes. | |
| - Drive animation values using Remotion's `useCurrentFrame()` hook. | |
| ## Examples | |
| - ✅ Static styling with Tailwind utility classes. | |
| - ✅ Frame-driven animation logic via `useCurrentFrame()`. | |
| - ❌ Tailwind `transition-*` or `animate-*` classes for motion. | |
| For setup instructions, fetch https://www.remotion.dev/docs/tailwind using WebFetch. |
🧰 Tools
🪛 LanguageTool
[grammar] ~7-~7: Ensure spelling is correct
Context: ... should use TailwindCSS in Remotion, if TailwindCSS is installed in the project. Don't use...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/remotion-video-creation/rules/tailwind.md` around lines 7 - 11, The
skill doc is missing the required sections; add clear Markdown headings "When to
Use", "How It Works", and "Examples" to
skills/remotion-video-creation/rules/tailwind.md; under "When to Use" state when
Tailwind in Remotion is appropriate, under "How It Works" describe that Tailwind
must be installed/enabled (fetch https://www.remotion.dev/docs/tailwind using
WebFetch) and explain the rule "Don't use transition-* or animate-*; always
animate using useCurrentFrame()", and under "Examples" show one or two concise
examples demonstrating Tailwind utility classes for styling combined with an
animation implemented via the useCurrentFrame() hook (reference useCurrentFrame
and Tailwind classes in the text).
There was a problem hiding this comment.
6 issues found across 41 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="skills/remotion-video-creation/rules/animations.md">
<violation number="1" location="skills/remotion-video-creation/rules/animations.md:12">
P3: The example code uses `useVideoConfig` and `interpolate` without importing them, so the snippet won’t compile as written. Include the missing imports so readers can copy/paste it successfully.</violation>
</file>
<file name="skills/remotion-video-creation/rules/videos.md">
<violation number="1" location="skills/remotion-video-creation/rules/videos.md:41">
P2: The trimming section says `trimBefore`/`trimAfter` are in seconds, but the example (and the audio guide) treats them as frame counts (`2 * fps`). This inconsistency will mislead readers about the expected units.</violation>
</file>
<file name="skills/remotion-video-creation/SKILL.md">
<violation number="1" location="skills/remotion-video-creation/SKILL.md:16">
P2: These rule links point to files that don’t exist in the repo, so readers will hit broken links. Add the referenced rule files or update the links to the correct locations.</violation>
</file>
<file name="skills/autonomous-agent-harness/SKILL.md">
<violation number="1" location="skills/autonomous-agent-harness/SKILL.md:11">
P3: Use the standard skill section name “When to Use” so this skill follows the documented format and stays consistent with other skills.</violation>
</file>
<file name="skills/remotion-video-creation/rules/trimming.md">
<violation number="1" location="skills/remotion-video-creation/rules/trimming.md:17">
P2: `useVideoConfig()` returns a config object; assigning it directly to `fps` makes the arithmetic in this example evaluate to `NaN`. Destructure `fps` from the config like the other Remotion examples.</violation>
</file>
<file name="skills/remotion-video-creation/rules/extract-frames.md">
<violation number="1" location="skills/remotion-video-creation/rules/extract-frames.md:91">
P2: Abort inside the sample loop only breaks and resolves successfully, so callers can’t detect cancellation (the try/catch example will log completion even when aborted). Throw on abort in the loop to match the earlier abort checks and the documented behavior.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
|
|
||
| ## Trimming | ||
|
|
||
| Use `trimBefore` and `trimAfter` to remove portions of the video. Values are in seconds. |
There was a problem hiding this comment.
P2: The trimming section says trimBefore/trimAfter are in seconds, but the example (and the audio guide) treats them as frame counts (2 * fps). This inconsistency will mislead readers about the expected units.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At skills/remotion-video-creation/rules/videos.md, line 41:
<comment>The trimming section says `trimBefore`/`trimAfter` are in seconds, but the example (and the audio guide) treats them as frame counts (`2 * fps`). This inconsistency will mislead readers about the expected units.</comment>
<file context>
@@ -0,0 +1,171 @@
+
+## Trimming
+
+Use `trimBefore` and `trimAfter` to remove portions of the video. Values are in seconds.
+
+```tsx
</file context>
| Use `trimBefore` and `trimAfter` to remove portions of the video. Values are in seconds. | |
| Use `trimBefore` and `trimAfter` to remove portions of the video. Values are in frames. |
|
|
||
| Read individual rule files for detailed explanations and code examples: | ||
|
|
||
| - [rules/3d.md](rules/3d.md) - 3D content in Remotion using Three.js and React Three Fiber |
There was a problem hiding this comment.
P2: These rule links point to files that don’t exist in the repo, so readers will hit broken links. Add the referenced rule files or update the links to the correct locations.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At skills/remotion-video-creation/SKILL.md, line 16:
<comment>These rule links point to files that don’t exist in the repo, so readers will hit broken links. Add the referenced rule files or update the links to the correct locations.</comment>
<file context>
@@ -0,0 +1,43 @@
+
+Read individual rule files for detailed explanations and code examples:
+
+- [rules/3d.md](rules/3d.md) - 3D content in Remotion using Three.js and React Three Fiber
+- [rules/animations.md](rules/animations.md) - Fundamental animation skills for Remotion
+- [rules/assets.md](rules/assets.md) - Importing images, videos, audio, and fonts into Remotion
</file context>
| ```tsx | ||
| import { Sequence, useVideoConfig } from "remotion"; | ||
|
|
||
| const fps = useVideoConfig(); |
There was a problem hiding this comment.
P2: useVideoConfig() returns a config object; assigning it directly to fps makes the arithmetic in this example evaluate to NaN. Destructure fps from the config like the other Remotion examples.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At skills/remotion-video-creation/rules/trimming.md, line 17:
<comment>`useVideoConfig()` returns a config object; assigning it directly to `fps` makes the arithmetic in this example evaluate to `NaN`. Destructure `fps` from the config like the other Remotion examples.</comment>
<file context>
@@ -0,0 +1,53 @@
+```tsx
+import { Sequence, useVideoConfig } from "remotion";
+
+const fps = useVideoConfig();
+
+<Sequence from={-0.5 * fps}>
</file context>
|
|
||
| for await (using videoSample of sink.samplesAtTimestamps(timestamps)) { | ||
| if (signal?.aborted) { | ||
| break; |
There was a problem hiding this comment.
P2: Abort inside the sample loop only breaks and resolves successfully, so callers can’t detect cancellation (the try/catch example will log completion even when aborted). Throw on abort in the loop to match the earlier abort checks and the documented behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At skills/remotion-video-creation/rules/extract-frames.md, line 91:
<comment>Abort inside the sample loop only breaks and resolves successfully, so callers can’t detect cancellation (the try/catch example will log completion even when aborted). Throw on abort in the loop to match the earlier abort checks and the documented behavior.</comment>
<file context>
@@ -0,0 +1,229 @@
+
+ for await (using videoSample of sink.samplesAtTimestamps(timestamps)) {
+ if (signal?.aborted) {
+ break;
+ }
+
</file context>
| Write animations in seconds and multiply them by the `fps` value from `useVideoConfig()`. | ||
|
|
||
| ```tsx | ||
| import { useCurrentFrame } from "remotion"; |
There was a problem hiding this comment.
P3: The example code uses useVideoConfig and interpolate without importing them, so the snippet won’t compile as written. Include the missing imports so readers can copy/paste it successfully.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At skills/remotion-video-creation/rules/animations.md, line 12:
<comment>The example code uses `useVideoConfig` and `interpolate` without importing them, so the snippet won’t compile as written. Include the missing imports so readers can copy/paste it successfully.</comment>
<file context>
@@ -0,0 +1,29 @@
+Write animations in seconds and multiply them by the `fps` value from `useVideoConfig()`.
+
+```tsx
+import { useCurrentFrame } from "remotion";
+
+export const FadeIn = () => {
</file context>
|
|
||
| Turn Claude Code into a persistent, self-directing agent system using only native features and MCP servers. | ||
|
|
||
| ## When to Activate |
There was a problem hiding this comment.
P3: Use the standard skill section name “When to Use” so this skill follows the documented format and stays consistent with other skills.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At skills/autonomous-agent-harness/SKILL.md, line 11:
<comment>Use the standard skill section name “When to Use” so this skill follows the documented format and stays consistent with other skills.</comment>
<file context>
@@ -0,0 +1,267 @@
+
+Turn Claude Code into a persistent, self-directing agent system using only native features and MCP servers.
+
+## When to Activate
+
+- User wants an agent that runs continuously or on a schedule
</file context>
…ript SHA Critical: - Pin all npx -y MCP server packages to specific versions in .mcp.json to prevent supply chain attacks via version hijacking: - @modelcontextprotocol/server-github@2025.4.8 - @modelcontextprotocol/server-memory@2026.1.26 - @modelcontextprotocol/server-sequential-thinking@2025.12.18 - @playwright/mcp@0.0.69 (was 0.0.68) Medium: - Add .github/dependabot.yml for weekly npm + github-actions updates with grouped minor/patch PRs - Pin actions/github-script to SHA (was @v7 tag, now pinned to commit)
|
Analysis Failed
Troubleshooting
Retry: |
New skill: social-graph-ranker - Weighted social graph traversal with exponential decay across hops - Bridge Score: B(m) = Σ w(t) · λ^(d(m,t)-1) ranks mutuals by target proximity - Extended Score incorporates 2nd-order network (mutual-of-mutual connections) - Final ranking includes engagement bonus for responsive connections - Runs in parallel with lead-intelligence skill for combined warm+cold outreach - Supports X API + LinkedIn CSV for graph harvesting - Outputs tiered action list: warm intros, direct outreach, network gap analysis Added to business-content install module. Catalog validates: 30/60/140.
|
Analysis Failed
Troubleshooting
Retry: |
Applied npm audit fix --force to resolve: - minimatch ReDoS (3 vulnerabilities, HIGH) - smol-toml DoS (MODERATE) - brace-expansion memory exhaustion (MODERATE) - markdownlint-cli upgraded from 0.47.0 to 0.48.0 npm audit now reports 0 vulnerabilities.
|
Analysis Failed
Troubleshooting
Retry: |
- MD047: ensure single trailing newline on all remotion rule files - MD012: remove consecutive blank lines in lottie, measuring-dom-nodes, trimming - MD034: wrap bare URLs in angle brackets (tailwind, transcribe-captions) - yarn.lock: regenerated to sync with npm audit changes in package.json
|
Analysis Failed
Troubleshooting
Retry: |
|
Analysis Failed
Troubleshooting
Retry: |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
skills/remotion-video-creation/rules/tailwind.md (1)
7-11:⚠️ Potential issue | 🟠 MajorAdd the required skill sections (
When to Use,How It Works,Examples).This skill document still lacks the required structural sections. As per coding guidelines,
skills/**/*.mdmust include clear Markdown sections for When to Use, How It Works, and Examples.📝 Proposed restructure
-You can and should use TailwindCSS in Remotion, if TailwindCSS is installed in the project. - -Don't use `transition-*` or `animate-*` classes - always animate using the `useCurrentFrame()` hook. - -Tailwind must be installed and enabled first in a Remotion project - fetch https://www.remotion.dev/docs/tailwind using WebFetch for instructions. +## When to Use + +Use TailwindCSS in Remotion projects when Tailwind is already installed and enabled in the project. + +## How It Works + +- Tailwind must be installed and enabled first. Fetch https://www.remotion.dev/docs/tailwind using WebFetch for setup instructions. +- Use Tailwind utility classes for styling. +- **Do not** use `transition-*` or `animate-*` classes. +- Always animate using Remotion's `useCurrentFrame()` hook instead. + +## Examples + +```tsx +// ✅ Correct: Tailwind for styling, useCurrentFrame() for animation +import { useCurrentFrame } from 'remotion'; + +export const AnimatedBox = () => { + const frame = useCurrentFrame(); + const opacity = Math.min(1, frame / 30); + + return ( + <div + className="w-64 h-64 bg-blue-500 rounded-lg" + style={{ opacity }} + > + Content + </div> + ); +}; + +// ❌ Wrong: Using Tailwind animation classes +<div className="animate-pulse bg-blue-500">Don't do this</div> +```🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/remotion-video-creation/rules/tailwind.md` around lines 7 - 11, Add the required Markdown sections "When to Use", "How It Works", and "Examples" to skills/remotion-video-creation/rules/tailwind.md; in "When to Use" state that Tailwind is suitable for styling in Remotion projects (only if Tailwind is installed/enabled), in "How It Works" explain that animations must rely on Remotion's useCurrentFrame() hook rather than Tailwind's transition-* or animate-* classes, and in "Examples" include the proposed correct example referencing the AnimatedBox component and useCurrentFrame() and a short "Don't do this" note showing animate-* usage so readers see both the correct pattern (useCurrentFrame → inline style opacity) and the incorrect pattern (Tailwind animate-*).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@skills/lead-intelligence/SKILL.md`:
- Line 144: Update the phrase in the SKILL.md content where it currently reads
"GitHub: open source contributions (for developer-centric leads)" to use the
hyphenated compound adjective "open-source contributions" so it becomes "GitHub:
open-source contributions (for developer-centric leads)"; locate this exact
string and replace the unhyphenated form with the hyphenated form to improve
clarity.
- Around line 11-31: Rename the section headings to match the required skill
schema: change "When to Activate" to "When to Use", change "Pipeline Overview"
to "How It Works", and change any "Example Usage" or similar to "Examples"
(update the exact strings "When to Activate", "Pipeline Overview", and "Example
Usage"/"Example" wherever they appear in SKILL.md, including the referenced
later occurrence around line 210). Ensure the Tool Requirements and content
under Required/Optional remain unchanged and update any internal links or
references that point to the old headings so documentation and machine checks
keep working.
---
Duplicate comments:
In `@skills/remotion-video-creation/rules/tailwind.md`:
- Around line 7-11: Add the required Markdown sections "When to Use", "How It
Works", and "Examples" to skills/remotion-video-creation/rules/tailwind.md; in
"When to Use" state that Tailwind is suitable for styling in Remotion projects
(only if Tailwind is installed/enabled), in "How It Works" explain that
animations must rely on Remotion's useCurrentFrame() hook rather than Tailwind's
transition-* or animate-* classes, and in "Examples" include the proposed
correct example referencing the AnimatedBox component and useCurrentFrame() and
a short "Don't do this" note showing animate-* usage so readers see both the
correct pattern (useCurrentFrame → inline style opacity) and the incorrect
pattern (Tailwind animate-*).
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 18c54fec-a51b-4d38-849e-1d98491da6bc
⛔ Files ignored due to path filters (1)
yarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (6)
skills/lead-intelligence/SKILL.mdskills/remotion-video-creation/rules/lottie.mdskills/remotion-video-creation/rules/measuring-dom-nodes.mdskills/remotion-video-creation/rules/tailwind.mdskills/remotion-video-creation/rules/transcribe-captions.mdskills/remotion-video-creation/rules/trimming.md
✅ Files skipped from review due to trivial changes (4)
- skills/remotion-video-creation/rules/transcribe-captions.md
- skills/remotion-video-creation/rules/lottie.md
- skills/remotion-video-creation/rules/trimming.md
- skills/remotion-video-creation/rules/measuring-dom-nodes.md
| ## When to Activate | ||
|
|
||
| - User wants to find leads or prospects in a specific industry | ||
| - Building an outreach list for partnerships, sales, or fundraising | ||
| - Researching who to reach out to and the best path to reach them | ||
| - User says "find leads", "outreach list", "who should I reach out to", "warm intros" | ||
| - Needs to score or rank a list of contacts by relevance | ||
| - Wants to map mutual connections to find warm introduction paths | ||
|
|
||
| ## Tool Requirements | ||
|
|
||
| ### Required | ||
| - **Exa MCP** — Deep web search for people, companies, and signals (`web_search_exa`) | ||
| - **X API** — Follower/following graph, mutual analysis, recent activity (`X_BEARER_TOKEN`, `X_ACCESS_TOKEN`) | ||
|
|
||
| ### Optional (enhance results) | ||
| - **LinkedIn** — Via browser-use MCP or direct API for connection graph | ||
| - **Apollo/Clay API** — For enrichment cross-reference if user has access | ||
| - **GitHub MCP** — For developer-centric lead qualification | ||
|
|
||
| ## Pipeline Overview |
There was a problem hiding this comment.
Use the required skill section headings.
Please rename/add headings so the document explicitly contains “When to Use”, “How It Works”, and “Examples” (currently “When to Activate”, “Pipeline Overview”, and “Example Usage”). This keeps skill docs consistent and machine-checkable.
Suggested minimal heading update
-## When to Activate
+## When to Use
...
-## Pipeline Overview
+## How It Works
...
-## Example Usage
+## ExamplesAs per coding guidelines: “skills/**/*.md: Skill format must be Markdown with clear sections for When to Use, How It Works, and Examples”.
Also applies to: 210-210
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/lead-intelligence/SKILL.md` around lines 11 - 31, Rename the section
headings to match the required skill schema: change "When to Activate" to "When
to Use", change "Pipeline Overview" to "How It Works", and change any "Example
Usage" or similar to "Examples" (update the exact strings "When to Activate",
"Pipeline Overview", and "Example Usage"/"Example" wherever they appear in
SKILL.md, including the referenced later occurrence around line 210). Ensure the
Tool Requirements and content under Required/Optional remain unchanged and
update any internal links or references that point to the old headings so
documentation and machine checks keep working.
| ### Enrichment Sources | ||
| - Exa: company data, news, blog posts | ||
| - X API: recent tweets, bio, followers | ||
| - GitHub: open source contributions (for developer-centric leads) |
There was a problem hiding this comment.
Hyphenate compound adjective for clarity.
At Line 144, use “open-source contributions” instead of “open source contributions”.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~144-~144: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...recent tweets, bio, followers - GitHub: open source contributions (for developer-centric le...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/lead-intelligence/SKILL.md` at line 144, Update the phrase in the
SKILL.md content where it currently reads "GitHub: open source contributions
(for developer-centric leads)" to use the hyphenated compound adjective
"open-source contributions" so it becomes "GitHub: open-source contributions
(for developer-centric leads)"; locate this exact string and replace the
unhyphenated form with the hyphenated form to improve clarity.
Summary
check-codex-global-state.shusedrg(ripgrep) which is not available on GitHub Actions Ubuntu 24.04 runners. Addedsearch_file()helper that usesrgwhen available, falls back togrep -En. All regex patterns converted to POSIX ERE for portability. This was the root cause of the codex-hooks sync test failing on all platforms.check-unicode-safety.test.jsregex expected/separators but Windows uses\. Changed to[/\\]character class.PYTHONUTF8=1in the test env."in the name, which NTFS does not allow. Test now skips onwin32.Test plan
rgon PATH (simulating CI)Summary by cubic
Fixes cross-platform test failures and stabilizes CI on Ubuntu, macOS, and Windows. Adds
remotion-video-creation(29 rules), restoresautonomous-agent-harnessandlead-intelligence, addssocial-graph-ranker, updates the catalog to 140 skills, and hardens tooling with pinned MCP servers, Dependabot, and resolved npm audit vulnerabilities.Bug Fixes
scripts/codex/check-codex-global-state.sh: added portablesearch_file()usingrgorgrep -En; converted patterns to POSIX ERE.tests/scripts/check-unicode-safety.test.js: path regex accepts/or\.tests/scripts/openclaw-persona-forge-gacha.test.js: setPYTHONUTF8=1for UTF-8 stdout on Windows.tests/scripts/codex-hooks.test.js: skipped quoted-path shell-injection test on Windows due to NTFS rules.skills/lead-intelligence: replaced Unicode arrows with ASCII to satisfy CI unicode safety checks.Dependencies
.mcp.json: pinned MCP servers for supply-chain safety (@modelcontextprotocol/server-github@2025.4.8,@modelcontextprotocol/server-memory@2026.1.26,@modelcontextprotocol/server-sequential-thinking@2025.12.18,@playwright/mcp@0.0.69)..github/dependabot.yml: weekly updates fornpmandgithub-actionswith grouped minor/patch PRs..github/workflows/monthly-metrics.yml: pinnedactions/github-scriptto a commit SHA.package.json/lockfiles: upgradedmarkdownlint-clito^0.48.0, patchedbrace-expansionand other advisories;npm auditnow reports 0 vulnerabilities; regeneratedyarn.lockto matchpackage.json.Written for commit cbc65a8. Summary will update on new commits.
Summary by CodeRabbit
New Features
Documentation
Tests
Chores