# Animus Blog Generator An automated blog generation pipeline powered by [Animus](https://github.com/launchapp-dev/animus-cli). It uses multiple AI agents working in sequence to research topics, write SEO-optimized posts, generate images, and create social media excerpts — all on autopilot. You configure it once for your business niche, and it handles the rest: finding topics worth writing about, collecting research, writing with your brand voice, optimizing for search engines and AI citations, and generating platform-specific social content.
Preview: what the workflow YAML looks like ```yaml # blog-engine.yaml — Automated SEO blog pipeline mcp_servers: exa: command: npx args: [-y, exa-mcp-server] env: { EXA_API_KEY: "${EXA_API_KEY}" } firecrawl: command: npx args: [-y, firecrawl-mcp-server] env: { FIRECRAWL_API_KEY: "${FIRECRAWL_API_KEY}" } # ... brave, tavily, google-maps, search-console, replicate, perplexity agents: content-strategist: model: claude-sonnet-4-6 mcp_servers: [exa, tavily, brave, firecrawl, search-console] system_prompt: | SKILLS: Read and follow .animus/skills/content-strategy.md CONTEXT: Read business-context.yaml for all client details. content-writer: model: claude-opus-4-6 mcp_servers: [] system_prompt: | SKILLS: Read and follow .animus/skills/content-production.md, .animus/skills/ai-seo.md, .animus/skills/content-humanizer.md CONTEXT: Read business-context.yaml for voice guidelines. seo-optimizer: model: claude-sonnet-4-6 mcp_servers: [search-console, firecrawl] system_prompt: | SKILLS: Read and follow .animus/skills/seo-audit.md, .animus/skills/schema-markup.md, .animus/skills/ai-seo.md # ... content-researcher, asset-generator, performance-analyst, content-refresher phases: topic-research: agent: content-strategist directive: | Pick ONE blog topic. Analyze Search Console for striking-distance keywords, scan industry news, check competitor blogs for gaps, and mine Reddit/forums for real questions. research-collection: agent: content-researcher directive: | Gather all source material. Scrape data sources via Firecrawl, search via Exa/Tavily/Brave, pull location data from Google Maps. content-writing: agent: content-writer directive: | Write the full blog post as markdown with YAML frontmatter. Follow the voice rules and SEO rules in your system prompt. seo-review: agent: seo-optimizer directive: | Audit and fix SEO issues in-place. Keyword density, meta tags, internal links, readability, AI cliche removal. asset-generation: agent: asset-generator directive: | Generate a featured image via Replicate (Nano Banana Pro). social-excerpts: agent: asset-generator directive: | Create platform-specific social content for Instagram, Facebook, and LinkedIn. # Workflows + schedules live in per-workflow files (workflow-*.yaml), e.g.: workflows: - id: blog-production phases: [topic-research, research-collection, content-writing, commit-draft, seo-review, asset-generation, social-excerpts, register-post, push-branch, publish-post] schedules: - { id: blog-primary, cron: "0 8 * * 2", workflow_ref: blog-production, enabled: false } # all schedules ship disabled ``` This preview is abridged. The real config is **split**: `custom.yaml` holds shared base config, `mcp_servers`, `subjects`, agents, and shared phases; each workflow (and its schedule) lives in its own [`.animus/workflows/workflow-*.yaml`](.animus/workflows/).
## How It Works The pipeline runs as a series of **workflows**, each made up of **phases** executed by specialized **agents**. Each agent has a specific role, its own set of tools (MCP servers), and access to your business context. ### Blog Production Workflow ``` topic-research ─→ research-collection ─→ content-writing ─→ commit-draft │ seo-review ─→ asset-generation ─→ social-excerpts ─→ register-post │ publish-post ←──────── push-branch ``` | Phase | Agent | What it does | |-------|-------|-------------| | **topic-research** | content-strategist | Picks the highest-priority topic by analyzing Search Console data, scanning industry news, checking competitor blogs for gaps, and mining forums for real questions | | **research-collection** | content-researcher | Gathers source material — scrapes reports, market data, government records via Firecrawl; searches via Exa, Tavily, Brave; pulls location data from Google Maps | | **content-writing** | content-writer | Writes the full blog post (1,500-2,500+ words) as markdown with YAML frontmatter, following your brand voice and SEO rules | | **commit-draft** | (command) | Git commits the draft | | **seo-review** | seo-optimizer | Audits and fixes SEO issues in-place — keyword density, meta tags, internal links, readability, AI cliche removal | | **asset-generation** | asset-generator | Generates a featured image via Replicate (Nano Banana Pro) and updates the post frontmatter | | **social-excerpts** | asset-generator | Creates platform-specific social media content (Instagram, Facebook, LinkedIn) | | **register-post** | register-post-runner (agent) | Runs `scripts/register-post.sh` to append the post to `content/manifest.json` (dedup index + internal-link slugs) | | **push-branch** | (command) | Pushes the branch to origin | | **publish-post** | (command) | *Optional.* Upserts the finished post into a database (Supabase/PostgREST by default). Skips unless configured; git stays the source of truth. See [publish targets](docs/integrations/publish-targets/README.md) | ### Other Workflows | Workflow | Purpose | Schedule | |----------|---------|----------| | **refresh-cycle** | Analyzes Search Console performance, identifies the most impactful post to refresh, updates statistics and data, re-optimizes SEO | Weekly | | **image-refresh** | Regenerates featured images for existing posts | On demand | | **news-monitor** | Scans for breaking industry news and auto-enqueues urgent blog topics | Daily | ### Agent Architecture Each agent is a Claude instance with a focused role. These are the **core content-pipeline** agents; the discovery flow adds more (transcript-collector, idea-strategist, approval-watcher, linear-coordinator, register-post-runner) — the full agent→MCP map is in [MCP-TOOLS.md](MCP-TOOLS.md). | Agent | Model | Role | Tools | |-------|-------|------|-------| | content-strategist | Sonnet 4.6 | Topic selection and content planning | Animus, Exa, Tavily, Brave, Firecrawl, Search Console, Content Library | | content-researcher | Sonnet 4.6 | Data collection and source gathering | Firecrawl, Exa, Tavily, Brave, Google Maps, Content Library | | content-writer | Opus 4.6 | Long-form content writing | Content Library | | seo-optimizer | Sonnet 4.6 | SEO auditing and fixing | Search Console, Firecrawl, Content Library | | asset-generator | Sonnet 4.6 | Image generation and social content | Replicate | | performance-analyst | Sonnet 4.6 | Content performance analysis | Animus, Search Console, Exa, Perplexity | | content-refresher | Opus 4.6 | Updating existing content | Firecrawl, Content Library | All **content** agents read `business-context.yaml` for your business details, brand voice, and content strategy (the data-plumbing agents — transcript-collector, approval-watcher, linear-coordinator, register-post-runner — do not). The content-writing agents also follow skill files in `.animus/skills/` that encode best practices for content production, SEO, humanization, and social media. ## Discovery Flow (transcript-driven) In addition to the cron-driven `blog-production` pipeline, this generator supports a transcript-driven discovery loop with a human-review gate in Linear (integrated as an Animus subject backend). **Daily 7am — `idea-discovery`.** Polls the configured transcript provider (Krisp or Granola) for new transcripts. The strategist proposes 3–5 angles per transcript, each pre-validated with Search Console + competitor scan + spot-scraped citable sources. Surviving angles become Linear issues (Animus subjects) at status `ready`. **Every 15 min — `approval-watch`.** Polls Linear-backed subjects for `status == in-progress` (the human-approval signal) and dispatches each newly-approved subject to `blog-from-ticket` via the queue (carrying `linear_subject_id`). Cancelled/Done/Blocked are filtered out. The gate is a deterministic script (`scripts/approval-watch.sh`), not an LLM — dedup is exact and a no-op poll costs no tokens. **Per approved ticket — `blog-from-ticket`.** A variant of blog-production using the Linear ticket as the topic brief. `ticket-acknowledge` and `ticket-to-brief` both re-check the subject's status; if the human cancelled after approval, the run aborts cleanly. `register-post` runs before `push-branch` so the manifest commit ships with the push. The last phase posts a completion comment; status transition is opt-in via `LINEAR_FINALIZE_TRANSITION=done`. **Authoritative-lifecycle invariant.** Linear is the single source of truth for lifecycle. The local SQLite `blogtask` wrapper — created by `scripts/approval-watch.sh` purely as a dispatch log — is subordinate and reference-only: no phase reads its status, and lifecycle is written back only to Linear (by `linear-finalize`). ### Transcript provider (Krisp or Granola) Transcripts flow through one provider-neutral MCP alias, `transcript-source`, in `.animus/workflows/custom.yaml`. Exactly one provider is active at a time, declared by `TRANSCRIPT_PROVIDER` and matched by what you wire under that alias. Switching providers is config-only — the collector agent normalizes either provider's tools into the staged transcript contract, and transcript ids are namespaced (`:`) so they never collide across a switch. Both **Krisp** and **Granola** ship official remote MCP servers (Streamable HTTP, OAuth — no static API key); Granola also has community local-cache servers for fully non-interactive macOS use. Per-provider endpoints, tool tables, auth/daemon trade-offs, and copy-paste wiring snippets are in **[`docs/integrations/transcript-providers/`](docs/integrations/transcript-providers/README.md)**. Until you wire one, `transcript-source` is a no-op stub and the discovery schedule stays disabled. ### One-time setup ```bash animus plugin install launchapp-dev/animus-subject-linear animus plugin list animus plugin ping --name animus-subject-linear ``` ### Daemon environment (`.env` is NOT auto-loaded) The Animus daemon does **not** auto-load `.env`. Source it into the daemon's parent shell before starting: ```bash set -a; source .env; set +a animus daemon start --autonomous ``` `ANIMUS_SQLITE_KINDS=blogtask` must be in that environment too — it routes the local SQLite backend onto a dedicated kind so it doesn't collide with markdown's `task`. ### Required `.env` values (placeholders are in `.env.example`) - `TRANSCRIPT_PROVIDER` (`krisp` or `granola`) — the official MCPs authenticate via OAuth (`animus mcp auth transcript-source`); `KRISP_API_KEY` / `GRANOLA_API_KEY` are only for non-MCP or community paths (see the [transcript-provider docs](docs/integrations/transcript-providers/README.md)) - `LINEAR_API_TOKEN`, `LINEAR_TEAM_ID`, `LINEAR_DISCOVERY_PROJECT_ID` - `CONTENT_LIBRARY_URL`, `CONTENT_LIBRARY_TOKEN` - `ANIMUS_SQLITE_KINDS=blogtask` Optional: `LINEAR_STATUS_MAP`, `LINEAR_FINALIZE_TRANSITION=done`. To publish finished posts to a database, also set `SUPABASE_URL` + `SUPABASE_SERVICE_ROLE_KEY` (+ optional `PUBLISH_TABLE`) — see [publish targets](docs/integrations/publish-targets/README.md); unset = publishing skipped. The `discovery` and `approval-watch` schedules ship **disabled** — flip them to `enabled: true` in their files (`.animus/workflows/workflow-idea-discovery.yaml` and `workflow-approval-watch.yaml`) once the secrets above are set and the daemon has been restarted. ### State Gitignored runtime state (`.animus/state/`): - `discovery-cursor.json` — last *processed* transcript (+ active `provider`) - `approval-seen.json` — already-enqueued Linear subject IDs - `transcripts/.json` — staged transcripts Tracked in repo (`content/manifest.json`): the canonical list of every post this generator produces — written by `register-post`, consumed for dedup + real internal-link slugs. ## Prerequisites - **[Animus CLI](https://github.com/launchapp-dev/animus-cli)** — Install the Animus command-line tool - **Node.js 18+** — Required for MCP servers (installed via npx) - **Git** — For version control of generated content - **API keys** — At least one search API (Exa, Tavily, or Brave). See [API Keys](#api-keys) below. ## Quick Start ### 1. Clone the repo ```bash git clone https://github.com/launchapp-dev/animus-blog-generator.git cd animus-blog-generator ``` ### 2. Install Animus plugins (one-time) The daemon needs provider, queue, and workflow-runner plugins. The discovery flow additionally needs the Linear subject backend. ```bash animus plugin install-defaults # providers + queue + runner animus plugin install launchapp-dev/animus-subject-linear # only for the discovery flow animus daemon preflight # verifies required roles are satisfied ``` ### 3. Configure secrets ```bash cp .env.example .env # Edit .env — at minimum one search key (EXA / TAVILY / BRAVE). # See "Required .env values" above for the full set. ``` ### 4. Create your business context The pipeline reads `business-context.yaml` (niche, audience, brand voice, pillars) on every run. Create it manually — see [Business Context](#business-context) below — or ask Claude Code to run the **setup-wizard** skill, which generates it interactively. (There is no `workflow run setup`; the wizard is a skill, not a workflow.) ### 5. Start the daemon The daemon does **not** auto-load `.env`, so source it into the daemon's shell first; `ANIMUS_SQLITE_KINDS=blogtask` must be present too (see [Daemon environment](#daemon-environment-env-is-not-auto-loaded)). ```bash set -a; source .env; set +a animus daemon start --autonomous ``` ### 6. Run your first blog post ```bash animus workflow run blog-production ``` The first run typically takes 15–30 minutes as agents research, write, optimize, and generate assets. Output lands in `content/` and `assets/` and is committed/pushed to a branch. ### 7. Enable scheduled runs (optional) **All schedules ship disabled.** To automate runs, flip `enabled: true` on the schedule in the relevant `.animus/workflows/*.yaml`, then persist the config (the running daemon also hot-reloads YAML edits): ```bash animus workflow config compile ``` Default (currently disabled) schedules: - **`blog-primary`** — Tue 8am · **`blog-secondary`** — Thu 8am → `blog-production` - **`refresh`** — Wed 8am → `refresh-cycle` - **`news`** — daily 6am → `news-monitor` - **`discovery`** — daily 7am · **`approval-watch`** — every 15 min → discovery flow (also needs Linear + transcript secrets) ## Configuration # MCP Tools The blog generator ships with **9 core content-pipeline MCP servers** that give agents access to search, scraping, analytics, image generation, and self-orchestration. The discovery flow adds two more bring-your-own servers — `transcript-source` and `content-library` — covered under [Discovery Flow](#discovery-flow-transcript-driven). ## Search & Discovery | Server | Package | What It Does | |--------|---------|--------------| | **Exa** | `exa-mcp-server` | Neural/semantic search — finds topically relevant content, competitor articles, and research papers | | **Tavily** | `tavily-mcp` | AI-optimized search — returns structured, LLM-friendly results for research queries | | **Brave Search** | `@anthropic/brave-search-mcp` | Web search — broad coverage for news, forums, Reddit threads, and general queries | ## Data Extraction | Server | Package | What It Does | |--------|---------|--------------| | **Firecrawl** | `firecrawl-mcp-server` | Web scraping — extracts clean content from industry reports, competitor blogs, government data | | **Google Maps** | `google-maps-mcp-server` | Location data — business details, local context, neighborhood info for geo-relevant content | ## Analytics & Performance | Server | Package | What It Does | |--------|---------|--------------| | **Search Console** | `search-console-mcp` | Google Search Console — ranking data, click-through rates, striking-distance keywords, performance trends | | **Perplexity** | `@perplexity/modelcontextprotocol` | AI citation tracking — checks whether your content is being cited by LLM-powered search engines | ## Asset Generation | Server | Package | What It Does | |--------|---------|--------------| | **Replicate** | `replicate-mcp` | Image generation — creates featured images via Google's Nano Banana Pro model (16:9, no text/watermarks) | ## Orchestration | Server | Package | What It Does | |--------|---------|--------------| | **animus** | `animus mcp serve` | Animus self-management — task creation, queue management, lets agents schedule follow-up work | ## Which Agents Use What Core content pipeline (the discovery-flow agents — transcript-collector, idea-strategist, approval-watcher — are covered under [Discovery Flow](#discovery-flow-transcript-driven); the full map is in [MCP-TOOLS.md](MCP-TOOLS.md)): ``` Strategist → animus, exa, tavily, brave, firecrawl, search-console, content-library Researcher → firecrawl, exa, tavily, brave, google-maps, content-library Writer → content-library SEO Optimizer → search-console, firecrawl, content-library Asset Generator → replicate Performance Analyst → animus, search-console, exa, perplexity Content Refresher → firecrawl, content-library ``` ## Publishing to a database The pipeline writes posts as markdown to git (the source of truth). To also upsert each finished post into a database, the optional **`publish-post`** phase ships built in (Supabase/PostgREST by default, swappable). Set `SUPABASE_URL` + `SUPABASE_SERVICE_ROLE_KEY` to enable it — see [publish targets](docs/integrations/publish-targets/README.md). It skips cleanly when unconfigured. Agents degrade gracefully on missing *optional* tools — without Search Console, `topic-research` leans more on web search. Note that `asset-generation` (Replicate) is a **required** phase in `blog-production`: if you don't have a Replicate token, remove that phase from the workflow rather than expecting it to be skipped automatically. ### Business Context `business-context.yaml` is the central configuration file. Every content agent reads it. It defines: ```yaml business: name: "Your Business" # Business or brand name niche: "your industry" # e.g., real estate, SaaS, fitness location: "City, State" # Where you're based scope: "local" # local | regional | national | global services: [...] # Core offerings differentiator: "..." # What makes you unique blog_url: "https://..." # Where blog posts are published audience: ideal_reader: "..." # One-sentence reader description common_questions: [...] # Questions they ask before buying objections: [...] # What holds them back competitors: - name: "Competitor A" notes: "..." voice: perspective: "first-person" # first-person | first-person-plural | third-person author_name: "Your Name" author_bio: "..." tone: ["practical", "data-driven"] banned_words: ["delve", ...] # AI cliches are banned by default content: pillars: [...] # 3-7 topic categories target_word_count: 2000 publish_frequency: "2x per week" social_platforms: ["Instagram", "Facebook", "LinkedIn"] ``` Create it manually, or ask Claude Code to run the **setup-wizard** skill, which generates it interactively. (`setup-wizard` is a skill, not a `workflow run setup` target.) ### Publishing to a database or CMS The pipeline writes posts as markdown to git (the source of truth) and, optionally, upserts each finished post into a database via the built-in **`publish-post`** phase (Supabase/PostgREST by default). To enable or retarget it, see [publish targets](docs/integrations/publish-targets/README.md). To push to a CMS instead, point `scripts/publish-post.sh`'s two seams (`build_payload()` + `publish()`) at your CMS's API. ## Project Structure ``` animus-blog-generator/ ├── .animus/ │ ├── skills/ # Agent skill files (markdown — source of truth) │ │ ├── setup-wizard.md # Interactive business setup │ │ ├── content-strategy.md # Topic planning best practices │ │ ├── content-production.md # Writing pipeline guide │ │ ├── content-humanizer.md # De-AI-ify content │ │ ├── ai-seo.md # AI search optimization │ │ ├── seo-audit.md # SEO audit checklist │ │ ├── schema-markup.md # Structured data guide │ │ └── social-content.md # Social media content guide │ └── workflows/ # Config is split across these files │ ├── custom.yaml # Shared base config, mcp_servers, subjects, agents, shared phases │ ├── workflow-blog-production.yaml │ ├── workflow-blog-from-ticket.yaml │ ├── workflow-idea-discovery.yaml │ ├── workflow-news-monitor.yaml │ ├── workflow-refresh-cycle.yaml │ ├── workflow-image-refresh.yaml │ └── workflow-approval-watch.yaml ├── scripts/ # approval-watch.sh, register-post.sh, publish-post.sh (+ bats tests) ├── content/ # Generated blog posts (.md) ├── assets/ # Generated images (.webp) ├── business-context.yaml # Your business config (generated by setup wizard) ├── .env.example # API key template ├── .env # Your API keys (gitignored) ├── .mcp.json # MCP server config for Claude Code ├── CLAUDE.md # Project instructions for Claude └── README.md ``` ## Skills Skills are markdown files that encode domain expertise. Agents reference them in their system prompts. They come from the [Animus marketing skills library](https://github.com/launchapp-dev/animus-cli) and can be customized. | Skill | What it teaches the agent | |-------|--------------------------| | **content-strategy** | Topic discovery, pillar planning, keyword gap analysis, competitor content mapping | | **content-production** | End-to-end writing: research briefs, drafting, SEO optimization, quality gates | | **content-humanizer** | Detecting and removing AI writing patterns, injecting brand voice, fixing rhythm | | **ai-seo** | Optimizing for AI search citations (ChatGPT, Perplexity, Google AI Overviews) | | **seo-audit** | Technical and on-page SEO auditing with actionable fix recommendations | | **schema-markup** | JSON-LD structured data for rich results and AI readability | | **social-content** | Platform-specific social media content creation and strategy | | **setup-wizard** | Interactive business context questionnaire and config generation | ## Customization ### Adjust the pipeline Edit `.animus/workflows/custom.yaml` to: - **Change agent models** — Swap `claude-opus-4-6` for `claude-sonnet-4-6` to reduce cost, or vice versa for higher quality - **Add/remove MCP servers** — Enable only the search APIs you have keys for - **Modify phase directives** — Change what each agent does in its phase - **Adjust schedules** — Change publishing frequency and timing - **Add new phases** — Insert custom steps (e.g., email newsletter generation, translation) After editing, always run: ```bash animus workflow config compile ``` ### Customize agent behavior Edit the skill files in `.animus/skills/` to change how agents approach their work. These are markdown files with best practices — agents read and follow them. ### Override voice and content rules Edit `business-context.yaml` to change your brand voice, content pillars, or publishing preferences at any time. Changes take effect on the next workflow run. ## License MIT