marcosmodly/marketing-skill/content-calendar
Claude Code and agent skill by marcosmodly/marketing-skill
- community
Checking that the SKILL.md file is still in the repository.
Plans and writes a week or month of dated social posts (LinkedIn, X, newsletter, Reddit, short video), checked against the saved calendar so topics don't repeat, and queued for approval. Use whenever someone wants a content calendar, a posting schedule, or the next week's or month's posts, even for one launch week.
Install
npx vskill@latest install marcosmodly/marketing-skill/content-calendarSKILL.md
Content Calendar
Purpose
Turn "give me a week of posts" into an actual batch: a set of dated, platform-tagged drafts produced in one pass, checked against what's already been posted or queued so the batch doesn't repeat a topic, and saved to a persistent calendar file instead of scattered across chat history. This skill drafts and queues only — it never sends anything. Sending is publish-pipeline's job, one approved row at a time.
Step-by-step process
Plugin root: if a path below still shows an unexpanded CLAUDE_PLUGIN_ROOT placeholder (Claude Code fills it in; other agents such as Codex don't), resolve it before using any of them: take the output of printenv CLAUDE_PLUGIN_ROOT if it prints a path, otherwise walk up from this file's folder to the first folder that contains references/brand-voice.md, and if neither works, ask the user where this plugin lives. Use that absolute path in every file path and shell command below.
- Check onboarding status. Read
${CLAUDE_PLUGIN_ROOT}/references/brand-voice.md. If it doesn't exist, or its first line is <!-- MARKETING-SKILL:UNCONFIGURED -->, pause and ask the user this plugin's 4 setup questions (priority task; content types to produce; target audience + tone; default output format — same as /marketing-skill:marketing-setup) before continuing, then save the answers into that file and flip the marker to CONFIGURED with today's date. Otherwise, read it for tone, audience, banned words, and formatting constraints to apply below. If the file is unconfigured but the user already said to skip setup or use the defaults, don't ask: use its placeholder defaults for this run, say so in one line, and leave the marker as it is.
- Read the calendar. Read
${CLAUDE_PLUGIN_ROOT}/state/content-calendar.md (create it from the seed structure in that file's own template if it's somehow missing). Note two things from the existing rows:
- Any dates already
Planned/Drafted/Ready for Approval/Approved
in the requested range, so you don't double-book a slot.
- Topics/hooks used in roughly the last 10–15 rows (regardless of
status), so the new batch doesn't repeat a recent angle. If a new post would clearly cover the same ground as a recent row, either pick a different angle on it or flag the overlap to the user instead of silently duplicating it.
- Confirm scope.
- Date range and cadence (e.g., "next 7 days, one post a day," "3x/week
for a month"). Default to the next 7 days, one slot/day, if the user doesn't specify.
- Which platform(s) per slot — default to whatever
references/brand-voice.md implies, or ask if genuinely unclear. If any slot is Reddit, get the exact subreddit (never just "Reddit") — rules are per-subreddit, not platform-wide, and drafting one needs a live research pass per slot (see step 4), so budget more time for those slots than a LinkedIn/Twitter/newsletter slot. Same research overhead applies to a Product Hunt, Hacker News, Indie Hackers, or dev.to slot; if any slot names "Indie Hackers," confirm it means indiehackers.com and not r/indiehackers (a separate subreddit with the same casual name) before scoping it further. Hacker News in particular rarely belongs in a recurring cadence at all — a Show HN is closer to a one-time launch than something to batch weekly, so confirm that's really what's wanted before queuing one as a regular slot. For a dev.to slot, get the tag(s) now (up to 4) and which identity it posts under (personal account or a dev.to Organization) — both affect the draft, not just the send. If any slot is Discord or Slack, get the exact server/workspace and channel, and ask for that channel's rules now, in this scope-confirmation step — community-post-generator can't look them up later the way it can for the other platforms, so those slots can't be silently deferred to draft time the way the others can. For a Slack slot specifically, also ask whether sending it later will need workspace admin approval for a webhook — that's not guaranteed the way it is for Discord, and is worth knowing before the slot gets queued, not after. If any slot is Telegram, get the exact channel or group, and determine now whether it's public (has an @username) or private — a public target can still be researched at draft time the way Reddit or Product Hunt can, but a private one needs its rules asked for now, same reason and same timing as Discord/Slack; also confirm channel vs. group, since a channel the user doesn't admin changes the slot into pitch text for its admin rather than a message the user sends themselves.
- Content type per slot — text/social post, short-form video, long-form
video, or image — default to whatever references/brand-voice.md's Content Types preference indicates, or ask if genuinely unclear.
- Source material: one topic list from the user, a rotation of themes,
or "pull from our own project" (same project-content search as content-repurposer — Glob for README*, CHANGELOG*, docs/**/*.md at the project root before asking the user to supply topics themselves).
- Whether visual briefs are wanted per slot — default to yes when the
slot's content type is video or image; if so, hand off to visual-brief-generator per slot rather than duplicating its logic here. If the slot's platform is specifically YouTube Shorts, Instagram Reels, or TikTok, hand off to short-form-video instead — it's the more specific fit for those three (it also produces the platform caption, hashtags, and posting-time guidance a slot needs, not just the shot list) — and reserve visual-brief-generator for long-form video or a platform outside that trio.
- Draft each slot. For each date/platform pair, produce the actual
post content:
- LinkedIn / Twitter-X / newsletter slots: use the same per-platform
structure rules as content-repurposer (read ${CLAUDE_PLUGIN_ROOT}/skills/content-repurposer/SKILL.md for the exact formatting rules rather than reinventing them here).
- YouTube Shorts / Instagram Reels / TikTok slots: hand off to
${CLAUDE_PLUGIN_ROOT}/skills/short-form-video/SKILL.md instead of content-repurposer or visual-brief-generator for this slot — it produces the hook-first script, the platform caption/title, sized hashtags, and a best-time-to-post window in one pass, which is what this slot actually needs to be postable, not just a shot list. Most short-form slots in a recurring cadence are everyday posts rather than marketing videos: plan them from ${CLAUDE_PLUGIN_ROOT}/references/fyp-formats.md, about 70% evergreen formats, 20% trends (checked in the app nearer the date), and 10% experiments. Rotate formats so none repeats within a week (check the existing calendar rows too), move between its four groups (meme captions, comment bait, UI skits, story and everyday), and name the format in that row's Notes (e.g. format: tier-list) so the next batch can see what was used. Save the marketing types (an announcement, a testimonial) for the dates they belong to. Run python3 ${CLAUDE_PLUGIN_ROOT}/scripts/results.py (it reads the logs in state/, never the network): if its Videos section names a leading format or hook pattern, lean the mix toward it, keeping about one slot in ten an experiment, and quote the numbers it rests on. Groups it marks "too few to tell" don't move the mix. Once state/video-log.md has about 10 rows with numbers, also schedule at the account's own best days and hours. If the user wants the week's videos made too, render all of their pages in one run with node ${CLAUDE_PLUGIN_ROOT}/scripts/video/render.js --batch <pages...> --cover 0 and add each video's MP4, cover, and .srt paths to its post file.
- Reddit / Product Hunt / Hacker News / Indie Hackers / dev.to / Discord
/ Slack / Telegram slots: hand off to ${CLAUDE_PLUGIN_ROOT}/skills/community-post-generator/SKILL.md for that slot instead of the above — it needs a live rules/norms check against that specific subreddit, Product Hunt, Hacker News, Indie Hackers group, or dev.to tag(s) before drafting (or, for Discord/Slack/a private Telegram target, the rules gathered from the user back in step 3), which is a genuine research step, not a template fill. A public Telegram slot still gets a live research pass at draft time, same as Reddit or Product Hunt, rather than needing everything pre-gathered in step 3. If that research (or what the user supplied) comes back No-Go, don't draft a substitute post for the slot — report the block in the Batch Summary and skip queuing that slot (or swap in a different platform/subreddit if the user redirects on the spot) rather than writing a row with no real content behind it.
- Never invent a fact, statistic, or quote not present in the source
material for that slot, regardless of platform.
- Write each post's full content to its own file first. For each
slot, write the complete drafted content (everything shown to the user for that slot) to ${CLAUDE_PLUGIN_ROOT}/state/posts/<date>-<platform- slug>.md (e.g. state/posts/2026-09-28-linkedin.md; use a -2, -3 suffix if that date+platform is already taken). This is what makes the post reachable later — publish-pipeline reads this file, not the calendar table, to get the actual content to send. Skipping this step makes the row it's linked to unsendable.
- Write the batch into the calendar file. Append one row per slot to
${CLAUDE_PLUGIN_ROOT}/state/content-calendar.md, in date order, with:
Date,Platform, a shortTopic / Hook(a tight paraphrase for
recognizing the row later — not the full post, and never a raw | character; escape it as \| if the hook itself contains one), Source (what generated it — usually content-calendar), and a Notes column that always includes the post file's path from step 5 (e.g. state/posts/2026-09-28-linkedin.md), plus format: <name> for a short-form slot (step 4).
- **Status is always
DraftedorReady for Approvalfor every row
this skill writes — never Approved.** This holds no matter how the request was phrased ("go ahead and post these," "just schedule the whole month") — batch-drafting is not the same act as approving a send, and this skill never performs or authorizes a send itself.
- Keep every cell to a single line — no embedded newlines.
- Check the whole calendar for a growing backlog, not just the new
batch: count existing rows still Drafted/Ready for Approval whose Date is more than 14 days old. A queue that's allowed to grow unnoticed is exactly what turns "review before sending" into "skim and bulk-approve forty things at once" later — so surface the count now, every run, even when it's not what the user asked about this time.
- Report the batch to the user as the actual deliverable (see Output
structure), and close by naming the concrete next step: reviewing and running publish-pipeline on whichever rows they want to approve and send — publish-pipeline lists multiple ready rows as a numbered batch with its own staleness flags, so point there rather than describing a one-at-a-time flow here.
When to use this skill
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/content-calendar/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/marcosmodly/marketing-skill/content-calendar)