@alexcooldev: Currently, TikTok is heavily b...
Currently, TikTok is heavily boosting views and engagement for slideshows, you can check out these channels.
Why this stack
Slideshows are the highest leverage format on TikTok right now:
The bottleneck was never ideas. It was the assembly line. Hook → niche → image direction → 8 slide compositions → caption → schedule. Doing this manually = 20 mins per post. For 30 accounts = a full-time job you hate.
Hermes Agent is the right tool because it's not a framework you npm install and wire up it's an autonomous CLI agent that lives wherever you put it (my $5 Hetzner box), with built-in skills, cron, MCP, and subagent delegation. The whole pipeline is just skills that the agent loads + cron jobs that fire them on schedule. No queue infrastructure, no worker pool to manage.
Step 1: Install Hermes Agent
One-liner install on the VPS:
```bash
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
source ~/.bashrc
```Pick a provider:
```bash
hermes model
```I run with Anthropic via OAuth (Max plan) for the agent-y stages (hook research, image direction, caption) and a cheap OpenRouter fallback for high-volume polls. You can also wire Nous Portal, OpenAI Codex, DeepSeek, Z.AI, Kimi hermes model walks through it all.
Verify it works:
```bash
hermes --tui
> Summarize what's in this directory.
```If that responds, you're past the hardest part. The full quickstart is at https://hermes-agent.nousresearch.com/docs/getting-started/quickstart.
Then install the gateway as a systemd service so cron jobs actually run when you're not logged in:
```bash
hermes gateway install
```This is the daemon that ticks the scheduler every 60 seconds and runs due jobs in fresh agent sessions.
Step 2: Mental model pipeline = skills + cron, not workers
Most automation tutorials reach for queues and workers. Hermes flips this. The unit of work is a skill (markdown file in ~/.hermes/skills/) and the trigger is a cron job that loads one or more skills and runs them.
Here's the mapping for the TikTok pipeline:
Each skill is a markdown file the agent loads on demand. Cron jobs chain them via context_from. The Hermes scheduler runs each job in a fresh isolated session, so no state corruption between accounts.
Step 3: Create the skills
Skills live in ~/.hermes/skills/
Hook Researcher skill
bash
```bash
mkdir -p ~/.hermes/skills/tiktok/hook-researcher
```~/.hermes/skills/tiktok/hook-researcher/SKILL.md:
```markdown
---
name: tiktok-hook-researcher
description: Generate TikTok slideshow hooks for a given niche, eval, return top 3
version: 1.0.0
metadata:
hermes:
tags: [tiktok, content, hooks]
category: tiktok
---
# TikTok Hook Researcher
## When to Use
When asked to generate hooks for a TikTok slideshow in a specific niche.
## Procedure
1. Read the last 20 winning hooks for the niche from
`~/.hermes/data/tiktok/hook_performance.jsonl`.
2. Generate 10 hook candidates. Constraints:
- Under 60 characters
- Curiosity gap, not clickbait
- Mix of 3 archetypes: contrarian, listicle, transformation
3. Score each candidate 1-10 on "would a 19yo stop scrolling for this",
calibrated against the winning hooks.
4. Output JSON to stdout: `{ hooks: [{ text, archetype, score }, ...] }`
sorted by score descending. Return the top 3.
## Pitfalls
- LLMs default to clickbait. Bias hard against "You won't believe..." patterns.
- Don't reuse exact phrasing from the last 20 winners — algorithm penalizes recycled hooks.
## Verification
Output is valid JSON. Top hook has score ≥ 7. All hooks ≤ 60 chars.
```Image Source Router skill
This decides Pinterest vs AI gen per slot.
~/.hermes/skills/tiktok/source-router/SKILL.md:
```markdown
---
name: tiktok-source-router
description: Decide image source (pinterest or ai_gen) per slide for a TikTok carousel
version: 1.0.0
metadata:
hermes:
tags: [tiktok, images, routing]
category: tiktok
---
# TikTok Image Source Router
## When to Use
After a hook is picked, before image gathering. Decides per slide whether to
source from Pinterest or generate with AI.
## Procedure
1. Read the niche + hook from context.
2. Apply routing rules:
- Fitness, fashion, food, travel, aesthetic → Pinterest (real photos win)
- Anime/RPG, fictional characters, abstract concepts → AI gen
- Mixed niches: cover slide AI gen, body slides Pinterest
3. Output JSON array of 8 routing decisions:
`[{ slot, source, query_or_brief }, ...]`
## Pitfalls
- Don't AI-gen fitness transformations. Uncanny valley. Use Pinterest.
- Don't Pinterest-search for "anime warrior rank up". Doesn't exist. Use AI gen.
```Pinterest Scraper skill
This one needs a helper script because the agent shouldn't be doing HTTP rotation logic in-context.
```bash
mkdir -p ~/.hermes/skills/tiktok/pinterest-scraper/scripts
```~/.hermes/skills/tiktok/pinterest-scraper/SKILL.md:
```markdown
---
name: tiktok-pinterest-scraper
description: Source TikTok-ready images from Pinterest with proxy rotation and phash dedup
version: 1.0.0
required_environment_variables:
- name: PROXY_POOL_URL
prompt: Residential proxy pool endpoint
help: Bright Data, Smartproxy, or any rotating residential proxy
metadata:
hermes:
tags: [tiktok, pinterest, scraping]
category: tiktok
---
# TikTok Pinterest Scraper
## When to Use
Source router routes a slot to `pinterest`. Need fresh, unique, properly-sized
images for that account.
## Procedure
1. Call `scripts/scrape.py` with the search query and account_id:
`python scripts/scrape.py --query "{q}" --account {id} --count {n}`
2. The script handles:
- Proxy rotation per request
- Cookie pool rotation
- Perceptual hash dedup against the last 30 days for that account
- Aspect ratio filter (min 1080×1350)
- S3 upload to MinIO
3. Parse the script's stdout (JSON list of S3 URLs).
4. If count returned < requested, retry with rephrased query (max 2 retries).
## Pitfalls
- Pinterest rate-limits per IP. Always go through proxy.
- Hamming distance < 5 = duplicate. Don't relax this threshold.
- Anything < 1080×1350 will look soft on TikTok. Filter at search, not after download.
```~/.hermes/skills/tiktok/pinterest-scraper/scripts/scrape.py is a normal Python script. The agent invokes it via execute_code or terminal and parses stdout. The PROXY_POOL_URL declared above gets passed through automatically into execute_code sandboxes that's a Hermes feature that saved me a lot of env plumbing.
Slide Compositor no-agent mode
This stage is fully deterministic. No LLM needed. Hermes has no_agent mode for exactly this:
bash
```bash
mkdir -p ~/.hermes/scripts
```~/.hermes/scripts/compose-slides.py:
```python
#!/usr/bin/env python3
"""Composite 8 raw images + hook into TikTok-ready 1080x1920 slides.
Reads job spec from stdin (JSON), writes composited file paths to stdout.
"""
import json, sys
from PIL import Image, ImageDraw, ImageFont
# ...full Sharp/PIL compositing logic here...
if __name__ == "__main__":
spec = json.load(sys.stdin)
output_paths = compose_all(spec)
print(json.dumps({"slides": output_paths}))
```Then schedule it as a no_agent cron job wakeAgent never fires, no LLM cost on this step.
Publisher skill
~/.hermes/skills/tiktok/publisher/SKILL.md:
```markdown
---
name: tiktok-publisher
description: Upload composited slides to TikTok as draft via Postiz Cloud
version: 1.0.0
required_environment_variables:
- name: POSTIZ_API_KEY
prompt: Postiz Cloud API key
help: Get from postiz.com → Settings → API Keys
metadata:
hermes:
tags: [tiktok, publishing]
category: tiktok
---
# TikTok Publisher
## When to Use
After slides + caption are ready. Uploads as draft to TikTok via Postiz.
## Procedure
1. Read slides paths + caption + account_id from context.
2. Always check account age. If `< 30 days` or `total_posts < 20` → force draft mode.
Honestly even for old accounts I default to draft. There is zero upside to direct-publish.
3. Call `postiz-cli`:
postiz-cli schedule
--account {account_id}
--platform tiktok
--mode draft
--media {slide_paths}
--caption {caption}
--time {scheduled_iso}
4. Capture postId from stdout. Write to `~/.hermes/data/tiktok/posts.jsonl`.
## Pitfalls
- NEVER direct-publish on a new account. Silent shadow ban inside a week.
- Postiz CLI needs POSTIZ_API_KEY in env. Hermes passes it through automatically.
- Randomize scheduled time within ±90min jitter to kill robotic interval signal.
```Step 4: The shadow ban killer always draft mode
This is the part most tutorials skip and it's the biggest reason new accounts die.
If an account is less than 30 days old, ALWAYS post as draft. No exceptions.
New accounts on TikTok are on probation. The algorithm profiles:
Stack 2-3 of those on a fresh account and you get shadow banned silently. No notification. Videos stuck at 50-200 views forever. You'll think your content sucks. It doesn't the account is dead.
The Publisher skill above hardcodes draft mode for any account under 30 days / under 20 posts. Postiz uploads it as a draft, then my iPhone farm picks up the draft (via WebDriverAgent automation) and hits Publish from a real device with a real IP. TikTok sees a human-initiated publish from a known device clean.
Warmup protocol:
Hermes cron + Postiz Cloud + iPhone farm device publish = indistinguishable from organic behavior to TikTok's classifiers.
Step 5: Chain everything together with cron + context_from
This is the magic of Hermes' cron system. Each pipeline stage is a separate cron job. Job N reads the most recent output of Job N-1 via context_from. The chain runs end-to-end without me orchestrating anything.
I create the chain from a single chat session with Hermes:
text
hermes --tui
> I need to set up the TikTok pipeline for account acc_42, niche=fitness.
> Schedule the pipeline to run every day at 09:00 UTC.
> Chain: hook research → source routing → pinterest scrape → compose → caption → publish.
> Each stage should use the matching skill and receive context from the previous stage.
Hermes uses the cronjob tool internally and creates the chain. Here's what the equivalent direct calls look like (Hermes does this for you):
```python
# Stage 1: Hook research, daily at 09:00
cronjob(
action="create",
name="tt-hook-acc42",
schedule="0 9 * * *",
skills=["tiktok-hook-researcher"],
prompt="Generate hooks for niche=fitness for account acc_42. Output top 3 as JSON.",
workdir="/home/alex/tiktok-pipeline",
)
# Stage 2: Source routing, 5 minutes later
cronjob(
action="create",
name="tt-route-acc42",
schedule="5 9 * * *",
skills=["tiktok-source-router"],
context_from="tt-hook-acc42",
prompt="Route image sources for the top hook. Output 8 routing decisions.",
)
# Stage 3: Pinterest scrape (for pinterest-routed slots)
cronjob(
action="create",
name="tt-pinterest-acc42",
schedule="10 9 * * *",
skills=["tiktok-pinterest-scraper"],
context_from="tt-route-acc42",
prompt="For each pinterest-routed slot, scrape unique deduped images. Output S3 URLs.",
)
# Stage 4: Compositor — no_agent mode, pure script
cronjob(
action="create",
name="tt-compose-acc42",
schedule="20 9 * * *",
no_agent=True,
script="compose-slides.py",
context_from=["tt-pinterest-acc42", "tt-hook-acc42"],
name="tt-compose-acc42",
)
# Stage 5: Caption
cronjob(
action="create",
name="tt-caption-acc42",
schedule="25 9 * * *",
skills=["tiktok-caption-writer"],
context_from=["tt-hook-acc42", "tt-compose-acc42"],
prompt="Write caption + 4 hashtags for the slideshow.",
)
# Stage 6: Publish
cronjob(
action="create",
name="tt-publish-acc42",
schedule="30 9 * * *",
skills=["tiktok-publisher"],
context_from=["tt-compose-acc42", "tt-caption-acc42"],
prompt="Upload slides + caption as draft to TikTok account acc_42 via Postiz.",
deliver="telegram", # ping me when done
)
```A few key things:
context_from chains the outputs. Hermes reads each upstream job's most recent saved output from ~/.hermes/cron/output/{job_id}/ and prepends it to the next job's prompt as context. No databases, no queues, no glue code.
workdir runs the job inside the project directory. This means AGENTS.md, .cursorrules, and any local context files get auto-loaded. Useful when you keep account configs and prompt overrides in a project repo.
no_agent=True on the compositor. Pure deterministic Sharp/PIL work. No reason to pay for an LLM turn. The script's stdout becomes the job's output and chains to the next stage normally.
deliver="telegram" pings me when the publish completes. I use "all" for the final stage on the high-value account so I get the success ping on every connected channel.
Step 6: Per-stage toolset control (cost saver)
By default cron jobs inherit the toolsets you configured for the cron platform via hermes tools. But for cost control on high-frequency stages, lock toolsets per job:
```python
cronjob(
action="create",
name="tt-hook-acc42",
schedule="0 9 * * *",
skills=["tiktok-hook-researcher"],
enabled_toolsets=["file"], # hook gen only needs file read for past performance
prompt="...",
)
```Hook research doesn't need browser, terminal, or delegation toolsets — those bloat the tool-schema prompt on every LLM call. Locking the hook job to ["file"] cut my hook-gen tokens by ~40%. Across 30 accounts × 1 post/day × 30 days = real money.
The Pinterest scrape job needs ["terminal", "file"] to call the script. The compositor in no_agent mode doesn't load any toolsets (no agent runs). The publisher needs ["terminal", "file"] for postiz-cli.
Step 7: Skip the agent when nothing changed
Hermes has a pre-check script pattern that's perfect for the daily hook job. If the niche performance data hasn't changed since yesterday, there's no reason to generate fresh hooks yesterday's top 3 are still the top 3.
~/.hermes/scripts/hook-precheck.py:
```python
#!/usr/bin/env python3
import json, hashlib, pathlib, sys
perf_file = pathlib.Path.home() / ".hermes/data/tiktok/hook_performance.jsonl"
state_file = pathlib.Path.home() / ".hermes/state/hook-perf-hash.txt"
state_file.parent.mkdir(parents=True, exist_ok=True)
current_hash = hashlib.sha256(perf_file.read_bytes()).hexdigest()
last_hash = state_file.read_text().strip() if state_file.exists() else ""
if current_hash == last_hash:
# Nothing new since last run. Skip the agent.
print(json.dumps({"wakeAgent": False}))
sys.exit(0)
state_file.write_text(current_hash)
print(json.dumps({"wakeAgent": True, "context": {"perf_updated": True}}))
```Attach via the script parameter when creating the cron job. The agent only wakes when performance data actually changed. On a typical day where I haven't manually logged anything new, this skips the LLM entirely. Free.
Step 8: Postiz setup cloud (or you can self hosted) + the official Hermes skill
I tried self-hosting Postiz in Docker for 2 months. Spent more time fixing the container than building features OAuth token refreshes failing, media disk filling up, schedule worker dying silently. Postiz Cloud at $29/mo bought back ~5 hrs/week of debugging.
The 60-second setup:
bash
```bash
# 1. Sign up at postiz.com, get an API key from Settings → Developers → Public API
# 2. Install the official Postiz × Hermes skill
npx skills add gitroomhq/postiz-agent
# 3. Add the API key to Hermes env
echo "POSTIZ_API_KEY=pos_your_key_here" >> ~/.hermes/.env
# 4. Connect your TikTok accounts via the Postiz web UI (OAuth flow)
# Each connected account = one "integration" with a unique integration_id
# 5. Verify discovery from Hermes
hermes tools list | grep postiz # should show postiz commands available
postiz integrations:list # lists all connected channels
```The Postiz skill exposes itself to Hermes through this SKILL.md (lives in ~/.hermes/skills/postiz-agent/SKILL.md after install):
```markdown
---
name: postiz
description: Social media automation CLI for scheduling posts across 30+ platforms including TikTok
metadata:
hermes-agent:
requirements:
env:
- POSTIZ_API_KEY
binaries:
- postiz
---
# Available Commands
- postiz integrations:list
- postiz integrations:settings
- postiz posts:create
- postiz upload
- postiz analytics:platform
``` Hermes reads this on session start, registers the postiz binary as a tool, and now any cron job that loads this skill can call it.
API basics worth knowing
The two-layer mode system trips people up. Postiz has its own type: "draft" for posts that sit in Postiz's UI without going anywhere. That's NOT what we want. We want type: "schedule" with content_posting_method: "UPLOAD" Postiz schedules the post, pushes it to TikTok at the scheduled time, but as a TikTok-side draft that lands in the account's inbox for the iPhone farm to publish from a real device.
Wrong combination = wrong outcome. Test this on one account first.
Self-host only if you have compliance reasons or you're posting at volume that justifies it. Cloud has a real cost (30 req/hr cap per key), but self-host eats your hours.What I learned the hard way
Don't trust your first hooks. I ran the pipeline for 2 weeks blasting hook-archetype #1. Flat. Switched to A/B testing 3 archetypes per niche with a daily eval loop reading back from TikTok's view counts → killed the dead archetypes, doubled down on winners. CTR jumped within a week.
Pinterest beats AI for authentic niches. I spent 3 months optimizing image gen prompts for fitness transformation slides. Then tested 50/50 against Pinterest-scraped equivalents. Pinterest slides got 2.3x the saves. Real photos hit different. The fix: route per-niche.
Draft mode is non-negotiable for new accounts. I lost 4 accounts before I accepted this. Direct publish on a fresh account = silent shadow ban within the first week. You won't know until you've wasted 2 months of content on a dead account.
Resource:
Good luck guys 💪






