Skip to content
SlashClone

Content calendar

@contentstudio/content-calendar

Plan a few weeks of content across LinkedIn, a newsletter, a blog, and more. A script lays out dated slots per channel with your content pillars rotated evenly, then Claude fills in specific topics and hooks you can actually write. Exports a CSV for your sheet or planner.

SkillContentv1.0.0 (latest)Tested
Activity
New: be the first to try it
  1. 1{
  2. 2 "name": "content-calendar",
  3. 3 "owner": "contentstudio",
  4. 4 "version": "1.0.0",
  5. 5 "type": "skill",
  6. 6 "description": "Plan a few weeks of content across LinkedIn, a newsletter, a blog, and more. A script lays out dated slots per channel with your content pillars rotated evenly, then Claude fills in specific topics and hooks you can actually write. Exports a CSV for your sheet or planner.",
  7. 7 "category": "content",
  8. 8 "license": "MIT",
  9. 9 "compat": ["claude-code"],
  10. 10 "permissions": {
  11. 11 "shell": ["node scripts/calendar.mjs"],
  12. 12 "files": {
  13. 13 "read": ["./content/**", "./brand.md"],
  14. 14 "write": ["./content/calendar/**"]
  15. 15 }
  16. 16 },
  17. 17 "tests": {
  18. 18 "cases": [
  19. 19 {
  20. 20 "name": "lays out three weeks with pillars rotated and a holiday skipped",
  21. 21 "inputs": {},
  22. 22 "checks": [
  23. 23 {
  24. 24 "type": "command_exits_zero",
  25. 25 "command": "node scripts/calendar.mjs content/calendar --start 2026-11-09 --weeks 3 --cadence \"linkedin:mon,wed,fri newsletter:thu blog:tue\" --pillars \"Product tips,Customer stories,Behind the scenes\" --skip 2026-11-26"
  26. 26 },
  27. 27 {
  28. 28 "type": "output_matches_schema",
  29. 29 "path": "content/calendar/content-calendar.json",
  30. 30 "schema": {
  31. 31 "type": "object",
  32. 32 "required": ["slots", "by_channel", "by_pillar", "skipped"],
  33. 33 "properties": {
  34. 34 "start": { "const": "2026-11-09" },
  35. 35 "end": { "const": "2026-11-27" },
  36. 36 "slots": { "const": 14 },
  37. 37 "by_channel": {
  38. 38 "type": "object",
  39. 39 "properties": { "linkedin": { "const": 9 }, "blog": { "const": 3 }, "newsletter": { "const": 2 } }
  40. 40 },
  41. 41 "by_pillar": {
  42. 42 "type": "object",
  43. 43 "properties": {
  44. 44 "Product tips": { "const": 4 },
  45. 45 "Customer stories": { "const": 5 },
  46. 46 "Behind the scenes": { "const": 5 }
  47. 47 }
  48. 48 },
  49. 49 "skipped": { "const": ["2026-11-26 newsletter"] }
  50. 50 }
  51. 51 }
  52. 52 },
  53. 53 {
  54. 54 "type": "file_contains",
  55. 55 "path": "content/calendar/content-calendar.csv",
  56. 56 "text": "date,day,week,channel,format,pillar,topic,hook,status,owner,link\n2026-11-09,Mon,1,linkedin,post,Product tips,,,idea,,"
  57. 57 },
  58. 58 { "type": "file_contains", "path": "content/calendar/content-calendar.md", "text": "## Week 3 (from 2026-11-23)" }
  59. 59 ]
  60. 60 },
  61. 61 {
  62. 62 "name": "writes a new file and leaves a filled-in calendar alone",
  63. 63 "inputs": {
  64. 64 "content/calendar/content-calendar.csv": "date,channel,topic\n2026-11-09,linkedin,Our best tip\n"
  65. 65 },
  66. 66 "checks": [
  67. 67 {
  68. 68 "type": "command_exits_zero",
  69. 69 "command": "node scripts/calendar.mjs content/calendar --start 2026-11-09 --weeks 1 --name december"
  70. 70 },
  71. 71 { "type": "file_contains", "path": "content/calendar/content-calendar.csv", "text": "Our best tip" },
  72. 72 { "type": "file_exists", "path": "content/calendar/december.csv" }
  73. 73 ]
  74. 74 }
  75. 75 ]
  76. 76 }