New: Earn 20% as an AgentAlley affiliate. Share your link and earn on every sale you refer. Join now New: Earn 20% as an affiliate. Join now

Write a TikTok caption under 2,200 chars

TikTok Caption Writer

by sergebulaev · MIT license · ★ 50 on GitHub · updated Sep 17

TikTok Caption Writer cover

Write a TikTok caption under 2,200 chars (hashtags included), pick a tasteful 3 to 5 hashtag set with mixed reach, and set the platformSettings.tiktok flags (viewer setting, comments, duet, stitch, commercial and branded content).…

---
name: tt-caption-writer
description: "Write a TikTok caption under 2,200 chars (hashtags included), pick a tasteful 3 to 5 hashtag set with mixed reach, and set the platformSettings.tiktok flags (viewer setting, comments, duet, stitch, commercial and branded content). Front-loads a reason to comment, runs the humanizer pass, and publishes the rendered video via Publora on approval. Use to caption a finished video. Not for the in-video hook (use tt-hook-scripter) or scrubbing a script (use tt-humanizer)."
---

# TikTok Caption Writer

Write the caption that sits under the video: a tight caption inside the 2,200
char API limit, a mixed-reach hashtag set, and the `platformSettings.tiktok`
flags that control reach and interaction. On TikTok the caption supports the
video, it does not carry it. The hook is in the first 1-3 seconds of the clip
(see `tt-hook-scripter`); the caption's job is to add context and earn a comment.

## When to use

- User has a video (or a script) and needs the caption, hashtags, and settings
- User is about to upload and wants the posting flags right
- User wants Claude Code or Codex to schedule a rendered .mp4 via Publora

Overview

Write the caption that sits under the video: a tight caption inside the 2,200 char API limit, a mixed-reach hashtag set, and the platformSettings.tiktok flags that control reach and interaction. On TikTok the caption supports the video, it does not carry it. The hook is in the first 1-3 seconds of the clip (see tt-hook-scripter); the caption's job is to add context and earn a comment.

Manual install (npx, ZIP)
Claude Codenpx skills add sergebulaev/tiktok-skills --skill tt-caption-writer -g -a claude-code
Claude Code (manual)mkdir -p ~/.claude/skills && curl -sL https://codeload.github.com/sergebulaev/tiktok-skills/tar.gz/edffc4f7b663 \ | tar -xz -C ~/.claude/skills --strip-components=4 tiktok-skills-edffc4f7b663/.codex-marketplace/tiktok-skills/skills/tt-caption-writer
Windows (PowerShell)New-Item -ItemType Directory -Force "$HOME\.claude\skills" | Out-Null; Invoke-WebRequest "https://m.agentalley.io/zip/47ef9b41ac8f0f564038/tt-caption-writer.zip" -OutFile "$env:TEMP\tt-caption-writer.zip"; Expand-Archive "$env:TEMP\tt-caption-writer.zip" -DestinationPath "$HOME\.claude\skills" -Force
Claude.ai / desktopDownload the ZIP and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md7.6 KB
  • references/1 file · 3.4 KB
Read the files here
sergebulaev/edffc4f2 files
Shared references5SKILL.md reads these from elsewhere in the repo. Not in the ZIP.Get them on GitHub ↗
SKILL.md
Show the full text135 lines

TikTok Caption Writer

Write the caption that sits under the video: a tight caption inside the 2,200 char API limit, a mixed-reach hashtag set, and the platformSettings.tiktok flags that control reach and interaction. On TikTok the caption supports the video, it does not carry it. The hook is in the first 1-3 seconds of the clip (see tt-hook-scripter); the caption's job is to add context and earn a comment.

When to use

  • User has a video (or a script) and needs the caption, hashtags, and settings
  • User is about to upload and wants the posting flags right
  • User wants Claude Code or Codex to schedule a rendered .mp4 via Publora

What this skill produces

  • Caption (<= 2,200 chars on the API; aim much shorter), first line front- loaded with a reason to read or comment
  • Hashtag set (3 to 5, mixed reach), placed at the end
  • platformSettings.tiktok flags with a plain-English summary
  • On approval, the publish call (draft -> upload -> schedule) when a video file is supplied

