@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.
Files changed (66) hide show
  1. package/.claude/agents/lead-builder.md +55 -0
  2. package/.claude/agents/lead-reviewer.md +39 -0
  3. package/README.md +276 -0
  4. package/assets/readme-hero.png +0 -0
  5. package/assets/skill-cards/async-learning-teacher.svg +7 -0
  6. package/assets/skill-cards/code-standards.svg +7 -0
  7. package/assets/skill-cards/lead-research.svg +7 -0
  8. package/assets/skill-cards/lead.svg +7 -0
  9. package/assets/skill-cards/orwell-writing.svg +7 -0
  10. package/assets/skill-cards/session-profiler.svg +7 -0
  11. package/assets/skill-cards/validate-market.svg +7 -0
  12. package/assets/skill-cards/write-blog.svg +7 -0
  13. package/bin/builder-essential-skills.js +134 -0
  14. package/install.ps1 +58 -0
  15. package/install.sh +63 -0
  16. package/package.json +24 -0
  17. package/skills/async-learning-teacher/README.md +50 -0
  18. package/skills/async-learning-teacher/SKILL.md +192 -0
  19. package/skills/async-learning-teacher/agents/openai.yaml +4 -0
  20. package/skills/code-standards/README.md +27 -0
  21. package/skills/code-standards/SKILL.md +51 -0
  22. package/skills/lead/README.md +29 -0
  23. package/skills/lead/SKILL.md +222 -0
  24. package/skills/lead/config.py +359 -0
  25. package/skills/lead/dispatch.md +342 -0
  26. package/skills/lead/loop.md +103 -0
  27. package/skills/lead/models.json +34 -0
  28. package/skills/lead/research.md +76 -0
  29. package/skills/lead/status.ps1 +114 -0
  30. package/skills/lead/status.sh +110 -0
  31. package/skills/lead/watchdog.ps1 +90 -0
  32. package/skills/lead/watchdog.sh +88 -0
  33. package/skills/lead-research/README.md +27 -0
  34. package/skills/lead-research/SKILL.md +157 -0
  35. package/skills/lead-research/tactics.md +150 -0
  36. package/skills/orwell-writing/README.md +27 -0
  37. package/skills/orwell-writing/SKILL.md +44 -0
  38. package/skills/orwell-writing/agents/openai.yaml +4 -0
  39. package/skills/session-profiler/README.md +25 -0
  40. package/skills/session-profiler/SKILL.md +103 -0
  41. package/skills/session-profiler/agents/openai.yaml +4 -0
  42. package/skills/session-profiler/scripts/requirements.txt +2 -0
  43. package/skills/session-profiler/scripts/session_profiler/__init__.py +5 -0
  44. package/skills/session-profiler/scripts/session_profiler/analyses.py +246 -0
  45. package/skills/session-profiler/scripts/session_profiler/cli.py +77 -0
  46. package/skills/session-profiler/scripts/session_profiler/dataset.py +369 -0
  47. package/skills/session-profiler/scripts/session_profiler/discover.py +191 -0
  48. package/skills/session-profiler/scripts/session_profiler/toc.py +74 -0
  49. package/skills/session-profiler/scripts/session_profiler/trace.py +146 -0
  50. package/skills/session-profiler/scripts/sp +20 -0
  51. package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-child.jsonl +7 -0
  52. package/skills/session-profiler/scripts/tests/codex_home/sessions/2026/01/01/rollout-root.jsonl +10 -0
  53. package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.jsonl +2 -0
  54. package/skills/session-profiler/scripts/tests/fixture/main/subagents/agent-abc.meta.json +1 -0
  55. package/skills/session-profiler/scripts/tests/fixture/main.jsonl +7 -0
  56. package/skills/session-profiler/scripts/tests/test_fixture.py +58 -0
  57. package/skills/validate-market/README.md +27 -0
  58. package/skills/validate-market/SKILL.md +202 -0
  59. package/skills/write-blog/README.md +27 -0
  60. package/skills/write-blog/SKILL.md +142 -0
  61. package/skills/write-blog/check.sh +52 -0
  62. package/skills/write-blog/reference/angles.md +51 -0
  63. package/skills/write-blog/reference/craft.md +94 -0
  64. package/skills/write-blog/reference/seo.md +116 -0
  65. package/skills/write-blog/reference/voice.md +64 -0
  66. 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`.