Local-first generator of one daily vertical short video from RSS feeds. FeedReel turns RSS feeds into a single 1080×1920 vertical video (YouTube Shorts / TikTok / Instagram Reels format), music only, with an auto "subscribe" outro — and a ready-to-paste title + description + hashtags you post manually.
Everything runs locally. The pipeline pulls your RSS feeds, deduplicates against past videos, and renders a fully code-generated video with Remotion. The editorial work (selecting items, writing the script/title/description) is done by the bundled agent skill (Claude Code, Codex, and compatible hosts).
| Output | one output/<date>.mp4 (1080×1920 @ 30 fps, H.264/AAC) + output/<date>.txt |
| Rendering | Remotion (React/TSX), no external images |
| Audio | CC0 background music (SoundSafari/CC0-1.0-Music), fixed scene durations |
| Script & caption | written by the feedreel agent skill |
| Publishing | none — you post the MP4 manually using the generated caption |
feedreel prepare → fetch RSS + dedup (SQLite) → cache/items/<date>.json (local, deterministic)
↓ (the "feedreel" skill reads the items and writes the script)
cache/scripts/<date>.json { date, title, description, hashtags, segments[intro,item…] }
↓
feedreel render → music + Remotion → output/<date>.mp4
→ output/<date>.txt (title + description + hashtags + sources)
+ prints the caption to the terminal
The closing "subscribe" scene is appended automatically — you don't write it.
- macOS / Apple Silicon.
- Node.js >= 20 and pnpm.
- ffmpeg / ffprobe on the
PATH(music trim + mux). - Claude Code, Codex, or another compatible agent host (to run the bundled skill).
pnpm setupscripts/setup.sh is idempotent: it checks Node >= 20, installs dependencies,
downloads the CC0 music tracks, vendors the OFL fonts, prepares the Remotion
headless browser, creates the working directories, and creates
config/feedreel.yaml from the example template if missing.
Your feeds live in config/feedreel.yaml, which is gitignored (your RSS
feeds stay private). Start from the committed template:
cp config/feedreel.example.yaml config/feedreel.yaml # then edit your feedsThe config describes a single video: format, language identity, editorial
identity (label, emoji, accentColor, maxItems, subscribeText), the
feeds list, the background music, and the scene durations
(introSec / itemSec / outroSec).
Keep alternate feed sets in their own gitignored files and switch with
FEEDREEL_CONFIG, e.g. FEEDREEL_CONFIG=config/feedreel.tech.yaml pnpm feedreel prepare.
Tell your agent "generate me the video" (or "génère moi la vidéo"). The
feedreel skill drives the whole flow locally: prepare → write the script →
render → report the MP4 and the copy-paste caption. Nothing leaves your machine
except fetching the RSS feeds.
Under the hood it runs two commands (both accept --date YYYY-MM-DD, default today):
# 1) Fetch + dedup today's items → cache/items/<date>.json
pnpm feedreel prepare
# 2) The skill reads the items and writes cache/scripts/<date>.json
# 3) Build the video + caption → output/<date>.mp4 + output/<date>.txt
pnpm feedreel renderDeduplication is persisted in SQLite (feedreel.db): items are marked seen only
after a successful render, so a second run on the same day won't repeat the same
news, while re-running prepare before rendering is safe.
All have defaults (see config/index.ts). Relative paths resolve from the project root.
| Variable | Default | Role |
|---|---|---|
FEEDREEL_CONFIG |
config/feedreel.yaml |
Active config file |
FEEDREEL_OUTPUT_DIR |
output |
Rendered videos directory |
FEEDREEL_CACHE_DIR |
cache |
items / scripts / audio cache |
FEEDREEL_DB_PATH |
feedreel.db |
SQLite dedup database |
FEEDREEL_MUSIC_TRACK |
(config) | Override the background track |
FEEDREEL_FPS / FEEDREEL_WIDTH / FEEDREEL_HEIGHT |
30 / 1080 / 1920 |
Video format |
FEEDREEL_FEED_TIMEOUT_MS |
12000 |
Per-feed RSS timeout (ms) |
FEEDREEL_LOG_FILE |
— | If set, also logs to this file |
feedreel/
config/ feedreel.yaml (private) · feedreel.example.yaml · schema.ts · load.ts · index.ts
src/
types.ts · log.ts · exec.ts · util.ts · cli.ts
pipeline/ fetchRss · dedup · script · music · render · orchestrate
remotion/ FeedReelVideo.tsx · scenes/{Intro,Item,Outro} · components/* · theme · fonts
scripts/ setup.sh · vendor-*.mjs
.claude/skills/feedreel/ canonical skill that drives generation
.agents/skills/feedreel/ versioned Codex discovery link to the canonical skill
| Component | License |
|---|---|
TypeScript, Node, tsx, vitest, rss-parser, better-sqlite3, zod, commander |
MIT |
| ffmpeg / ffprobe | LGPL |
| Remotion | source-available (free for solo use; see Remotion's terms) |
| Fonts Unbounded, Hanken Grotesk, JetBrains Mono | SIL Open Font License (OFL) |
| Music | CC0 (SoundSafari/CC0-1.0-Music) |
These skills run when explicitly invoked: feedreel. Use $name in Codex or /name in Claude Code and OpenCode (with the plugin namespace when installed as a Claude plugin).
The skill bundle disables implicit selection in Codex and Claude Code. OpenCode V2 reads metadata.opencode/autoinvoke: "false". For OpenCode V1, merge these entries into permission.skill in ~/.config/opencode/opencode.json or the project configuration; retain unrelated permissions:
{
"permission": {
"skill": {
"feedreel": "deny"
}
}
}On OpenCode 1.18.30, these rules hide the skills from the agent and reject skill-tool loading, while explicit /name commands remain available. Installation with skills add does not apply this OpenCode V1 configuration.