AIKit's marketing doesn't need a human marketer — it runs itself. Every day, a cron-driven CMO agent wakes up, checks the theme rotation, generates a full blog post via LLM, writes it into the queue, and publishes it to the live site. All of it is orchestrated through EmDash plugins, D1 storage, and KV settings. The result: 6+ blog posts per week, zero manual intervention, and a content engine that never sleeps.
The Challenge: Consistent Content at Scale
Marketing teams face a fundamental tension: producing high-quality technical content takes time, but the algorithm rewards consistency. Publishing weekly deep-dives about AIKit's architecture, plugin system, and MCP capabilities is essential for developer adoption — but it's also the kind of work that gets deprioritized when engineering sprints run hot.
The traditional solution is hiring a content manager or agency. The AIKit solution is building a CMO agent that automates the entire pipeline end-to-end.
The Solution: Autonomous Pipeline
The autonomous pipeline replaces the manual editorial workflow with an LLM-driven content engine. Here's what it does:
| Component | Role | Technology |
|-----------|------|------------|
| **CMO Agent** | Orchestrates content strategy & generation | EmDash plugin with LLM |
| **Cron Trigger** | Fires every N hours to keep content flowing | Cloudflare Workers Cron Triggers |
| **Queue System** | Stages drafts before publication | JSON files on local filesystem |
| **Theme Rotator** | Ensures topic variety across posts | Day-of-year + hour modulo arithmetic |
| **Publishers** | Push live to each channel | blog-publisher, devto-publisher, telegram-channel-publisher |
| **D1 Database** | Stores published posts and metadata | Cloudflare D1 (SQLite) |
| **KV Store** | Manages settings, rotation state, counters | Cloudflare KV |
Architecture Breakdown
1. The Cron Trigger
A scheduled cron job runs every 12 hours on production. It invokes the CMO agent with a specific task: generate the next blog post in the queue. The cron configuration is straightforward:
```toml
wrangler.toml
[triggers]
crons = ["0 */12 * * *"] # Every 12 hours
```
Each trigger call follows this flow:
1. Resolve current theme from day-of-year rotation
2. Determine project focus from hour-based rotation
3. Instruct LLM to generate a blog post matching the theme
4. Write the output JSON to the queue directory
5. Flag the post as ready for publishing
2. The LLM Generation Engine
The core generation happens inside the CMO agent's EmDash plugin. It receives a structured prompt with:
- **Theme context**: The current theme (from rotation)
- **Target format**: JSON schema for the queue file
- **Content guidelines**: Word count, headings, code blocks, tables
- **SEO metadata**: Auto-generated excerpt and tags
```python
Simplified generation flow
prompt = build_blog_prompt(
theme=current_theme,
project=project_focus,
post_number=next_post_number,
word_count_range=(800, 1500)
)
blog_post = llm_complete(prompt)
queue_path = f"/Users/tuannguyen/cmo/content/queue/{post_id}-{slug}.json"
write_queue_file(queue_path, blog_post)
```
The LLM handles all the heavy lifting: topic research, outline, drafting, formatting, and even SEO metadata extraction.
The Queue System Explained
The queue system is refreshingly simple — it's a directory of JSON files. Each file represents one draft blog post waiting to be published.
```
~/cmo/content/queue/
├── 410-aikit-mcp-hybrid-dev-marketing.json
├── 411-aikit-plugin-architecture-deep-dive.json
├── 412-aikit-llm-automation-workflows.json
└── 413-aikit-autonomous-marketing-pipeline-emdash-plugins.json
```
Each queue file follows a strict schema:
```json
{
"title": "Post title string",
"body_text": "Full markdown body (800-1500 words)",
"excerpt": "SEO-optimized one-paragraph summary",
"category": "Tutorials",
"tags": ["AIKit", "Marketing Automation", "EmDash", "LLM"]
}
```
The publish step reads the queue directory, picks the next file (by numeric prefix), inserts it into D1, and removes the file. This gives a natural backpressure — if publishing fails, the file stays in the queue and gets retried.
Theme Rotation & Project Focus
To avoid generating repetitive content, the pipeline uses two rotation systems:
Theme Rotation (Day-Level)
The primary theme is determined by `day_of_year % 4`:
| Index | Theme | Example Topics |
|-------|-------|----------------|
| 0 | **Hybrid Dev+Marketing** | MCP integrations, autonomous pipelines |
| 1 | **Technical Deep-Dive** | Plugin architecture, D1 schema, KV patterns |
| 2 | **Use Case / Tutorial** | Step-by-step guides, deployment walkthroughs |
| 3 | **Community & Ecosystem** | MCP marketplace, partner integrations |
Project Focus (Hour-Level)
Within each theme, the project focus cycles based on the current hour modulo the number of active projects:
```python
project_index = current_hour % len(active_projects)
project_focus = active_projects[project_index]
```
This ensures that over a 4-day cycle, every combination of theme and project gets covered. The active project list is stored in KV and can be updated without redeploying.
CMO Agent Skills
The CMO agent isn't a monolithic script — it's built from composable skills, each implemented as an EmDash plugin hook:
1. **blog-publisher** — Writes the post to the AIKit blog (D1 query → HTML render → site update)
2. **devto-publisher** — Cross-posts to dev.to via their API for developer reach
3. **telegram-channel-publisher** — Sends a formatted summary to the AIKit Telegram channel
4. **queue-manager** — Reads/writes queue files, tracks post numbers
5. **theme-resolver** — Computes current theme and project focus from time/date
6. **llm-generator** — Calls the LLM with structured prompts and validates output
Each skill is an independent EmDash plugin that registers hooks. The CMO agent orchestrates them through the EmDash event system:
```javascript
// Conceptual EmDash plugin registration
EmDash.register({
name: "blog-publisher",
hook: "cmo:publish:blog",
handler: async (event, context) => {
const post = context.queue.next();
await insertPostToD1(post);
await invalidateCDNCache("/blog/*");
return { published: true, slug: post.slug };
}
});
```
Key Takeaways
1. **Autonomous content is achievable today** — With LLMs, cron triggers, and a simple queue system, you can run a blog that produces 6+ posts per week with zero human writing.
2. **Theme rotation prevents staleness** — Combining day-of-year and hour-based rotation ensures consistent variety without manual topic selection.
3. **The queue system is the killer pattern** — JSON files in a directory provide natural backpressure, failure isolation, and debuggability. No complex message broker needed.
4. **EmDash plugins make the system composable** — Each publisher, generator, and manager is an independent plugin with clear hooks. Adding a new channel (e.g., LinkedIn, Medium) means writing one new plugin.
5. **End-to-end automation is the product** — When AIKit's own marketing runs on AIKit patterns (plugins, MCP, LLM pipelines), it's not just documentation — it's a proof by existence.
The pipeline described here is running in production right now. Every post you read on the AIKit blog was created by this autonomous system — including this one.