@tamng0905/builder-essential-skills 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/lead-builder.md +55 -0
- package/.claude/agents/lead-reviewer.md +39 -0
- package/README.md +276 -0
- package/assets/readme-hero.png +0 -0
- package/assets/skill-cards/async-learning-teacher.svg +7 -0
- package/assets/skill-cards/code-standards.svg +7 -0
- package/assets/skill-cards/lead-research.svg +7 -0
- package/assets/skill-cards/lead.svg +7 -0
- package/assets/skill-cards/orwell-writing.svg +7 -0
- package/assets/skill-cards/session-profiler.svg +7 -0
- package/assets/skill-cards/validate-market.svg +7 -0
- package/assets/skill-cards/write-blog.svg +7 -0
- package/bin/builder-essential-skills.js +134 -0
- package/install.ps1 +58 -0
- package/install.sh +63 -0
- package/package.json +24 -0
- package/skills/async-learning-teacher/README.md +50 -0
- package/skills/async-learning-teacher/SKILL.md +192 -0
- package/skills/async-learning-teacher/agents/openai.yaml +4 -0
- package/skills/code-standards/README.md +27 -0
- package/skills/code-standards/SKILL.md +51 -0
- package/skills/lead/README.md +29 -0
- package/skills/lead/SKILL.md +222 -0
- package/skills/lead/config.py +359 -0
- package/skills/lead/dispatch.md +342 -0
- package/skills/lead/loop.md +103 -0
- package/skills/lead/models.json +34 -0
- package/skills/lead/research.md +76 -0
- package/skills/lead/status.ps1 +114 -0
- package/skills/lead/status.sh +110 -0
- package/skills/lead/watchdog.ps1 +90 -0
- package/skills/lead/watchdog.sh +88 -0
- package/skills/lead-research/README.md +27 -0
- package/skills/lead-research/SKILL.md +157 -0
- package/skills/lead-research/tactics.md +150 -0
- package/skills/orwell-writing/README.md +27 -0
- package/skills/orwell-writing/SKILL.md +44 -0
- package/skills/orwell-writing/agents/openai.yaml +4 -0
- package/skills/session-profiler/README.md +25 -0
- package/skills/session-profiler/SKILL.md +103 -0
- package/skills/session-profiler/agents/openai.yaml +4 -0
- package/skills/session-profiler/scripts/requirements.txt +2 -0
- package/skills/session-profiler/scripts/session_profiler/__init__.py +5 -0
- package/skills/session-profiler/scripts/session_profiler/analyses.py +246 -0
- package/skills/session-profiler/scripts/session_profiler/cli.py +77 -0
- package/skills/session-profiler/scripts/session_profiler/dataset.py +369 -0
- package/skills/session-profiler/scripts/session_profiler/discover.py +191 -0
- package/skills/session-profiler/scripts/session_profiler/toc.py +74 -0
- package/skills/session-profiler/scripts/session_profiler/trace.py +146 -0
- package/skills/session-profiler/scripts/sp +20 -0
- package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-child.jsonl +7 -0
- package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-root.jsonl +10 -0
- package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.jsonl +2 -0
- package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.meta.json +1 -0
- package/skills/session-profiler/scripts/tests/fixture/main.jsonl +7 -0
- package/skills/session-profiler/scripts/tests/test_fixture.py +58 -0
- package/skills/validate-market/README.md +27 -0
- package/skills/validate-market/SKILL.md +202 -0
- package/skills/write-blog/README.md +27 -0
- package/skills/write-blog/SKILL.md +142 -0
- package/skills/write-blog/check.sh +52 -0
- package/skills/write-blog/reference/angles.md +51 -0
- package/skills/write-blog/reference/craft.md +94 -0
- package/skills/write-blog/reference/seo.md +116 -0
- package/skills/write-blog/reference/voice.md +64 -0
- package/skills/write-blog/reference/wiring.md +113 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: write-blog
|
|
3
|
+
description: >-
|
|
4
|
+
Write and ship a blog post for your project that reads like a human wrote it and pulls
|
|
5
|
+
SEO traffic to your site. Use when a contributor wants to draft, edit, or publish a blog
|
|
6
|
+
post, add a post to the site, write about the project for search/traction, or make an
|
|
7
|
+
existing draft sound less like AI. Enforces the house voice (no em dashes), picks a
|
|
8
|
+
non-cannibalizing angle, wires the post into your site, and runs the humanizer pass
|
|
9
|
+
before shipping.
|
|
10
|
+
compatibility: claude-code
|
|
11
|
+
allowed-tools:
|
|
12
|
+
- Read
|
|
13
|
+
- Write
|
|
14
|
+
- Edit
|
|
15
|
+
- Grep
|
|
16
|
+
- Glob
|
|
17
|
+
- Bash
|
|
18
|
+
- AskUserQuestion
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Write a blog post
|
|
22
|
+
|
|
23
|
+
You are helping a contributor write a blog post for the project's website. The bar: it
|
|
24
|
+
reads like a person wrote it, it ranks for a search cluster no other post already owns,
|
|
25
|
+
and it ships wired correctly into the site with the build green.
|
|
26
|
+
|
|
27
|
+
This skill exists so every contributor writes in the same voice, picks non-overlapping
|
|
28
|
+
topics, and passes the same anti-AI-slop gate, whether or not they already know the house
|
|
29
|
+
rules.
|
|
30
|
+
|
|
31
|
+
## The one rule that gets a post rejected
|
|
32
|
+
|
|
33
|
+
**No em dashes (—) or en dashes (–). Ever.** The house voice bans them. Use a period, a
|
|
34
|
+
comma, or "so"/"because"/parentheses instead. A single dash in a draft is a hard fail.
|
|
35
|
+
There is a scanner: run `bash check.sh <file>` (in this skill's folder) on any draft before
|
|
36
|
+
you call it done.
|
|
37
|
+
|
|
38
|
+
## Workflow
|
|
39
|
+
|
|
40
|
+
Do these in order. Don't skip the angle check or the humanizer pass.
|
|
41
|
+
|
|
42
|
+
### 1. Read the ground truth first
|
|
43
|
+
|
|
44
|
+
Before writing a word, read what already exists so you match voice and don't cannibalize
|
|
45
|
+
keywords:
|
|
46
|
+
|
|
47
|
+
- **Your site's post registry / index.** Whatever lists every published post (a registry
|
|
48
|
+
file, a content collection, a CMS list, or the frontmatter across your blog's source
|
|
49
|
+
directory). This is the **live record of every published post and the angle it owns.**
|
|
50
|
+
Read every slug, title, description, and tag set.
|
|
51
|
+
- One or two full published posts (the prose sources) to absorb the voice.
|
|
52
|
+
- `reference/angles.md` (in this skill folder) for how to pick an angle that doesn't
|
|
53
|
+
collide, plus the topics still untapped.
|
|
54
|
+
- `reference/voice.md` for the house voice and the anti-AI checklist, self-contained.
|
|
55
|
+
- `reference/craft.md` for the writing craft: leads that win the click, spine structure,
|
|
56
|
+
and which creative-writing skill to reach for at each stage.
|
|
57
|
+
- `reference/seo.md` for on-page keyword placement, internal linking, verifying the
|
|
58
|
+
machine-readable SEO, and the post-ship distribution loop that earns the first backlinks.
|
|
59
|
+
|
|
60
|
+
### 2. Pick and pitch the angle
|
|
61
|
+
|
|
62
|
+
Every post must **own a distinct search cluster.** Two posts fighting for the same
|
|
63
|
+
keywords cannibalize each other. From your post index and `reference/angles.md`, pick an
|
|
64
|
+
angle no shipped post already owns, then pitch it back to the contributor in one line
|
|
65
|
+
before drafting: the working title, the one-sentence thesis, and the 3-5 keyword phrases it
|
|
66
|
+
targets. Confirm before you write the body. If they gave you a topic that collides with an
|
|
67
|
+
existing post, say so and propose the adjacent-but-distinct angle instead.
|
|
68
|
+
|
|
69
|
+
### 3. Outline
|
|
70
|
+
|
|
71
|
+
A good post has a spine, not a listicle. Read `reference/craft.md` before you outline; the
|
|
72
|
+
lead and the H2-spine are 80% of whether the post gets finished and ranked. Structure:
|
|
73
|
+
|
|
74
|
+
- **A lead (description + opening) that names a concrete, specific problem** the reader has.
|
|
75
|
+
Not "AI agents are transforming collaboration." Something like "Two agents can talk about
|
|
76
|
+
a change all day. Handing over the change itself, byte for byte, is a different problem."
|
|
77
|
+
- 4-7 sections, each with a claim and **real code, real commands, or a real number from
|
|
78
|
+
your project** backing it. Read the actual source and docs of your project and quote it
|
|
79
|
+
accurately. Made-up APIs are worse than no code.
|
|
80
|
+
- A "what this is NOT" or honest-limitations beat. The voice is a little contrarian and
|
|
81
|
+
admits what's deferred. That honesty is what makes it not read like marketing.
|
|
82
|
+
- A close that lands the thesis without a generic "in conclusion, the future is bright"
|
|
83
|
+
wrap-up. End on a concrete thing the reader can do or check.
|
|
84
|
+
|
|
85
|
+
### 4. Draft
|
|
86
|
+
|
|
87
|
+
Write the prose as plain markdown first, in your blog's source directory (the source of
|
|
88
|
+
truth). Follow `reference/voice.md` and `reference/craft.md` as you write, so there's less
|
|
89
|
+
to fix later. Keep it honest, concrete, and grounded in real project code. Vary sentence
|
|
90
|
+
length. Have an opinion. If `/direct-response-copy` is available in your environment, run it
|
|
91
|
+
on the title, description, and closing CTA (only those three surfaces, not the body).
|
|
92
|
+
|
|
93
|
+
### 5. Humanize (mandatory)
|
|
94
|
+
|
|
95
|
+
Run a humanizer pass on the draft: if `/humanizer` is available in your environment, invoke
|
|
96
|
+
it on the draft. If it isn't available, apply the checklist in `reference/voice.md`
|
|
97
|
+
yourself. Strip: significance inflation, promotional adjectives, the rule of three, "-ing"
|
|
98
|
+
tail analyses, negative parallelisms ("it's not X, it's Y"), synonym cycling, hedging, and
|
|
99
|
+
every dash. For headline/description/CTA polish you may also pull in
|
|
100
|
+
`/direct-response-copy` if it's available.
|
|
101
|
+
|
|
102
|
+
Then run `bash check.sh <draft-file>` and fix anything it flags.
|
|
103
|
+
|
|
104
|
+
### 6. Wire it into the site
|
|
105
|
+
|
|
106
|
+
Follow `reference/wiring.md`. In short: register the post in whatever index/registry your
|
|
107
|
+
blog uses, add the body in your blog's format, make sure the SEO surfaces (sitemap, RSS,
|
|
108
|
+
OG/Twitter cards, JSON-LD) include the new post, add the cover image, and build. For keyword
|
|
109
|
+
placement (title/description/first-H2/tags), internal-link count, and anchor-text rules,
|
|
110
|
+
follow `reference/seo.md`. Add a reciprocal inbound link from the most related existing post.
|
|
111
|
+
|
|
112
|
+
### 7. Verify before done
|
|
113
|
+
|
|
114
|
+
Your site's build command must be green. Then smoke-test the post: confirm the post page,
|
|
115
|
+
the cover image, the blog index, the sitemap, and the RSS feed all load and include the new
|
|
116
|
+
post. View source on the post and confirm the meta description, OG/Twitter tags, and
|
|
117
|
+
`BlogPosting` JSON-LD actually emitted with the right values (`reference/seo.md` lists what
|
|
118
|
+
to check). Re-run `bash check.sh` on the final markdown. Only then is the post itself done.
|
|
119
|
+
|
|
120
|
+
### 8. Distribute (this is what earns the traction)
|
|
121
|
+
|
|
122
|
+
A correct post with no inbound links does not rank. After it ships, seed the first signal:
|
|
123
|
+
if `/x-tweet` is available in your environment, run it on the post's core insight for a
|
|
124
|
+
thread that teaches the idea and links the post; cross-link the post from the relevant docs;
|
|
125
|
+
and answer the real question it solves where people are already asking it. See the
|
|
126
|
+
distribution loop in `reference/seo.md`. Always link the canonical production URL
|
|
127
|
+
(`<your-site-url>/blog/<slug>`), never a staging or preview host.
|
|
128
|
+
|
|
129
|
+
## Guardrails
|
|
130
|
+
|
|
131
|
+
- Never invent project APIs, flags, or numbers. Read the source and quote it.
|
|
132
|
+
- Never weaken the house voice to sound "professional." Concrete and a little contrarian
|
|
133
|
+
beats polished and generic every time.
|
|
134
|
+
- Don't ship a post whose angle overlaps a published one. Adjust the angle instead.
|
|
135
|
+
- Covers can be SVG or a raster image. Match your site's brand palette. If you can't make a
|
|
136
|
+
good cover, reuse an existing one rather than shipping something ugly.
|
|
137
|
+
|
|
138
|
+
## Note on this skill's own files
|
|
139
|
+
|
|
140
|
+
The scanner will flag `SKILL.md` and the `reference/` files because they name the banned
|
|
141
|
+
characters `(—)` `(–)` and use `→` as teaching notation. That's expected. The scanner is
|
|
142
|
+
for blog drafts and rendered post bodies, not for this skill's documentation.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# check.sh — pre-ship scan for a blog draft.
|
|
3
|
+
# Flags the house-style hard fails (em/en dashes, curly quotes, emoji) and the most
|
|
4
|
+
# common AI-slop phrases so they get fixed before the post ships.
|
|
5
|
+
#
|
|
6
|
+
# Usage: bash check.sh <path/to/post> (a markdown source or a rendered post body)
|
|
7
|
+
# Exit: 0 = clean, 1 = hard issues found, 2 = bad usage.
|
|
8
|
+
#
|
|
9
|
+
# Unicode checks run through perl (portable across macOS BSD grep + Linux GNU grep,
|
|
10
|
+
# which disagree on -P). Soft-phrase check uses portable grep -E.
|
|
11
|
+
|
|
12
|
+
set -u
|
|
13
|
+
|
|
14
|
+
file="${1:-}"
|
|
15
|
+
if [ -z "$file" ] || [ ! -f "$file" ]; then
|
|
16
|
+
echo "usage: bash check.sh <file>" >&2
|
|
17
|
+
exit 2
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
fails=0
|
|
21
|
+
|
|
22
|
+
# perl_scan REGEX LABEL — print "line:text" for each matching line, count as a hard fail.
|
|
23
|
+
perl_scan() {
|
|
24
|
+
local re="$1" label="$2" hits
|
|
25
|
+
hits="$(perl -CSD -ne 'print " $.: $_" if /'"$re"'/' "$file")"
|
|
26
|
+
if [ -n "$hits" ]; then
|
|
27
|
+
echo "✗ $label:"
|
|
28
|
+
printf '%s\n' "$hits"
|
|
29
|
+
fails=$((fails + 1))
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# --- Hard fails: characters the house style bans -----------------------------
|
|
34
|
+
perl_scan '[\x{2013}\x{2014}]' "em/en dash (— or –) — replace with a period, comma, or parentheses"
|
|
35
|
+
perl_scan '[\x{2018}\x{2019}\x{201C}\x{201D}]' "curly quote (‘ ’ “ ”) — use straight quotes"
|
|
36
|
+
perl_scan '[\x{1F000}-\x{1FAFF}\x{2600}-\x{27BF}\x{2190}-\x{21FF}\x{2B00}-\x{2BFF}]' "emoji / pictograph in prose"
|
|
37
|
+
|
|
38
|
+
# --- Soft flags: common AI tells. Review each; not every hit is wrong. --------
|
|
39
|
+
tells='testament to|pivotal|groundbreaking|seamless(ly)?|ever-evolving|evolving landscape|cutting-edge|game-chang|revolutioniz|underscor|it is (important|worth noting) to note|in conclusion|in order to|due to the fact|at this point in time|delve|leverage|robust and|it.s not just|isn.t just|serves as a|stands as a|plays a (vital|key|crucial) role|the possibilities are endless'
|
|
40
|
+
soft="$(grep -nEi "$tells" "$file" 2>/dev/null)"
|
|
41
|
+
if [ -n "$soft" ]; then
|
|
42
|
+
echo "⚠ possible AI-slop phrasing (review, don't blindly delete):"
|
|
43
|
+
printf '%s\n' "$soft" | sed 's/^/ /'
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
echo
|
|
47
|
+
if [ "$fails" -gt 0 ]; then
|
|
48
|
+
echo "FAIL: $fails hard-style issue group(s). Fix before shipping."
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
echo "OK: no hard-style issues. Still eyeball the ⚠ soft flags above."
|
|
52
|
+
exit 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Picking an angle that doesn't cannibalize
|
|
2
|
+
|
|
3
|
+
The blog's job is SEO traction to your project and its site. That only works if each post
|
|
4
|
+
owns a **distinct search cluster.** Two posts chasing the same keywords split their own
|
|
5
|
+
ranking. So the first rule of a new post is: pick an angle no shipped post already owns.
|
|
6
|
+
|
|
7
|
+
## How to check what's taken
|
|
8
|
+
|
|
9
|
+
Your post registry / index is the live record. Read every title, description, and tag set
|
|
10
|
+
before pitching. Each shipped post should own one spine, one topic cluster. Write down, for
|
|
11
|
+
each existing post, the one search cluster it owns, then make sure your new angle sits in a
|
|
12
|
+
gap between them, not on top of one.
|
|
13
|
+
|
|
14
|
+
For example, on a developer-tool blog the shipped posts might each own a distinct spine: one
|
|
15
|
+
on how the core mechanism works, one on a specific integration, a numbered "bugs that hid
|
|
16
|
+
until production" war-stories post, a field-guide survey of the landscape, and a "why not
|
|
17
|
+
just use X" honest-comparison post. A new post has to find the next gap, not re-litigate one
|
|
18
|
+
of those.
|
|
19
|
+
|
|
20
|
+
Always re-read the registry at write time; any list you wrote down earlier is a snapshot and
|
|
21
|
+
the registry is the truth.
|
|
22
|
+
|
|
23
|
+
## Finding an untapped angle
|
|
24
|
+
|
|
25
|
+
Good starting points for a gap the existing posts don't cover:
|
|
26
|
+
|
|
27
|
+
- **A deep dive on a subsystem no post has centered yet** (security/trust model, storage and
|
|
28
|
+
ops, a specific protocol or format). Check that a related post hasn't already spent the key
|
|
29
|
+
anecdotes; if it has, the new post needs a different spine.
|
|
30
|
+
- **A "how we actually build this" process post** if the engineering workflow itself is
|
|
31
|
+
interesting and undocumented.
|
|
32
|
+
- **An interoperability or integration story** that a broad post only mentioned in passing.
|
|
33
|
+
- **An honest comparison** ("why not just use X") that no existing post has made head-on.
|
|
34
|
+
|
|
35
|
+
Mine your own docs and issues for these. The best untapped angles are usually questions your
|
|
36
|
+
users already ask that no post answers directly yet.
|
|
37
|
+
|
|
38
|
+
## When to write a checklist / listicle instead
|
|
39
|
+
|
|
40
|
+
Usually don't. The house format is a spine with a thesis, not a listicle. A "top N tools"
|
|
41
|
+
post ranks briefly and ages badly, and it doesn't fit the voice. If a contributor wants one,
|
|
42
|
+
steer them to a spine post on the same topic instead.
|
|
43
|
+
|
|
44
|
+
## Keyword discipline
|
|
45
|
+
|
|
46
|
+
- One primary phrase per post; put it in the `title`, the description (meta description),
|
|
47
|
+
the first H2, and the tags.
|
|
48
|
+
- Pick phrases a real developer in your audience would type into a search box (an exact error
|
|
49
|
+
message, the plain name of a concept, a comparison like "X vs Y"), not brand-y phrases
|
|
50
|
+
nobody searches.
|
|
51
|
+
- Internal-link to 1-2 sibling posts so ranking flows between them instead of competing.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Writing craft: make a technical post that people finish
|
|
2
|
+
|
|
3
|
+
The house voice (`voice.md`) tells you what to strip. This file tells you what to build. A
|
|
4
|
+
post that ranks but reads like a spec sheet gets a 90% bounce and never earns a backlink.
|
|
5
|
+
Craft is what turns a correct post into one people finish and share.
|
|
6
|
+
|
|
7
|
+
Study the shipped posts before you write. They are the ground truth for the craft, not this
|
|
8
|
+
file. Read two full ones from your blog's source and notice what they actually do.
|
|
9
|
+
|
|
10
|
+
## The lead is 80% of the job
|
|
11
|
+
|
|
12
|
+
Most readers decide in the first two sentences. The lead is also your meta description and
|
|
13
|
+
your search snippet, so it does double duty. Every shipped lead names a concrete, specific
|
|
14
|
+
problem the reader already feels, with zero throat-clearing.
|
|
15
|
+
|
|
16
|
+
- War-story open: `"A WebSocket that passed every localhost test and died the moment it
|
|
17
|
+
spoke TLS."` A single failing scene, not a topic sentence.
|
|
18
|
+
- Tension open: `"Two agents can talk about a change all day. Handing over the change
|
|
19
|
+
itself, byte for byte, is a different problem."` State the easy thing, then the hard thing.
|
|
20
|
+
- Contrarian open: `"AI agent memory in 2026 is mostly single-player."` A claim someone
|
|
21
|
+
could disagree with.
|
|
22
|
+
|
|
23
|
+
Bad leads announce the topic ("In this post we'll explore agent memory"). Good leads drop
|
|
24
|
+
the reader into a problem mid-scene. If your lead would survive being pasted into a search
|
|
25
|
+
result as the one line that wins the click, it's ready. This is where `/direct-response-copy`
|
|
26
|
+
earns its keep: run it on the title and lead specifically.
|
|
27
|
+
|
|
28
|
+
## Structure is a spine, not a pile
|
|
29
|
+
|
|
30
|
+
A ranking technical post is an argument that moves. Each section advances one claim and
|
|
31
|
+
hands off to the next. The test: read only your H2s in order. Do they tell a story on their
|
|
32
|
+
own? If they read like a glossary ("Overview", "Architecture", "Details", "Conclusion"),
|
|
33
|
+
the spine is missing. Rewrite the H2s to be claims: "Identity is not authorization",
|
|
34
|
+
"One SQLite file, two search engines".
|
|
35
|
+
|
|
36
|
+
Proven shapes:
|
|
37
|
+
|
|
38
|
+
- **Problem to mechanism.** Name the pain, show the naive fix, show why it breaks, show the
|
|
39
|
+
real mechanism with code.
|
|
40
|
+
- **Numbered war stories.** N self-contained bug narratives, each with a one-line lesson,
|
|
41
|
+
bound by a theme. Scannable and linkable.
|
|
42
|
+
- **Field guide.** Survey the landscape honestly, then place your thing inside it. Earns
|
|
43
|
+
authority because it credits the alternatives.
|
|
44
|
+
|
|
45
|
+
## Show the machine
|
|
46
|
+
|
|
47
|
+
The single biggest credibility lever in a technical post is real code, real commands, real
|
|
48
|
+
numbers from your project, quoted accurately. Read the actual source and docs of your
|
|
49
|
+
project and paste the actual thing. A reader who spots one invented API stops trusting the
|
|
50
|
+
whole post. One accurate 8-line snippet beats three paragraphs describing it.
|
|
51
|
+
|
|
52
|
+
Give every code block a job. Don't paste code and move on; the sentence before it says what
|
|
53
|
+
to watch for, the sentence after says what just happened. Numbers are strongest of all:
|
|
54
|
+
"buffers the whole blob in RAM" is fine, "buffers the whole blob in RAM, so a 200MB bundle
|
|
55
|
+
is 200MB resident" lands.
|
|
56
|
+
|
|
57
|
+
## Rhythm and voice
|
|
58
|
+
|
|
59
|
+
- Vary sentence length on purpose. A four-word sentence after a long one is a drum hit. If
|
|
60
|
+
every sentence is the same length the reader's eye glazes; the humanizer will not catch
|
|
61
|
+
monotony, only you will. Read it out loud.
|
|
62
|
+
- Have exactly one opinion per post and defend it. Contrarian-but-earned is the house
|
|
63
|
+
register: "most guides get this wrong" only works if you then show why, with code.
|
|
64
|
+
- Admit what's deferred. A limitations beat ("what this is NOT") is the reason the post
|
|
65
|
+
reads like an engineer wrote it and not marketing. Candor converts.
|
|
66
|
+
- First person when it fits. "I shipped this and it warmed up my laptop" beats "the system
|
|
67
|
+
experienced elevated CPU utilization."
|
|
68
|
+
|
|
69
|
+
## Close on a next action, not a summary
|
|
70
|
+
|
|
71
|
+
Never end with "in conclusion, as agents evolve, the possibilities are endless." End on one
|
|
72
|
+
concrete thing the reader can do or check right now: a command to run, a file to read, a
|
|
73
|
+
repo to clone, a claim to go verify. The close is where you convert a reader into a repo
|
|
74
|
+
star or a hub signup, so make it a door, not a wall.
|
|
75
|
+
|
|
76
|
+
## Which creative skill to reach for, when
|
|
77
|
+
|
|
78
|
+
These are optional helper skills; use them if available in your environment.
|
|
79
|
+
|
|
80
|
+
- `/humanizer`: mandatory pass on the finished draft. Strips AI tells. This is the gate
|
|
81
|
+
in the main workflow. If it isn't available, apply the checklist in `voice.md` by hand.
|
|
82
|
+
- `/direct-response-copy`: the title, the description/lead, and the closing CTA. Use its
|
|
83
|
+
framework vocabulary (a promise, a specific mechanism, a reason to act now) on those three
|
|
84
|
+
surfaces. Do not let it inflate the body into ad copy; the body stays plain and technical.
|
|
85
|
+
- `/x-tweet`: after the post ships, for the distribution thread that seeds traction. See
|
|
86
|
+
`seo.md`. A post nobody links to does not rank.
|
|
87
|
+
|
|
88
|
+
## The finish test
|
|
89
|
+
|
|
90
|
+
Read the whole thing out loud once. Three failure modes to catch: it sounds like a
|
|
91
|
+
Wikipedia intro (clean but no pulse: add an opinion or a war story), it sounds like a sales
|
|
92
|
+
page (promotional: cut adjectives, add code), or you got bored reading it (the spine
|
|
93
|
+
sagged: find the section that repeats the one before it and cut it). Only ship a post you
|
|
94
|
+
would actually finish reading.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Technical SEO + distribution: get the post found and linked
|
|
2
|
+
|
|
3
|
+
`angles.md` covers not cannibalizing your own posts. This file covers the on-page mechanics
|
|
4
|
+
that make a single post rank, and the distribution loop that gets it the first backlinks so
|
|
5
|
+
it can rank at all. Ranking is on-page correctness times off-page signal; skip either half
|
|
6
|
+
and the post sits on page 5.
|
|
7
|
+
|
|
8
|
+
## On-page: one primary phrase, placed deliberately
|
|
9
|
+
|
|
10
|
+
Pick one primary keyword phrase per post, the exact string a developer in your audience
|
|
11
|
+
would type into a search box. Favor:
|
|
12
|
+
|
|
13
|
+
- **Real error strings** (an exact message a user would paste): low volume, near-zero
|
|
14
|
+
competition, high intent. These are the cheapest wins.
|
|
15
|
+
- **Concept phrases** (the plain name of the thing your post explains).
|
|
16
|
+
- **Comparison phrases** ("X vs Y", "alternative to Z").
|
|
17
|
+
|
|
18
|
+
Avoid brand-y phrases nobody searches ("the such-and-such paradigm"). You cannot rank for
|
|
19
|
+
demand that does not exist.
|
|
20
|
+
|
|
21
|
+
Place the primary phrase in all four of these, or the post is under-optimized:
|
|
22
|
+
|
|
23
|
+
1. The post `title` (the `<title>` and OG title derive from it).
|
|
24
|
+
2. The description / standfirst (the meta description and search snippet). Front-load the
|
|
25
|
+
phrase; make it a promise.
|
|
26
|
+
3. The first H2 in the body.
|
|
27
|
+
4. The tags/keywords (these become the JSON-LD `keywords`).
|
|
28
|
+
|
|
29
|
+
Use secondary phrases naturally in later H2s. Do not stuff; modern ranking reads for
|
|
30
|
+
coverage of a topic, not keyword density. One clear primary plus honest depth beats
|
|
31
|
+
repetition.
|
|
32
|
+
|
|
33
|
+
## On-page: the structural signals
|
|
34
|
+
|
|
35
|
+
- **Sentence-case headings that are claims**, not labels. They double as the spine (see
|
|
36
|
+
`craft.md`) and as the outline Google reads.
|
|
37
|
+
- **Deep-linkable H2s.** Every H2 needs an `id` so sections can be shared and can
|
|
38
|
+
win their own snippet.
|
|
39
|
+
- **Internal links: 2 to 3 per post**, to sibling posts by `/blog/<slug>`, using descriptive
|
|
40
|
+
anchor text ("how agents hand off code", not "click here"). This is the single most
|
|
41
|
+
under-used lever here. It flows ranking between your posts and keeps readers on-site.
|
|
42
|
+
Reciprocate: when you ship a post, add one inbound link to it from the most related
|
|
43
|
+
existing post.
|
|
44
|
+
- **One outbound link to an authority** (the MCP spec, a paper, a repo) signals the post is
|
|
45
|
+
situated in real work, not a content mill.
|
|
46
|
+
- **Reading time and date** are already wired; keep them honest.
|
|
47
|
+
|
|
48
|
+
## Verify the machine-readable SEO actually emitted
|
|
49
|
+
|
|
50
|
+
On many blog systems the sitemap, RSS, per-post OpenGraph + Twitter cards, and `BlogPosting`
|
|
51
|
+
JSON-LD auto-derive from the post's registry/frontmatter entry, so wiring the entry is most
|
|
52
|
+
of the job. But verify it, do not assume. After your site's build command, serve the site
|
|
53
|
+
locally and check:
|
|
54
|
+
|
|
55
|
+
- The sitemap returns 200 and contains the new `<loc>` for the slug.
|
|
56
|
+
- The RSS feed returns 200 and lists the new post.
|
|
57
|
+
- View source on `/blog/<slug>` and confirm: `<meta name="description">` matches the
|
|
58
|
+
description, `og:title` / `og:image` / `twitter:card` are present, and the
|
|
59
|
+
`application/ld+json` `BlogPosting` block has the right headline, datePublished, author,
|
|
60
|
+
and keywords.
|
|
61
|
+
- The cover image returns 200. A broken OG image kills the click-through on every social
|
|
62
|
+
share.
|
|
63
|
+
|
|
64
|
+
If any of these is wrong, the SEO surface is broken even though the build was green. This
|
|
65
|
+
step is not optional; it is the difference between a post that gets indexed well and one
|
|
66
|
+
that gets a bad snippet.
|
|
67
|
+
|
|
68
|
+
## Off-page: the distribution loop (this is what actually earns traction)
|
|
69
|
+
|
|
70
|
+
A technically perfect post with zero inbound links does not rank. Google needs a signal
|
|
71
|
+
that the page matters. You seed that signal yourself:
|
|
72
|
+
|
|
73
|
+
1. **The X thread.** If `/x-tweet` is available in your environment, run it on the post's
|
|
74
|
+
core insight. The thread is not "new blog post link", it teaches the one sharp idea and
|
|
75
|
+
links the post as the deep-dive. One genuinely useful thread out-performs ten "check out
|
|
76
|
+
my article" posts. Link the exact post URL (`<your-site-url>/blog/<slug>`), not the
|
|
77
|
+
homepage.
|
|
78
|
+
2. **The comment-where-the-question-lives play.** The post usually answers a real question
|
|
79
|
+
people ask (on Hacker News, the relevant subreddits, GitHub discussions, Lobsters). When
|
|
80
|
+
that question comes up, answer it for real and link the post as the fuller answer. Do not
|
|
81
|
+
drive-by drop links; that gets flagged and does the brand harm.
|
|
82
|
+
3. **Cross-link from the repo.** Reference the post from the relevant docs and, when apt,
|
|
83
|
+
the README. Repo-to-post links are backlinks Google trusts and they route repo traffic to
|
|
84
|
+
the site.
|
|
85
|
+
4. **Update, do not abandon.** When a post's facts change (a deferred feature ships, a
|
|
86
|
+
number moves), edit the post and bump nothing else. Fresh, accurate posts hold rank;
|
|
87
|
+
stale ones decay. Keeping the plain-markdown source makes this easy.
|
|
88
|
+
|
|
89
|
+
## Going deeper on SEO fundamentals
|
|
90
|
+
|
|
91
|
+
The rules above are the blog-specific subset. For the full SEO surface (structured-data
|
|
92
|
+
schema choices, exhaustive OG/Twitter tag coverage, canonical and hreflang patterns, and
|
|
93
|
+
Core Web Vitals), lean on the `astro-seo` skill, invocable as `/astro-seo` and published as
|
|
94
|
+
`astro-seo-expert` at https://mcpmarket.com/tools/skills/astro-seo-expert. It is written for
|
|
95
|
+
Astro, so ignore its Astro-specific integration code (`Astro.site`, `@astrojs/sitemap`,
|
|
96
|
+
`@astrojs/rss`). What transfers cleanly and is worth pulling in:
|
|
97
|
+
|
|
98
|
+
- **Structured-data recipes.** Which JSON-LD `@type` to emit and the required fields, beyond
|
|
99
|
+
the `BlogPosting` most blog systems emit (for example `BreadcrumbList`, `Person` author,
|
|
100
|
+
`Organization` publisher). Verify the values it recommends against what your build actually
|
|
101
|
+
emits (see the verify step above).
|
|
102
|
+
- **Meta-tag completeness.** The full Open Graph and Twitter Card checklist to confirm every
|
|
103
|
+
card renders when the post is shared.
|
|
104
|
+
- **Canonical and hreflang.** The canonical-URL discipline (point at the production host, one
|
|
105
|
+
canonical per page) maps onto whatever metadata layer your site uses.
|
|
106
|
+
- **Core Web Vitals.** The LCP/CLS/INP guidance is framework-agnostic. A fast post page keeps
|
|
107
|
+
the bounce down and helps rank.
|
|
108
|
+
|
|
109
|
+
Treat it as the reference textbook and `seo.md` as the house checklist: when they disagree on
|
|
110
|
+
a blog-specific call (internal-link count, keyword placement), `seo.md` wins.
|
|
111
|
+
|
|
112
|
+
## The public URL
|
|
113
|
+
|
|
114
|
+
Outward links point at your canonical production domain, never a staging or preview host.
|
|
115
|
+
Use the production domain in the thread, in cross-links, and anywhere a human will see it, so
|
|
116
|
+
link equity accrues to the canonical host.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# House voice + anti-AI checklist
|
|
2
|
+
|
|
3
|
+
This is self-contained: you can enforce it even if the `/humanizer` command isn't loaded.
|
|
4
|
+
But if `/humanizer` is available, run it too. This file is the house-specific layer on top
|
|
5
|
+
of it.
|
|
6
|
+
|
|
7
|
+
## What a good post sounds like
|
|
8
|
+
|
|
9
|
+
- **Human and a little contrarian.** It has an opinion and defends it. It's willing to say
|
|
10
|
+
"most guides get this wrong" and then show why.
|
|
11
|
+
- **Honest about what's deferred.** It names the limitations and the things not built yet.
|
|
12
|
+
That candor is the reason it doesn't read like a press release.
|
|
13
|
+
- **Concrete, always.** Every claim is backed by real code from the project, a real command,
|
|
14
|
+
or a real number. Read the source before you describe it.
|
|
15
|
+
- **Varied rhythm.** Short sentences next to long ones. Not every paragraph the same shape.
|
|
16
|
+
- **First person when it fits.** "We shipped this and it broke in production" beats "the
|
|
17
|
+
system experienced an issue."
|
|
18
|
+
|
|
19
|
+
## The hard rules (a post fails on any of these)
|
|
20
|
+
|
|
21
|
+
1. **No em dashes (—) or en dashes (–).** Use a period, comma, "so", "because", or
|
|
22
|
+
parentheses instead. Run `check.sh` to catch strays.
|
|
23
|
+
2. **No curly quotes.** Straight quotes only.
|
|
24
|
+
3. **No emojis in body prose.**
|
|
25
|
+
4. **Sentence case in headings, not Title Case.** "How agents hand off code", not "How
|
|
26
|
+
Agents Hand Off Code".
|
|
27
|
+
|
|
28
|
+
## AI tells to strip (the checklist)
|
|
29
|
+
|
|
30
|
+
Read the draft and remove each of these. This is the condensed version of the humanizer
|
|
31
|
+
patterns, tuned for this blog.
|
|
32
|
+
|
|
33
|
+
- **Significance inflation.** Cut "testament to", "pivotal", "groundbreaking", "in an
|
|
34
|
+
ever-evolving landscape", "plays a vital role", "underscores the importance". Say the
|
|
35
|
+
concrete thing instead.
|
|
36
|
+
- **Promotional adjectives.** Cut "seamless", "powerful", "robust", "cutting-edge",
|
|
37
|
+
"revolutionary", "game-changing". Show the behavior; let the reader conclude it's good.
|
|
38
|
+
- **Rule of three.** AI loves "fast, simple, and reliable" triples. Break the pattern. One
|
|
39
|
+
sharp adjective beats three padded ones.
|
|
40
|
+
- **The -ing tail analyses.** Cut sentences ending in "...highlighting the need for...",
|
|
41
|
+
"...reflecting a broader shift...", "...underscoring how...". They add nothing.
|
|
42
|
+
- **Negative parallelism.** Kill "it's not just X, it's Y" and "this isn't about X; it's
|
|
43
|
+
about Y". Overused to death by LLMs.
|
|
44
|
+
- **Synonym cycling / elegant variation.** Don't call the same thing a "solution", then a
|
|
45
|
+
"platform", then an "offering", then a "framework" to avoid repetition. Repeat the plain
|
|
46
|
+
noun.
|
|
47
|
+
- **Copula avoidance.** Prefer "is/are" over "serves as", "functions as", "stands as",
|
|
48
|
+
"acts as a".
|
|
49
|
+
- **Vague attributions.** No "industry experts say", "many believe", "it is widely
|
|
50
|
+
regarded". Name the source or cut it.
|
|
51
|
+
- **Hedging and filler.** "In order to" becomes "to". "Due to the fact that" becomes
|
|
52
|
+
"because". "At this point in time" becomes "now". "It is important to note that": just
|
|
53
|
+
say it. "Has the ability to" becomes "can".
|
|
54
|
+
- **Generic positive conclusion.** No "in conclusion, as agents continue to evolve, the
|
|
55
|
+
possibilities are endless." End on something concrete.
|
|
56
|
+
- **Sycophancy / chat artifacts.** No "Great question!", "I hope this helps", "Let me know
|
|
57
|
+
if...". This is an article, not a chat reply.
|
|
58
|
+
- **Boldface overuse.** Bold a term once when introduced, not every noun.
|
|
59
|
+
|
|
60
|
+
## The soul test
|
|
61
|
+
|
|
62
|
+
After cleaning, read it out loud. If it sounds like a Wikipedia intro or a LinkedIn post,
|
|
63
|
+
it's clean but soulless. Add back a real opinion, a specific war story, a dry aside. A post
|
|
64
|
+
with a pulse converts; a tidy one bounces.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Publish and wire the post into your site
|
|
2
|
+
|
|
3
|
+
Blog systems differ (static site generators like Astro, Hugo, Eleventy, Next.js, or Jekyll;
|
|
4
|
+
a CMS; or a plain markdown/frontmatter blog), but the wiring steps are the same everywhere.
|
|
5
|
+
Do them in this order.
|
|
6
|
+
|
|
7
|
+
## 1. Register the post in your site's index
|
|
8
|
+
|
|
9
|
+
Add the post to whatever your blog uses to list published posts: a registry file, a content
|
|
10
|
+
collection, a CMS entry, or the frontmatter that a content directory is scanned for. On many
|
|
11
|
+
systems all SEO surfaces (sitemap, RSS, per-post OpenGraph + Twitter cards, and the
|
|
12
|
+
`BlogPosting` JSON-LD) auto-derive from this metadata, so you do not wire them separately.
|
|
13
|
+
Whatever the mechanism, the entry needs at least:
|
|
14
|
+
|
|
15
|
+
- `slug` — kebab-case, matches the body file and the source markdown.
|
|
16
|
+
- `title` — sentence case, no dashes.
|
|
17
|
+
- `description` / standfirst — one to two sentences. This is your meta description, so
|
|
18
|
+
front-load the keyword phrase and make it read like a promise, not a summary.
|
|
19
|
+
- `date` — ISO, drives the `<time>` element and sort order (and a human label if your system
|
|
20
|
+
wants one separately).
|
|
21
|
+
- `readingTime` — honest.
|
|
22
|
+
- `author`.
|
|
23
|
+
- `tags` / keywords — these typically become the JSON-LD keywords.
|
|
24
|
+
- `cover` — path to the cover image.
|
|
25
|
+
|
|
26
|
+
## 2. Add the body in your blog's format
|
|
27
|
+
|
|
28
|
+
Write the post body in whatever format your blog renders: a markdown/MDX file, a template, a
|
|
29
|
+
component, or a CMS rich-text field. Whatever the format:
|
|
30
|
+
|
|
31
|
+
- Give H2s an `id` so they can be deep-linked.
|
|
32
|
+
- Use real links (not "click here"), and link to 1-2 related posts by `/blog/<slug>` for
|
|
33
|
+
internal SEO.
|
|
34
|
+
- Quote real code from your project accurately.
|
|
35
|
+
|
|
36
|
+
Copy the structure of an existing post rather than inventing a new layout.
|
|
37
|
+
|
|
38
|
+
## 3. Make sure the SEO surfaces include the new post
|
|
39
|
+
|
|
40
|
+
Confirm the sitemap, RSS feed, per-post OpenGraph + Twitter cards, and `BlogPosting` JSON-LD
|
|
41
|
+
all pick up the new post. On systems where these auto-derive from the index entry (step 1),
|
|
42
|
+
there's nothing extra to do but verify. On systems where they don't, add the post to each
|
|
43
|
+
surface by hand. The page should fail loudly (a 404 / not-found) if the post is registered
|
|
44
|
+
but its body is missing, or vice versa, so make sure both halves are present.
|
|
45
|
+
|
|
46
|
+
## 4. Drop the prose source
|
|
47
|
+
|
|
48
|
+
Keep the plain-markdown draft you wrote and humanized in your blog's source directory
|
|
49
|
+
permanently. It's the source of truth for the prose; whatever your site renders is the
|
|
50
|
+
rendered form. If your blog already authors directly in markdown, this and step 2 are the
|
|
51
|
+
same file.
|
|
52
|
+
|
|
53
|
+
## 5. Cover image
|
|
54
|
+
|
|
55
|
+
Add the cover image where your site serves post assets. SVG or a raster image is fine. Match
|
|
56
|
+
your site's brand palette. If you can't produce a good one, reuse an existing cover rather
|
|
57
|
+
than shipping something ugly. A broken OG image kills the click-through on every social
|
|
58
|
+
share.
|
|
59
|
+
|
|
60
|
+
## Verify
|
|
61
|
+
|
|
62
|
+
Your site's build command must be green. Then serve the site and smoke-test that these all
|
|
63
|
+
load and include the new post: the post page `/blog/<slug>`, the cover image, the blog index
|
|
64
|
+
(the new card shows), the sitemap, and the RSS feed. Re-run `bash check.sh` on the post's
|
|
65
|
+
markdown source.
|
|
66
|
+
|
|
67
|
+
## Example: Next.js
|
|
68
|
+
|
|
69
|
+
As one concrete illustration, a Next.js site might wire a post like this (adapt to your own
|
|
70
|
+
stack):
|
|
71
|
+
|
|
72
|
+
- Register metadata by adding an entry to the top of a `POSTS` array in `web/lib/blog.ts`
|
|
73
|
+
(newest first). All SEO surfaces auto-derive from it.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
{
|
|
77
|
+
slug: "your-slug",
|
|
78
|
+
title: "Sentence case, no dashes",
|
|
79
|
+
dek: "One-to-two sentence standfirst that front-loads the keyword phrase.",
|
|
80
|
+
date: "2026-07-DD",
|
|
81
|
+
dateLabel: "July D, 2026",
|
|
82
|
+
readingTime: "N min read",
|
|
83
|
+
author: "Your Name",
|
|
84
|
+
tags: ["Primary keyword", "Secondary"],
|
|
85
|
+
cover: "/blog/your-slug.svg",
|
|
86
|
+
},
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- Write the body as a React component in `web/components/blog/<slug>.tsx`, using shared prose
|
|
90
|
+
primitives (`ArticleH2`, `P`, `Lead`, `CodeBlock`, `A`, ...) from `components/blog/prose.tsx`
|
|
91
|
+
so every post renders identically.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { Lead, P, ArticleH2, A, InlineCode, CodeBlock } from "./prose";
|
|
95
|
+
|
|
96
|
+
export function YourPostName() {
|
|
97
|
+
return (
|
|
98
|
+
<>
|
|
99
|
+
<Lead>The opening that names a concrete, specific problem.</Lead>
|
|
100
|
+
<ArticleH2 id="the-problem">The problem, plainly</ArticleH2>
|
|
101
|
+
<P>...</P>
|
|
102
|
+
<CodeBlock language="rust">{`// real code, quoted accurately`}</CodeBlock>
|
|
103
|
+
</>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- Register the body in `web/app/blog/[slug]/page.tsx`: import the component and add
|
|
109
|
+
`"your-slug": <YourPostName />,` to the `BODIES` map. The page falls back to `notFound()`
|
|
110
|
+
if either the `POSTS` entry or the `BODIES` line is missing.
|
|
111
|
+
- Keep the prose source in `docs/blog/<slug>.md` and the cover in `web/public/blog/<slug>.svg`.
|
|
112
|
+
- Verify with `npm run build` (must be green), then `next start` and confirm 200s for
|
|
113
|
+
`/blog/<slug>`, the cover, `/blog`, `/sitemap.xml`, and `/rss.xml`.
|