The TikTok settings (platformSettings.tiktok)

Build these with lib.tiktok_settings(...). Defaults match Publora's.

Setting Values / default What it does
viewerSetting PUBLIC_TO_EVERYONE (default), MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY who can view. Effectively required; an empty value is rejected
allowComments true (default) viewers can comment
allowDuet false (default) viewers can Duet
allowStitch false (default) viewers can Stitch
commercialContent false (default) the video is commercial
brandOrganic false (default) promoting your own brand
brandedContent false (default) paid partnership / sponsored
Two gotchas you must surface to the user
  1. Boolean inversion bug. Publora currently maps allowComments, allowDuet, allowStitch to TikTok's disable_* flags, so the booleans can land inverted (sending allowDuet: true may disable duets). The status cannot be confirmed from the API alone. Test with a SELF_ONLY draft before trusting these values. Tell the user this whenever they change a flag.
  2. Commercial disclosure. If commercialContent is true, at least one of brandOrganic (your own brand) or brandedContent (paid partnership) must also be true, or Publora rejects it. lib.tiktok_settings enforces this.
Posting reality
  • Unaudited apps post PRIVATE only. Until the publishing app passes TikTok's review, posts are forced to SELF_ONLY regardless of viewerSetting. Warn the user if a "public" post lands private.
  • For reach, use PUBLIC_TO_EVERYONE. For an end-to-end test, use SELF_ONLY.

Steps

Voice profile first (all drafts). If ../../references/voice-profile.md has filled: yes, load it and match the user's voice fingerprint, hard rules, and CTA/link style throughout. If it is not filled, mention once that tt-humanizer --mode profile can learn their voice from a few posts, then proceed with the generic voice rules.

  1. Gather inputs, goal first. Ask (or infer) what the caption should earn, then shape for it: comments -> end on one specific question tied to the video; saves -> promise reference value ("the 3 settings are in the caption"); shares -> a claim people will want to show someone; profile taps -> an open loop the pinned video pays off. Then gather the video topic/script, the niche, whether it is commercial, and whether a rendered .mp4 path exists.
  2. Draft the caption. Front-load the first visible line with a reason to read or a specific question to comment on. Keep it tight. Em dashes under the cap (about one per 100 words; a short caption rarely needs one), no AI vocab cluster. Optionally restate the hook's open loop as a comment prompt.
  3. Pick hashtags. 3 to 5, mixed reach: one broad, one to two niche-defining, one to two specific to the video. Put them at the end. Never stuff.
  4. Set the flags. Default to PUBLIC_TO_EVERYONE, comments on, duet/stitch off, no commercial flags. Adjust per the user, and surface the two gotchas. Build with lib.tiktok_settings(...).
  5. Char check. Confirm caption + hashtags <= 2,200. If over, tighten.
  6. Humanizer pass. Scrub 2026 AI vocab by density, cap em dashes (about one per 100 words, never swap one for a period), break stacked triads, generic openers, reveal bridges and sincerity openers ("not gonna lie"). Leave the rhythm alone; never chop a line for punch. Canonical rules: tt-humanizer V3.
  7. Approval card. Show: caption, char count, hashtag set, settings summary, and the resolved viewerSetting (flag if it may post private).
  8. On approval. Call lib.publish("video", caption, target_url=<upload or profile URL>, video_path=<path or None>, platform_settings=<settings>, scheduled_time=<iso or None>, platforms=[<TIKTOK_PLATFORM_ID>]). With a video path and Publora configured, it runs draft -> upload -> schedule. Without one, it returns the caption and settings to upload in-app.

Hard rules

Global voice rules: see root SKILL.md Voice rules. Additional skill-specific rules:

  • Caption + hashtags must fit 2,200 chars (API), hashtags included. Aim far under.
  • 3 to 5 hashtags, mixed reach, at the end. Never 10+, never mid-sentence.
  • The caption never does the hook's job. The hook is in the video.
  • Always set viewerSetting. Never ship an empty value.
  • Surface the boolean inversion warning whenever an interaction flag changes.

