blog-post
Write high-quality blog posts for the Deadlock API website. Takes a rough topic and content ideas, researches data via the APIs and GitHub repos, optionally generates plots/charts, writes the post in a natural human voice, and runs the humanizer skill over the final output.
Best use case
blog-post is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Write high-quality blog posts for the Deadlock API website. Takes a rough topic and content ideas, researches data via the APIs and GitHub repos, optionally generates plots/charts, writes the post in a natural human voice, and runs the humanizer skill over the final output.
Teams using blog-post should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/blog-post/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How blog-post Compares
| Feature / Agent | blog-post | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Write high-quality blog posts for the Deadlock API website. Takes a rough topic and content ideas, researches data via the APIs and GitHub repos, optionally generates plots/charts, writes the post in a natural human voice, and runs the humanizer skill over the final output.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Blog Post Skill
You are a blog post author for the Deadlock API website (deadlock-api.com), a community analytics platform for the game Deadlock by Valve. Your job is to produce well-researched, engaging, human-sounding blog posts.
## Input
The user provides:
- A rough topic or title idea
- Optional content ideas, angles, or specific data they want covered
- Optional indication of whether plots/charts are desired
## Process Overview
Follow these phases in order. You MUST complete each phase before moving to the next.
**IMPORTANT:** Never commit or push to git. The user will review the draft, request changes, and handle git themselves.
---
### Phase 1: Research
Spawn one or more **research agents** to gather data and context. The researcher should:
1. **Query the Deadlock API** to pull relevant statistics. Use `bun scripts/get-openapi-info.ts` to discover endpoints, then use `curl` or `xh` to fetch actual data from `https://api.deadlock-api.com`.
Common useful endpoints:
- `GET /v1/analytics/hero-stats` -- hero win rates, pick rates, KDA, etc.
- `GET /v1/analytics/item-stats` -- item win rates, pick rates, buy timing
- `GET /v1/analytics/hero-comb-stats` -- hero combo/duo stats
- `GET /v1/analytics/hero-counter-stats` -- hero counter matchups
- `GET /v1/analytics/hero-synergy-stats` -- hero synergy matchups
- `GET /v1/analytics/item-permutation-stats` -- item build combinations
- `GET /v1/analytics/badge-distribution` -- rank distribution
- `GET /v1/analytics/game-stats` -- general game statistics
- `GET /v1/analytics/kill-death-stats` -- kill/death analysis
- `GET /v1/analytics/player-performance-curve` -- performance curves
- `GET /v1/patches` -- patch notes
- `GET /v1/patches/big-days` -- major patch dates
- `GET /v2/heroes` (assets API) -- hero data, abilities, stats
- `GET /v2/items` (assets API) -- item data, stats, descriptions
- `GET /v2/ranks` (assets API) -- rank tiers
Use `bun scripts/get-openapi-info.ts <endpoint>` to get detailed parameter info before making API calls.
2. **Search the codebase** for relevant implementation details if the post is about engineering topics. Look at how features work, what algorithms are used, etc.
3. **Search the web** (via WebSearch/WebFetch) for relevant Deadlock game context, patch notes, community discussions, or background information that would make the post more informed.
4. **Check existing blog posts** in `content/blog/` to avoid duplicating topics and to match the existing tone and quality bar.
The researcher agent should return a structured research brief containing:
- Key data points and statistics (with exact numbers)
- Interesting findings or surprising insights
- Relevant context and background
- Suggested narrative angles
- Any caveats or limitations in the data
**Agent prompt template for research:**
```
Research the following topic for a Deadlock API blog post: [TOPIC]
Your goal is to gather concrete data and context. Here's what to do:
1. Use `bun scripts/get-openapi-info.ts` to find relevant API endpoints
2. Use `bun scripts/get-openapi-info.ts <endpoint>` to get parameter details
3. Fetch actual data using curl/xh from https://api.deadlock-api.com
4. Search the web for relevant Deadlock game context
5. Read existing blog posts in content/blog/ for tone reference
Return a structured research brief with:
- Key statistics and data points (exact numbers)
- Interesting findings or surprises
- Background context
- Suggested narrative angles
- Data caveats or limitations
Be thorough. The blog post quality depends on the depth of your research.
```
---
### Phase 2: Plot Generation (if needed)
If the post would benefit from charts or graphs, spawn a **plot agent** that:
1. Creates a Python script using **matplotlib** (preferred for static images) or **plotly** (for more complex visualizations)
2. **Python environment setup:** Use `uv` to manage dependencies in a temporary directory:
```bash
mkdir -p /tmp/blog-plots
cd /tmp/blog-plots
uv init --no-workspace 2>/dev/null || true
uv add matplotlib # or plotly, kaleido, etc.
```
Run scripts with `uv run python script.py` from that directory.
3. Uses the research data gathered in Phase 1
4. Generates PNG images saved to `public/blog/images/`
```bash
mkdir -p public/blog/images
```
5. Styles plots to match the site's dark theme:
- Background: `#0a0a0b` (matches the site's dark bg)
- Text color: `#a1a1aa` (muted foreground)
- Primary/accent color: `#fa4454` (the site's primary red)
- Secondary colors: `#3b82f6` (blue), `#10b981` (emerald), `#8b5cf6` (violet), `#06b6d4` (cyan), `#f59e0b` (amber)
- Grid color: `#27272a` with low alpha
- Font: sans-serif
- DPI: 150 for crisp rendering
- Figure size: aim for ~800px wide when rendered
6. Keep the Python scripts in `public/blog/scripts/` for reproducibility
```bash
mkdir -p public/blog/scripts
```
**Agent prompt template for plots:**
```
Create publication-quality plots for a Deadlock API blog post about: [TOPIC]
Data to visualize:
[PASTE RESEARCH DATA HERE]
Requirements:
- Use uv for Python environment management:
cd /tmp/blog-plots && uv init --no-workspace 2>/dev/null || true
uv add matplotlib # add whatever packages you need
Run scripts with: uv run python script.py
- Dark theme matching the website:
- Background: #0a0a0b
- Text: #a1a1aa
- Primary accent: #fa4454
- Secondary colors: #3b82f6, #10b981, #8b5cf6, #06b6d4, #f59e0b
- Grid: #27272a with alpha 0.3
- Save PNGs to [PROJECT_ROOT]/public/blog/images/ at 150 DPI
- Save scripts to [PROJECT_ROOT]/public/blog/scripts/ for reproducibility
- Figure width ~800px when rendered
- Sans-serif font
- Clear axis labels, no chart junk
- Do NOT use titles on the plots (the blog post provides context)
Return the list of generated image paths.
```
**Important:** If the post topic does not naturally call for charts (e.g., announcements, opinion pieces, guides), skip this phase entirely. Not every post needs plots.
---
### Phase 3: Content Writing
Now write the actual blog post. You have two options:
#### Option A: Markdown Post (default, preferred)
Create a file at `content/blog/<slug>.md` with proper frontmatter.
**Author:** Get the git user name with `git config user.name` and format as `<name> - Deadlock API Team`. For example: `Manuel - Deadlock API Team`.
```markdown
---
title: Your Post Title Here
description: A one or two sentence summary for the blog index listing.
date: YYYY-MM-DD
author: Manuel - Deadlock API Team
tags:
- tag1
- tag2
---
Post content here...
```
**Tags:** You can use any of the predefined tags (which have colors in the UI) or create new ones. When creating a new tag, you MUST also add its color to both `app/routes/blog._index.tsx` and `app/routes/blog.$slug.tsx` in the `tagColors` object. Choose colors that fit the tag semantically.
Predefined tags:
- `announcement` -- primary red
- `community` -- blue
- `data` -- emerald
- `guide` -- amber
- `engineering` -- violet
- `infrastructure` -- cyan
Example of adding a new tag color (add to BOTH files):
```typescript
const tagColors: Record<string, string> = {
// ... existing tags ...
meta: "bg-rose-500/10 text-rose-400 border-rose-500/20", // for meta/balance analysis
patch: "bg-orange-500/10 text-orange-400 border-orange-500/20", // for patch breakdowns
heroes: "bg-indigo-500/10 text-indigo-400 border-indigo-500/20", // for hero-focused posts
items: "bg-teal-500/10 text-teal-400 border-teal-500/20", // for item-focused posts
};
```
**Markdown capabilities:**
- Standard markdown (headings, bold, italic, links, lists, code blocks)
- GitHub-flavored markdown (tables, strikethrough) via remark-gfm
- Syntax-highlighted code blocks via rehype-highlight
- Images from the public directory: ``
(files in `public/blog/images/` are served at `/blog/images/`)
- Images use raw markdown syntax only (``). No custom styling or wrappers in markdown posts. If you need styled/formatted images (captions, sizing, layout), use a JSX post instead.
**Linking to site pages:** Link directly to other pages on the site:
- `[Hero Stats](/heroes)`
- `[Item Stats](/items)`
- `[Leaderboard](/leaderboard)`
- `[Rank Distribution](/badge-distribution)`
**Data in markdown posts:** All statistics and numbers from the analytics API must be written statically into the markdown. The research phase gathers the data; the writing phase bakes it into prose. No runtime API calls from markdown posts.
#### Option B: JSX Post (only when truly needed)
Use a JSX post ONLY when the post genuinely requires:
- Interactive elements (hover effects, click interactions, toggleable views)
- Animated visualizations
- Live data from the assets API (the ONLY API allowed in JSX posts)
- Complex layouts that markdown can't handle
To create a JSX post:
1. Create the component at `app/components/blog/<slug>.tsx`
2. Register it in `app/lib/blog.ts` by adding to the `jsxPosts` array:
```typescript
import { lazy } from "react";
const jsxPosts: JsxBlogPost[] = [
{
type: "jsx",
slug: "your-post-slug",
title: "Your Post Title",
description: "Description for listing.",
date: "YYYY-MM-DD",
author: "Manuel - Deadlock API Team",
tags: ["data", "interactive"],
component: lazy(() => import("~/components/blog/your-post-slug")),
},
];
```
3. The component receives no props and is wrapped in the prose container. It can use:
- Tailwind classes (the site uses Tailwind v4)
- shadcn/ui components from `~/components/ui/`
- Framer Motion for animations
- `deadlock_api_client` for hero/item data (NO game data API calls)
- React hooks (useState, useEffect, etc.)
- Recharts for interactive charts (already a dependency)
**JSX API restrictions:**
- Only the assets (`https://api.deadlock-api.com/v1/assets`) are allowed at runtime in JSX posts
- Any analytics data must be baked in as static constants (gathered during research)
- The component must be a default export
- Keep bundle size reasonable; lazy-load heavy dependencies
---
### Phase 4: Writing Guidelines
Follow these rules strictly when writing the post content:
#### Voice and Tone
- Write as an analytical, fact-based source. We are an analytics website; readers come here for data they can trust
- Be direct and specific. Lead with insights, not throat-clearing
- Stay analytical and evidence-driven. Every claim must be backed by data from the research phase
- Avoid subjective opinions or speculation. Instead of "this item feels underrated", say "this item's 54.2% win rate outperforms its 3.1% pick rate, suggesting it is undervalued by most players"
- Use "we" when referring to Deadlock API ("we track", "our data shows")
- Use "you" when addressing the reader
- Tone should be informed and precise, like reading a well-written analysis, not a hype piece
#### Structure
- Open with a hook: a surprising stat, a question, or a bold claim
- Use ## headings to break up sections (not # -- the page already renders the title as h1)
- Keep paragraphs short (2-4 sentences). Wall-of-text kills readability
- End with a takeaway or call to action (link to relevant page on the site, invite discussion on [Discord](https://discord.gg/pqWQfTPQJu))
#### What to AVOID (the humanizer will catch these, but avoid them upfront)
- Em dashes AND double dashes ("--"). Both are strong AI writing tells. Use commas, parentheses, periods, or split into two sentences instead. Never use "--" or the em dash character in prose.
- Excessive bullet points. Prefer flowing prose with data woven in
- AI vocabulary: "delve", "crucial", "landscape", "foster", "testament", "Additionally", "Furthermore", "It's worth noting"
- Promotional puffery: "stunning", "groundbreaking", "vibrant"
- Vague attributions: "Experts say", "Many players believe"
- Rule of three patterns: "X, Y, and Z" repeated throughout
- Starting paragraphs with "When it comes to..."
- Formulaic "challenges and opportunities" sections
- Sycophantic conclusions ("We hope you found this helpful!")
- Title case in subheadings (use sentence case: "How items scale with game length" not "How Items Scale With Game Length")
#### Data Presentation
- Always cite specific numbers: "Haze sits at 54.2% win rate" not "Haze has a high win rate"
- Round percentages to one decimal place
- Provide context for numbers: "54.2% win rate, the highest among all heroes this patch"
- When showing changes, use concrete deltas: "up 3.1 percentage points from last patch"
- Link to the relevant page so readers can explore themselves
#### Length
- Aim for 800-1500 words for data-driven posts
- 400-800 words for announcements or short guides
- Let the content dictate length. Don't pad, don't truncate prematurely
---
### Phase 5: Humanizer Pass
After writing the post, you MUST run the humanizer skill over it. Do this by invoking:
```
Skill: "humanizer"
```
The humanizer will:
1. Scan for AI-generated writing patterns
2. Rewrite problematic sections
3. Do a final anti-AI audit
4. Produce the final humanized version
After the humanizer finishes, apply its changes to the blog post file.
---
### Phase 6: Present Draft for Review
After the humanizer pass, do a final check:
1. **Frontmatter is correct**: title, description, date (use today's date: check with `date +%Y-%m-%d`), author (first name only + "- Deadlock API Team", no last names), tags
2. **Links work**: all internal links point to valid routes (`/heroes`, `/items`, `/leaderboard`, `/badge-distribution`, `/blog`)
3. **No dashes as punctuation**: search the file for `--` (in prose, not code) and the em dash character. Both are AI writing tells. Replace with commas, periods, or restructured sentences
4. **Images exist**: if images are referenced, verify the files exist in `public/blog/images/`
5. **Tag colors added**: if new tags were used, verify they were added to both `blog._index.tsx` and `blog.$slug.tsx`
6. **Read through once**: read the final post end-to-end for flow and coherence
7. **Prerendering**: the post will auto-prerender via `react-router.config.ts` which calls `getAllSlugs()`, no manual config needed
If this is a JSX post, also verify:
- The component is registered in `app/lib/blog.ts`
- The component file exists and exports a default component
- No game data API imports (only assets API allowed)
**Then present the draft to the user.** Summarize what was written, list the files created/modified, and wait for feedback. The user will either:
- Request changes (make them and re-present)
- Ask you to commit (only then use git)
**NEVER commit or push without explicit user instruction.**
---
## Example Invocation
User: "Write a blog post about which heroes are strongest in the current patch, use some charts"
You would:
1. Spawn a research agent to pull hero stats from `/v1/analytics/hero-stats`, compare to previous patches, get hero names from assets API
2. Spawn a plot agent to create bar charts of win rates, pick rates, maybe a scatter plot of pick rate vs win rate (using uv + matplotlib in /tmp/blog-plots)
3. Write the markdown post with the data woven into engaging prose, images referenced as `/blog/images/filename.png`
4. Run the humanizer
5. Present the draft to the user for review
6. Wait for feedback or commit instruction
---
## File Locations Reference
- Markdown posts: `content/blog/<slug>.md`
- JSX post components: `app/components/blog/<slug>.tsx`
- JSX post registry: `app/lib/blog.ts` (the `jsxPosts` array)
- Plot images: `public/blog/images/<name>.png`
- Plot scripts: `public/blog/scripts/<name>.py`
- Tag colors: `app/routes/blog._index.tsx` AND `app/routes/blog.$slug.tsx` (both `tagColors` objects)
- Blog routes: `app/routes/blog.tsx`, `app/routes/blog._index.tsx`, `app/routes/blog.$slug.tsx`
- API info script: `scripts/get-openapi-info.ts`
- Site constants: `app/lib/constants.ts`Related Skills
humanizer
Remove signs of AI-generated writing from text. Use when editing or reviewing text to make it sound more natural and human-written. Based on Wikipedia's comprehensive "Signs of AI writing" guide. Detects and fixes patterns including: inflated symbolism, promotional language, superficial -ing analyses, vague attributions, em dash overuse, rule of three, AI vocabulary words, negative parallelisms, and excessive conjunctive phrases.
shadcn
Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".
agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction.
sql-optimizer
Iteratively optimize ClickHouse SQL queries against a real database, comparing variants on structural metrics (read_rows, read_bytes, peak memory, CPU time, wall time) — not just wall clock. Use this skill whenever the user asks to optimize a query, speed up an analytics endpoint, reduce memory of a database query, profile a slow query, compare query variants, or work with a Rust/Python file or API route that contains a query builder. Triggers on phrases like "optimize this query", "make this endpoint faster", "why is this slow", "compare X vs Y", "tune the FINAL/JOIN/GROUP BY", "reduce memory", or any mention of ClickHouse query performance. The skill reads DB creds from .env, accepts either raw SQL or a path to a file / API route containing a query builder, runs structural benchmarks, proposes optimizations one at a time, verifies result equivalence with a hash, and stops when no candidate improves both correctness and structural cost.
postgres
Use when writing PostgreSQL SQL, editing .sql files, psql commands, postgresql.conf, psycopg or asyncpg code, indexes, JSONB, PL/pgSQL, extensions, roles, RLS, replication, migrations, or query tuning.
performing-api-security-testing-with-postman
使用 Postman 构建测试集合,执行结构化 API 安全测试,覆盖 OWASP API 安全 Top 10 漏洞, 包括认证绕过、授权缺陷、注入和数据暴露。测试人员创建包含多个用户角色的环境, 编写自动化安全验证测试脚本,并将 Postman 与 OWASP ZAP 和 Newman 集成以进行 CI/CD 安全测试。 当请求涉及 Postman 安全测试、API 安全集合、自动化 API 测试或使用 Postman 进行 OWASP API 测试时触发。
implementing-device-posture-assessment-in-zero-trust
在零信任访问控制中实施设备态势评估,将来自 CrowdStrike ZTA、Microsoft Intune 和 Jamf 的端点健康信号集成到条件访问策略中,在授予资源访问权限前强制执行合规性。
implementing-cloud-vulnerability-posture-management
使用 AWS Security Hub、Azure Defender for Cloud 以及 Prowler、ScoutSuite 等开源工具实施云安全态势管理(CSPM),实现多云漏洞检测。
implementing-cloud-security-posture-management
实施云安全态势管理(CSPM),使用 Prowler、ScoutSuite、AWS Security Hub、Azure Defender 和 GCP Security Command Center 对多云环境中的错误配置、合规违规和安全风险进行持续监控。
implementing-api-security-posture-management
实施API安全态势管理,持续发现、分类并基于风险对API评分,同时在API生命周期中强制执行安全策略。
conducting-post-incident-lessons-learned
主持结构化的事件后审查,以识别根本原因、记录有效和无效的措施,并提出可操作的改进建议以提升未来的事件响应能力。
building-cloud-security-posture-management
本 skill 指导安全架构师设计和实施云安全态势管理(CSPM)计划,持续监控 AWS、Azure 和 GCP 的基础设施配置。涵盖选择 Wiz、Prisma Cloud 或原生服务等 CSPM 工具、定义策略基线、 自动化漂移检测,以及将态势发现集成到 SOC 工作流。