Release Calendar Skill
Generate a "Everything [Team] shipped in X days" calendar poster from real X data.
Choose the right mode first
Before running the setup wizard, decide whether this is a new calendar or an incremental update.
- Use New Calendar Mode when the product is not already represented in the project data or the user explicitly asks for a new poster/PNG from scratch.
- Use Incremental Update Mode when the user asks to update an existing calendar, extend the date range, sync recent releases, refresh x-1.dev, or add releases since the last update.
Default to Incremental Update Mode if existing release data is present. Do not redo discovery work just because the skill can do it.
Incremental Update Mode
Use this path for follow-up updates such as "sync Apr 6-Apr 20 for every product".
Inputs to reuse
Read the existing product data first:
find ximage/web/data/releases -maxdepth 1 -name '*.ts' -print
For each existing product, reuse:
teamMembers[].handleas the canonical X account list.teamMembers[].avataras the canonical avatar cache.releases[].authorAvatarfor previously known author avatars.brand,bg,file, andlogofrom the product data.
Do not fetch avatars, logos, or rediscover team members in incremental mode unless a new posting handle appears in the incremental tweet data and no cached avatar exists for that handle.
Incremental fetch rule
Fetch only the missing time window. If the user says "Apr 6-Apr 20", use:
SINCE=2026-04-06
UNTIL=2026-04-21 # X search until is exclusive, so this includes Apr 20 UTC
For each existing handle, fetch post/search data into a windowed cache directory instead of scattering raw files in the project root:
WINDOW=".omx/release-calendar/windows/${SINCE}_${UNTIL}"
mkdir -p "$WINDOW/raw" "$WINDOW/reports"
TWITTER_BROWSER=${BROWSER:-chrome} TWITTER_PROXY=http://127.0.0.1:1082 \
twitter search --from "$handle" --since "$SINCE" --until "$UNTIL" \
-t latest --max 100 --json > "$WINDOW/raw/${handle}.search.json"
If X returns 429 rate limits, do not restart from scratch. Keep successful cache
files, reduce concurrency, and retry only missing product/official handles
first. Prefer twitter user-posts <handle> --max 100 --json as the fallback for
key handles when search is rate-limited.
Filtering rule
Only append release items that are new and concrete:
- New product/model/platform launch.
- New feature shipped to users.
- Developer API/SDK/tooling release.
- Integration, connector, marketplace, IDE, or workflow launch.
- Meaningful availability expansion (GA, mobile, desktop, region, plan).
- Major usage/download/customer milestone only if the product account presents it as a shipping milestone.
Discard opinions, replies without shipped functionality, event reminders, podcasts, reposts, tutorials, and engagement posts.
Deduplicate by tweetUrl first, then by (date, normalized text).
Update existing data files
Append releases to the relevant ximage/web/data/releases/<slug>.ts file and
update:
subtitleday count from first release date to latest release date.dateRangeto the new first/latest month-day span.- release count is derived from the array; do not store a separate count.
Keep existing manually curated release labels. Do not regenerate older entries or overwrite existing avatar URLs.
PNG/HTML rule
For the web app, the canonical source is ximage/web/data/releases/*.ts.
Generating HTML/PNG posters is optional in incremental mode unless the user
explicitly asks for refreshed poster images. If posters are generated, write them
under a dedicated generated-output folder or the existing ximage/ poster
location intentionally; do not mix raw tweet caches with poster artifacts.
What this produces
A full-page PNG screenshot of an HTML calendar that shows:
- Header with brand logo + big title ("Everything OpenAI shipped in 54 days")
- Team member avatars (2 rows, up to 10 people) with their X handles
- Monthly calendar grid — release days highlighted in brand color with release items
- Each release item has: publisher avatar (tiny circle) + emoji + short description
- Background: either a provided image or a generated gradient, with the calendar as a white rounded card on top
Step 0: Interactive Setup Wizard
Run this wizard every time — do not skip steps.
0a. Check / install x-cli
which twitter 2>/dev/null || echo "NOT_FOUND"
If NOT_FOUND, tell the user:
x-cli is not installed. Run:
npm install -g twitter-cli(orbrew install twitter-cliif available). Then re-run this skill.
Stop here if x-cli is not installed.
0b. Ask which browser the user is logged in to X with
x-cli supports: chrome, firefox, safari, edge, brave
Ask the user:
Which browser are you logged in to X (Twitter) with? Options: chrome / firefox / safari / edge / brave
Store the answer as $BROWSER. Default to chrome if they don't say.
0c. Ask for the company / product to research
Ask the user:
Which company or product do you want to make a release calendar for? You can give a name ("Vercel"), an X handle ("@vercel"), or a website URL ("vercel.com").
- If a URL is given (e.g.
vercel.com), infer the company name and look up their X handle via search. - If a name is given, look up known handles from the Brand Colors reference, or search X for
@<name>to find the official account.
0d. Ask for background style
Ask the user:
What background do you want for the calendar?
- Your own image — drag a file into the folder and give me the path (e.g.
/path/to/bg.jpg)- AI-generated CSS background — I'll design an HTML/CSS background that matches the brand (gradients, patterns, textures)
If the user provides a file path → use it as url('file://[abs_path]') on the html element.
If the user picks option 2 (or skips) → generate a CSS background that fits the brand:
- Amp: warm parchment gradient (
#CEC8B8→#B8B0A0) — clean, editorial - OpenAI: deep dark mesh (
#0a0a0f→#111827) - Anthropic: warm sunset gradient (
#2d1b0e→#1a0a0a) - Vercel: pure black
- Unknown:
linear-gradient(135deg, #1a1a2e 0%, #0f3460 100%)
⚠️ Always put background CSS on html { }, not body { } — prevents cut-off in full-page screenshots.
0e. Ask for date range
Ask the user:
How far back should we look for releases? 30 days (focused, recent sprint) / 60 days (default, 2 months) / 90 days (broader history)
Use their choice to set $DAYS_BACK. Default: 60 days.
- The calendar will show months from
(today - $DAYS_BACK)through the month of the last release found. - ⚠️ The headline "shipped in N days" is always calculated from first release date → last release date, not $DAYS_BACK.
0f. Verify x-cli auth with the chosen browser
TWITTER_BROWSER=$BROWSER twitter whoami 2>/dev/null | head -3
If ok: false:
X login not found in $BROWSER. Please open $BROWSER, go to x.com, log in, then try again.
Stop here if auth fails.
1a. Confirm team handles to track
Based on the company identified in Step 0c:
- Check the Brand Colors Reference at the bottom of this skill first — many popular companies already have a confirmed handle list.
- If the company is in the reference, use those handles directly.
- If not in the reference:
- Use
twitter user <company_name> --yamlto find the official account - Search for founder/core team handles:
twitter search "(from:<handle>) OR (to:<handle>)" --yaml - Pick up to 10 unique handles: 1 official account + CEO/founder + up to 8 active product team members
- Use
Store the final list as $HANDLES (space-separated). You will use this in all subsequent steps.
1b. Pull posts — use --max 200, ALL handles in parallel
SINCE=$(date -v-${DAYS_BACK}d +%Y-%m-%d 2>/dev/null || date -d "-${DAYS_BACK} days" +%Y-%m-%