Anti-patterns (skill will refuse)

  • Hashtag walls (10+), or hashtags jammed into the sentence.
  • Em dashes above the cap (more than about one per 100 words), or an em dash swapped for a period.
  • "The result?" reveals and "No X. No Y. Just Z." staccato stacks added for punch.
  • "Follow for part 2 / like and subscribe / don't forget to share" stacks.
  • A caption that repeats the spoken hook word for word.
  • commercialContent: true with neither brand flag set.
  • Claiming a post will be public when the app is unaudited (it will be private).

Resources

  • ../../references/voice-rules.md - caption and hashtag rules
  • ../../references/algorithm-heuristics.md - caption, hashtag, and settings heuristics
  • references/settings-matrix.md - every platformSettings.tiktok value, defaults, and the known bugs
  • lib/publora_client.py - tiktok_settings(...), publish_video(...), create_draft(...)

Optional illustration

Offer a generated image when a visual would lift reach. Draft a prompt and call lib.illustrate(prompt, kind="story"), pulling brand handle/color from Voice & Brand Profile section 6 for a pixel-exact overlay. Show the returned url + cost, for a TikTok photo post, attach the image via media_urls=[url] (TikTok photo carousel); for a video, TikTok's API has no cover-image field, so set the cover in the TikTok app. Full workflow (incl. quote-cards): ../tt-humanizer/sub-skills/illustration.md. No Pixfaro key -> it drafts the prompt for you to generate manually.

  • tt-hook-scripter - the in-video hook (the caption does not replace it)
  • tt-humanizer - scrub the caption before publishing
  • tt-content-planner - schedule captions across a posting week
1---
2name: tt-caption-writer
3description: "Write a TikTok caption under 2,200 chars (hashtags included), pick a tasteful 3 to 5 hashtag set with mixed reach, and set the platformSettings.tiktok flags (viewer setting, comments, duet, stitch, commercial and branded content). Front-loads a reason to comment, runs the humanizer pass, and publishes the rendered video via Publora on approval. Use to caption a finished video. Not for the in-video hook (use tt-hook-scripter) or scrubbing a script (use tt-humanizer)."
4---
5 
6# TikTok Caption Writer
7 
8Write the caption that sits under the video: a tight caption inside the 2,200
9char API limit, a mixed-reach hashtag set, and the `platformSettings.tiktok`
10flags that control reach and interaction. On TikTok the caption supports the
11video, it does not carry it. The hook is in the first 1-3 seconds of the clip
12(see `tt-hook-scripter`); the caption's job is to add context and earn a comment.
13 
14## When to use
15 
16- User has a video (or a script) and needs the caption, hashtags, and settings
17- User is about to upload and wants the posting flags right
18- User wants Claude Code or Codex to schedule a rendered .mp4 via Publora
19 
20## What this skill produces
21 
22- **Caption** (<= 2,200 chars on the API; aim much shorter), first line front-
23 loaded with a reason to read or comment
24- **Hashtag set** (3 to 5, mixed reach), placed at the end
25- **platformSettings.tiktok** flags with a plain-English summary
26- On approval, the publish call (draft -> upload -> schedule) when a video file
27 is supplied
28 
29## The TikTok settings (platformSettings.tiktok)
30 
31Build these with `lib.tiktok_settings(...)`. Defaults match Publora's.
32 
33| Setting | Values / default | What it does |
34|---|---|---|
35| `viewerSetting` | PUBLIC_TO_EVERYONE (default), MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY | who can view. Effectively required; an empty value is rejected |
36| `allowComments` | true (default) | viewers can comment |
37| `allowDuet` | false (default) | viewers can Duet |
38| `allowStitch` | false (default) | viewers can Stitch |
39| `commercialContent` | false (default) | the video is commercial |
40| `brandOrganic` | false (default) | promoting your own brand |
41| `brandedContent` | false (default) | paid partnership / sponsored |
42 
43### Two gotchas you must surface to the user
44 
451. **Boolean inversion bug.** Publora currently maps `allowComments`,
46 `allowDuet`, `allowStitch` to TikTok's `disable_*` flags, so the booleans can
47 land inverted (sending `allowDuet: true` may disable duets). The status cannot
48 be confirmed from the API alone. **Test with a `SELF_ONLY` draft before
49 trusting these values.** Tell the user this whenever they change a flag.
502. **Commercial disclosure.** If `commercialContent` is true, at least one of
51 `brandOrganic` (your own brand) or `brandedContent` (paid partnership) must
52 also be true, or Publora rejects it. `lib.tiktok_settings` enforces this.
53 
54### Posting reality
55 
56- **Unaudited apps post PRIVATE only.** Until the publishing app passes TikTok's
57 review, posts are forced to `SELF_ONLY` regardless of `viewerSetting`. Warn the
58 user if a "public" post lands private.
59- For reach, use `PUBLIC_TO_EVERYONE`. For an end-to-end test, use `SELF_ONLY`.
60 
61## Steps
62 
63**Voice profile first (all drafts).** If `../../references/voice-profile.md` has `filled: yes`, load it and match the user's voice fingerprint, hard rules, and CTA/link style throughout. If it is not filled, mention once that `tt-humanizer --mode profile` can learn their voice from a few posts, then proceed with the generic voice rules.
64 
651. **Gather inputs, goal first.** Ask (or infer) what the caption should earn,
66 then shape for it: comments -> end on one specific question tied to the video;
67 saves -> promise reference value ("the 3 settings are in the caption");
68 shares -> a claim people will want to show someone; profile taps -> an open
69 loop the pinned video pays off. Then gather the video topic/script, the
70 niche, whether it is commercial, and whether a rendered
71 .mp4 path exists.
722. **Draft the caption.** Front-load the first visible line with a reason to read
73 or a specific question to comment on. Keep it tight. Em dashes under the cap
74 (about one per 100 words; a short caption rarely needs one), no AI vocab
75 cluster. Optionally restate the hook's open loop as a comment prompt.
763. **Pick hashtags.** 3 to 5, mixed reach: one broad, one to two niche-defining,
77 one to two specific to the video. Put them at the end. Never stuff.
784. **Set the flags.** Default to `PUBLIC_TO_EVERYONE`, comments on, duet/stitch
79 off, no commercial flags. Adjust per the user, and surface the two gotchas.
80 Build with `lib.tiktok_settings(...)`.
815. **Char check.** Confirm caption + hashtags <= 2,200. If over, tighten.
826. **Humanizer pass.** Scrub 2026 AI vocab by density, cap em dashes (about
83 one per 100 words, never swap one for a period), break stacked triads,
84 generic openers, reveal bridges and sincerity openers ("not gonna lie").
85 Leave the rhythm alone; never chop a line for punch. Canonical rules:
86 `tt-humanizer` V3.
877. **Approval card.** Show: caption, char count, hashtag set, settings summary,
88 and the resolved `viewerSetting` (flag if it may post private).
898. **On approval.** Call `lib.publish("video", caption, target_url=<upload or
90 profile URL>, video_path=<path or None>, platform_settings=<settings>,
91 scheduled_time=<iso or None>, platforms=[<TIKTOK_PLATFORM_ID>])`. With a video
92 path and Publora configured, it runs draft -> upload -> schedule. Without one,
93 it returns the caption and settings to upload in-app.
94 
95## Hard rules
96 
97Global voice rules: see root `SKILL.md` Voice rules. Additional skill-specific
98rules:
99 
100- Caption + hashtags must fit 2,200 chars (API), hashtags included. Aim far under.
101- 3 to 5 hashtags, mixed reach, at the end. Never 10+, never mid-sentence.
102- The caption never does the hook's job. The hook is in the video.
103- Always set `viewerSetting`. Never ship an empty value.
104- Surface the boolean inversion warning whenever an interaction flag changes.
105 
106## Anti-patterns (skill will refuse)
107 
108- Hashtag walls (10+), or hashtags jammed into the sentence.
109- Em dashes above the cap (more than about one per 100 words), or an em dash swapped for a period.
110- "The result?" reveals and "No X. No Y. Just Z." staccato stacks added for punch.
111- "Follow for part 2 / like and subscribe / don't forget to share" stacks.
112- A caption that repeats the spoken hook word for word.
113- `commercialContent: true` with neither brand flag set.
114- Claiming a post will be public when the app is unaudited (it will be private).
115 
116## Resources
117 
118- `../../references/voice-rules.md` - caption and hashtag rules
119- `../../references/algorithm-heuristics.md` - caption, hashtag, and settings heuristics
120- `references/settings-matrix.md` - every platformSettings.tiktok value, defaults, and the known bugs
121- `lib/publora_client.py` - `tiktok_settings(...)`, `publish_video(...)`, `create_draft(...)`
122 
123## Optional illustration
124 
125Offer a generated image when a visual would lift reach. Draft a prompt and call
126`lib.illustrate(prompt, kind="story")`, pulling brand handle/color from Voice &
127Brand Profile section 6 for a pixel-exact overlay. Show the returned `url` + `cost`,
128for a TikTok photo post, attach the image via `media_urls=[url]` (TikTok photo carousel); for a video, TikTok's API has no cover-image field, so set the cover in the TikTok app. Full workflow (incl. quote-cards):
129`../tt-humanizer/sub-skills/illustration.md`. No Pixfaro key -> it drafts the prompt for you to generate manually.
130## Related skills
131 
132- `tt-hook-scripter` - the in-video hook (the caption does not replace it)
133- `tt-humanizer` - scrub the caption before publishing
134- `tt-content-planner` - schedule captions across a posting week
135 
View all files on GitHub →

Details

Updated
Sep 17, 2026
License
MIT
Stars on the repo
★ 50
Checked
Source
sergebulaev/tiktok-skills ↗
Creator
sergebulaev · 77 listings
View creator

Similar skills

See all →
SkillResearch what people actually say about any topicSTEP 0: STALE-CLONE SELF-CHECK — RUN BEFORE READING BELOWmvanhorn/last30days-skill · by mvanhornResearch what people actually say about any topic in the last 30 days. Pulls posts and engagement from Reddit, X, YouTube, TikTok, Hacker News, Polymarket, GitHub, and the web. Includes a doctor health check to diagnose broken or missing sources.★ 63.5k GitHub starsSkillScrapes social platforms, business dataApifydanielmiessler/LifeOS · by danielmiesslerScrapes social platforms, business data, and e-commerce via Apify actors — Instagram, LinkedIn, TikTok, YouTube, Facebook, Google Maps, Amazon, and web crawls — filtering in code. USE WHEN scrape Instagram, scrape LinkedIn, scrape TikTok, scrape YouTube, scrape Facebook, Google Maps leads, Amazon reviews, business intelligence, multi-platform social listening, competitive analysis, lead generation, social monitoring, Apify actors, web crawl, extract contacts. NOT FOR X/Twitter account operations like posting, threads, or bookmarks (those need a dedicated X API client), 4-tier progressive scraping with proxy escalation (use BrightData), or real-Chrome bot bypass and computer use (use Interceptor).★ 19.3k GitHub starsSkill微信公众号长文增长闭环 ——tsingyuai/growth-lab · by tsingyuai微信公众号长文增长闭环 —— 从读者问题与复刻锚选题、写出可验证的公众号长文、预览与合规检查、同步微信草稿、三重确认下受控发布,到回收阅读与转化数据并复盘。用户要求写公众号、把内容改成公众号、同步或发布微信草稿、查看公众号数据或复盘时使用。★ 2k GitHub starsSkillSearch and retrieve content from Twitter/XTwitter/X SkillReScienceLab/opc-skills · by ReScienceLabSearch and retrieve content from Twitter/X. Get user info, tweets, replies, followers, communities, spaces, and trends via twitterapi.io. Use when user mentions Twitter, X, or tweets.★ 1.8k GitHub starsSkillSays 'YouTube script', 'video script'🎬 YouTube Script: Writing retention-optimized video script...cwinvestments/memstack · by cwinvestmentsUse this skill when the user says 'YouTube script', 'video script', 'write script for YouTube', 'YouTube video outline', or is creating scripted content for a YouTube video with hooks, chapters, and CTAs. Do NOT use for TikTok/Reels short-form scripts or webinar presentations.★ 423 GitHub starsSkillAgent Reach — 互联网能力路由器Ootto-AI/claude-content-skills · by Ootto-AIMUST USE when user wants to 调研/research/搜索/search/查/找/look up anything on the internet — e.g. 全网调研 X / 帮我调研一下 X / 查一下 X / 搜搜 X / 看看大家怎么评价 X / X 上有什么讨论 / research this topic。 Also MUST USE when user mentions any platform or shares any URL/链接: 小红书/xiaohongshu/xhs, Twitter/推特/X, B站/bilibili, Reddit, V2EX, LinkedIn/领英/招聘/求职/jobs, YouTube, GitHub code search, 小宇宙播客, 雪球/股票行情, RSS feeds, or any web URL. 13 platforms, multi-backend routing (OpenCLI / per-platform CLIs / APIs). Zero config for 6 channels. Run `agent-reach doctor --json` to see which backend serves each platform right now. NOT for: 写报告/数据分析/翻译等内容加工(本 skill 只负责从互联网获取内容); 发帖/评论/点赞等写操作;已有专门 skill 的平台(先用专门 skill)。 【路由方式】SKILL.md 包含路由表和常用命令,复杂场景需按需阅读对应分类的 references/*.md。 分类:search / social (小红书/推特/B站/V2EX/Reddit) / career(LinkedIn) / dev(github) / web(网页/文章/RSS) / video(YouTube/B站/播客)。★ 139 GitHub stars

More from sergebulaev

SkillBy density per paragraph, not per wordAI Tells — Complete Blacklist (V3, 2026-09)sergebulaev/linkedin-skills · by sergebulaevScored the way readers read: by density per paragraph, not per word. One marker in a paragraph is English. Three is a signature. The…★ 3.1k GitHub starsSkillFifteen rules from the linkedin-humanizer packageAI-Tell Rules: Tier-Classified Referencesergebulaev/linkedin-skills · by sergebulaevFifteen rules from the linkedin-humanizer package, sorted by what kind of evidence each one actually represents.★ 3.1k GitHub starsSkillPattern data from MagicPost LinkedIn analysisEmoji Patterns — AI vs. Humansergebulaev/linkedin-skills · by sergebulaevPattern data from MagicPost LinkedIn analysis (Feb 2026, viral post with 220 engagement).★ 3.1k GitHub starsSkillRead your Instagram niche and profile from real dataInstagram Audience Insightssergebulaev/instagram-skills · by sergebulaevRead your Instagram niche and profile from real data via Apify, no login. Scan a hashtag for the posts traveling now (likes, comments, owner) to see the format and hook that works. Pull profile stats for any handle, yours or a competitor's: followers, posts, bio, category. Instagram hides who liked or commented on other accounts, so this is discovery plus profiles, not engagers. Triggers on "what works in my niche", "scan the hashtag", "competitor stats". Not for writing captions (use ig-caption-writer).★ 138 GitHub starsSkillDraft an Instagram caption with the hook in the first 125Instagram Caption Writersergebulaev/instagram-skills · by sergebulaevDraft an Instagram caption with the hook in the first 125 characters, a skimmable body, and one clear CTA, using a 2026 hook formula chosen by goal (saves, shares, comments, follows). Runs the humanizer pass and, on approval, publishes with the image or video you supply via the Publora media flow. Use to caption a single image or a Reel. Not for slide-by-slide carousels (use ig-carousel-planner) or auditing a draft (use ig-humanizer --mode audit).★ 138 GitHub starsSkillPlan an Instagram carousel slide by slide, up to 10 slidesInstagram Carousel Plannersergebulaev/instagram-skills · by sergebulaevPlan an Instagram carousel slide by slide, up to 10 slides, with a hook slide that opens a loop, value slides that front-load the payoff, and a payoff slide that earns the save and follow. Picks a 2026 carousel formula (listicle, before/after, myth-buster, framework) by goal (saves, shares, follows), drafts each slide's text plus the caption, then publishes the images you supply via Publora. Use to structure a multi-slide carousel. Not for single-image captions (use ig-caption-writer).★ 138 GitHub stars